Skip to content

Commit bd18bc9

Browse files
committed
Auto merge of #70771 - RalfJung:ctfe-loop, r=oli-obk
Miri terminator handling: only do progress sanity check for 'Call' terminator This will still catch mistakes in bad intrinsic/foreign-item shims, which is the main source of errors here. Fixes #70723 r? @oli-obk
2 parents 733f104 + e92bde3 commit bd18bc9

File tree

8 files changed

+63
-31
lines changed

8 files changed

+63
-31
lines changed

src/librustc_mir/interpret/eval_context.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{self, TyAndLayout};
1717
use rustc_middle::ty::{
1818
self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable,
1919
};
20-
use rustc_span::source_map::DUMMY_SP;
20+
use rustc_span::{source_map::DUMMY_SP, Span};
2121
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
2222

2323
use super::{
@@ -256,7 +256,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
256256
/// or compute the layout.
257257
#[cfg_attr(not(debug_assertions), inline(always))]
258258
pub(super) fn from_known_layout<'tcx>(
259-
tcx: TyCtxt<'tcx>,
259+
tcx: TyCtxtAt<'tcx>,
260260
known_layout: Option<TyAndLayout<'tcx>>,
261261
compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
262262
) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -265,12 +265,14 @@ pub(super) fn from_known_layout<'tcx>(
265265
Some(known_layout) => {
266266
if cfg!(debug_assertions) {
267267
let check_layout = compute()?;
268-
assert!(
269-
mir_assign_valid_types(tcx, check_layout, known_layout),
270-
"expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
271-
known_layout.ty,
272-
check_layout.ty,
273-
);
268+
if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) {
269+
span_bug!(
270+
tcx.span,
271+
"expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
272+
known_layout.ty,
273+
check_layout.ty,
274+
);
275+
}
274276
}
275277
Ok(known_layout)
276278
}
@@ -294,6 +296,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
294296
}
295297
}
296298

299+
#[inline(always)]
300+
pub fn set_span(&mut self, span: Span) {
301+
self.tcx.span = span;
302+
self.memory.tcx.span = span;
303+
}
304+
297305
#[inline(always)]
298306
pub fn force_ptr(
299307
&self,
@@ -444,7 +452,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
444452
// have to support that case (mostly by skipping all caching).
445453
match frame.locals.get(local).and_then(|state| state.layout.get()) {
446454
None => {
447-
let layout = from_known_layout(self.tcx.tcx, layout, || {
455+
let layout = from_known_layout(self.tcx, layout, || {
448456
let local_ty = frame.body.local_decls[local].ty;
449457
let local_ty =
450458
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);

src/librustc_mir/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
529529
ty::ConstKind::Value(val_val) => val_val,
530530
};
531531
// Other cases need layout.
532-
let layout = from_known_layout(self.tcx.tcx, layout, || self.layout_of(val.ty))?;
532+
let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?;
533533
let op = match val_val {
534534
ConstValue::ByRef { alloc, offset } => {
535535
let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);

src/librustc_mir/interpret/place.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -867,12 +867,14 @@ where
867867
) -> InterpResult<'tcx> {
868868
// We do NOT compare the types for equality, because well-typed code can
869869
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
870-
assert!(
871-
mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout),
872-
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
873-
src.layout.ty,
874-
dest.layout.ty,
875-
);
870+
if !mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) {
871+
span_bug!(
872+
self.tcx.span,
873+
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
874+
src.layout.ty,
875+
dest.layout.ty,
876+
);
877+
}
876878

877879
// Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
878880
let src = match self.try_read_immediate(src)? {

src/librustc_mir/interpret/step.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7878

7979
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
8080
info!("{:?}", stmt);
81+
self.set_span(stmt.source_info.span);
8182

8283
use rustc_middle::mir::StatementKind::*;
8384

8485
// Some statements (e.g., box) push new stack frames.
8586
// We have to record the stack frame number *before* executing the statement.
8687
let frame_idx = self.cur_frame();
87-
self.tcx.span = stmt.source_info.span;
88-
self.memory.tcx.span = stmt.source_info.span;
8988

9089
match &stmt.kind {
9190
Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
@@ -276,16 +275,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
276275

277276
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
278277
info!("{:?}", terminator.kind);
279-
self.tcx.span = terminator.source_info.span;
280-
self.memory.tcx.span = terminator.source_info.span;
281-
282-
let old_stack = self.cur_frame();
283-
let old_bb = self.frame().block;
278+
self.set_span(terminator.source_info.span);
284279

285280
self.eval_terminator(terminator)?;
286281
if !self.stack.is_empty() {
287-
// This should change *something*
288-
assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
289282
if let Some(block) = self.frame().block {
290283
info!("// executing {:?}", block);
291284
}

src/librustc_mir/interpret/terminator.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5252
}
5353

5454
Call { ref func, ref args, destination, ref cleanup, .. } => {
55+
let old_stack = self.cur_frame();
56+
let old_bb = self.frame().block;
5557
let func = self.eval_operand(func, None)?;
5658
let (fn_val, abi) = match func.layout.ty.kind {
5759
ty::FnPtr(sig) => {
@@ -64,14 +66,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6466
let sig = func.layout.ty.fn_sig(*self.tcx);
6567
(FnVal::Instance(self.resolve(def_id, substs)?), sig.abi())
6668
}
67-
_ => bug!("invalid callee of type {:?}", func.layout.ty),
69+
_ => span_bug!(
70+
terminator.source_info.span,
71+
"invalid callee of type {:?}",
72+
func.layout.ty
73+
),
6874
};
6975
let args = self.eval_operands(args)?;
7076
let ret = match destination {
7177
Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
7278
None => None,
7379
};
7480
self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
81+
// Sanity-check that `eval_fn_call` either pushed a new frame or
82+
// did a jump to another block.
83+
if self.cur_frame() == old_stack && self.frame().block == old_bb {
84+
span_bug!(terminator.source_info.span, "evaluating this call made no progress");
85+
}
7586
}
7687

7788
Drop { location, target, unwind } => {
@@ -116,9 +127,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
116127
| FalseEdges { .. }
117128
| FalseUnwind { .. }
118129
| Yield { .. }
119-
| GeneratorDrop => {
120-
bug!("{:#?} should have been eliminated by MIR pass", terminator.kind)
121-
}
130+
| GeneratorDrop => span_bug!(
131+
terminator.source_info.span,
132+
"{:#?} should have been eliminated by MIR pass",
133+
terminator.kind
134+
),
122135
}
123136

124137
Ok(())

src/librustc_mir/transform/const_prop.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
425425
}
426426

427427
fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
428-
self.ecx.tcx.span = c.span;
429-
430428
// FIXME we need to revisit this for #67176
431429
if c.needs_subst() {
432430
return None;
@@ -435,6 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
435433
match self.ecx.eval_const_to_op(c.literal, None) {
436434
Ok(op) => Some(op),
437435
Err(error) => {
436+
// Make sure errors point at the constant.
437+
self.ecx.set_span(c.span);
438438
let err = error_to_const_error(&self.ecx, error);
439439
if let Some(lint_root) = self.lint_root(source_info) {
440440
let lint_only = match c.literal.val {
@@ -820,6 +820,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
820820
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
821821
trace!("visit_statement: {:?}", statement);
822822
let source_info = statement.source_info;
823+
self.ecx.set_span(source_info.span);
823824
self.source_info = Some(source_info);
824825
if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
825826
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
@@ -870,6 +871,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
870871

871872
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
872873
let source_info = terminator.source_info;
874+
self.ecx.set_span(source_info.span);
873875
self.source_info = Some(source_info);
874876
self.super_terminator(terminator, location);
875877
match &mut terminator.kind {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(const_loop)]
2+
3+
static _X: () = loop {}; //~ ERROR could not evaluate static initializer
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: could not evaluate static initializer
2+
--> $DIR/issue-70723.rs:3:17
3+
|
4+
LL | static _X: () = loop {};
5+
| ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)