Skip to content

Commit 576d27c

Browse files
committedAug 12, 2020
Auto merge of #75396 - RalfJung:miri-spans, r=oli-obk
Miri: improve spans of required_const failures In #75339 I added a loop evaluating all consts required by a function body. Unfortunately, if one of their evaluations fails, then the span used for that was that of the first statement in the function body, which happened to work form some existing test but is not sensible in general. This PR changes it to point to the whole function instead, which is at least not wrong. r? @oli-obk
2 parents ef1d58e + fd32fe9 commit 576d27c

File tree

11 files changed

+69
-56
lines changed

11 files changed

+69
-56
lines changed
 

‎src/librustc_mir/const_eval/machine.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
301301
Ok(())
302302
}
303303

304-
fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
305-
// Enforce stack size limit.
306-
if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len()) {
304+
#[inline(always)]
305+
fn init_frame_extra(
306+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
307+
frame: Frame<'mir, 'tcx>,
308+
) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
309+
// Enforce stack size limit. Add 1 because this is run before the new frame is pushed.
310+
if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len() + 1) {
307311
throw_exhaust!(StackFrameLimitReached)
308312
} else {
309-
Ok(())
313+
Ok(frame)
310314
}
311315
}
312316

‎src/librustc_mir/interpret/eval_context.rs

+33-20
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_middle::ty::layout::{self, TyAndLayout};
1616
use rustc_middle::ty::{
1717
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
1818
};
19-
use rustc_span::{source_map::DUMMY_SP, Pos, Span};
19+
use rustc_span::{Pos, Span};
2020
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
2121

2222
use super::{
@@ -83,9 +83,11 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
8383
////////////////////////////////////////////////////////////////////////////////
8484
// Current position within the function
8585
////////////////////////////////////////////////////////////////////////////////
86-
/// If this is `None`, we are unwinding and this function doesn't need any clean-up.
87-
/// Just continue the same as with `Resume`.
88-
pub loc: Option<mir::Location>,
86+
/// If this is `Err`, we are not currently executing any particular statement in
87+
/// this frame (can happen e.g. during frame initialization, and during unwinding on
88+
/// frames without cleanup code).
89+
/// We basically abuse `Result` as `Either`.
90+
pub(super) loc: Result<mir::Location, Span>,
8991
}
9092

9193
/// What we store about a frame in an interpreter backtrace.
@@ -189,7 +191,14 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> {
189191
impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
190192
/// Return the `SourceInfo` of the current instruction.
191193
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
192-
self.loc.map(|loc| self.body.source_info(loc))
194+
self.loc.ok().map(|loc| self.body.source_info(loc))
195+
}
196+
197+
pub fn current_span(&self) -> Span {
198+
match self.loc {
199+
Ok(loc) => self.body.source_info(loc).span,
200+
Err(span) => span,
201+
}
193202
}
194203
}
195204

@@ -324,11 +333,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
324333

325334
#[inline(always)]
326335
pub fn cur_span(&self) -> Span {
327-
self.stack()
328-
.last()
329-
.and_then(|f| f.current_source_info())
330-
.map(|si| si.span)
331-
.unwrap_or(self.tcx.span)
336+
self.stack().last().map(|f| f.current_span()).unwrap_or(self.tcx.span)
332337
}
333338

334339
#[inline(always)]
@@ -640,7 +645,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
640645
// first push a stack frame so we have access to the local substs
641646
let pre_frame = Frame {
642647
body,
643-
loc: Some(mir::Location::START),
648+
loc: Err(body.span), // Span used for errors caused during preamble.
644649
return_to_block,
645650
return_place,
646651
// empty local array, we fill it in below, after we are inside the stack frame and
@@ -654,9 +659,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
654659

655660
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
656661
for const_ in &body.required_consts {
662+
let span = const_.span;
657663
let const_ =
658664
self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
659-
self.const_to_op(const_, None)?;
665+
self.const_to_op(const_, None).map_err(|err| {
666+
// If there was an error, set the span of the current frame to this constant.
667+
// Avoiding doing this when evaluation succeeds.
668+
self.frame_mut().loc = Err(span);
669+
err
670+
})?;
660671
}
661672

662673
// Locals are initially uninitialized.
@@ -683,8 +694,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
683694
}
684695
// done
685696
self.frame_mut().locals = locals;
686-
687697
M::after_stack_push(self)?;
698+
self.frame_mut().loc = Ok(mir::Location::START);
688699
info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
689700

690701
Ok(())
@@ -693,7 +704,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
693704
/// Jump to the given block.
694705
#[inline]
695706
pub fn go_to_block(&mut self, target: mir::BasicBlock) {
696-
self.frame_mut().loc = Some(mir::Location { block: target, statement_index: 0 });
707+
self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 });
697708
}
698709

699710
/// *Return* to the given `target` basic block.
@@ -715,7 +726,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
715726
/// If `target` is `None`, that indicates the function does not need cleanup during
716727
/// unwinding, and we will just keep propagating that upwards.
717728
pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
718-
self.frame_mut().loc = target.map(|block| mir::Location { block, statement_index: 0 });
729+
self.frame_mut().loc = match target {
730+
Some(block) => Ok(mir::Location { block, statement_index: 0 }),
731+
None => Err(self.frame_mut().body.span),
732+
};
719733
}
720734

721735
/// Pops the current frame from the stack, deallocating the
@@ -743,8 +757,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
743757
assert_eq!(
744758
unwinding,
745759
match self.frame().loc {
746-
None => true,
747-
Some(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
760+
Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
761+
Err(_) => true,
748762
}
749763
);
750764

@@ -920,14 +934,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
920934
pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
921935
let mut frames = Vec::new();
922936
for frame in self.stack().iter().rev() {
923-
let source_info = frame.current_source_info();
924-
let lint_root = source_info.and_then(|source_info| {
937+
let lint_root = frame.current_source_info().and_then(|source_info| {
925938
match &frame.body.source_scopes[source_info.scope].local_data {
926939
mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
927940
mir::ClearCrossCrate::Clear => None,
928941
}
929942
});
930-
let span = source_info.map_or(DUMMY_SP, |source_info| source_info.span);
943+
let span = frame.current_span();
931944

932945
frames.push(FrameInfo { span, instance: frame.instance, lint_root });
933946
}

‎src/librustc_mir/interpret/intrinsics/caller_location.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3030
// Assert that there is always such a frame.
3131
.unwrap();
3232
// Assert that the frame we look at is actually executing code currently
33-
// (`current_source_info` is None when we are unwinding and the frame does
34-
// not require cleanup).
33+
// (`loc` is `Err` when we are unwinding and the frame does not require cleanup).
3534
let loc = frame.loc.unwrap();
3635
// If this is a `Call` terminator, use the `fn_span` instead.
3736
let block = &frame.body.basic_blocks()[loc.block];

‎src/librustc_mir/interpret/machine.rs

-8
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,4 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
409409
) -> Self::PointerTag {
410410
()
411411
}
412-
413-
#[inline(always)]
414-
fn init_frame_extra(
415-
_ecx: &mut InterpCx<$mir, $tcx, Self>,
416-
frame: Frame<$mir, $tcx>,
417-
) -> InterpResult<$tcx, Frame<$mir, $tcx>> {
418-
Ok(frame)
419-
}
420412
}

‎src/librustc_mir/interpret/step.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4747
}
4848

4949
let loc = match self.frame().loc {
50-
Some(loc) => loc,
51-
None => {
50+
Ok(loc) => loc,
51+
Err(_) => {
5252
// We are unwinding and this fn has no cleanup code.
5353
// Just go on unwinding.
5454
trace!("unwinding: skipping frame");
@@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
283283

284284
self.eval_terminator(terminator)?;
285285
if !self.stack().is_empty() {
286-
if let Some(loc) = self.frame().loc {
286+
if let Ok(loc) = self.frame().loc {
287287
info!("// executing {:?}", loc.block);
288288
}
289289
}

‎src/librustc_mir/transform/const_prop.rs

+8
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
281281
Ok(())
282282
}
283283

284+
#[inline(always)]
285+
fn init_frame_extra(
286+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
287+
frame: Frame<'mir, 'tcx>,
288+
) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
289+
Ok(frame)
290+
}
291+
284292
#[inline(always)]
285293
fn stack(
286294
ecx: &'a InterpCx<'mir, 'tcx, Self>,

‎src/test/ui/consts/const-err-multi.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ error: any use of this value will cause an error
2424
--> $DIR/const-err-multi.rs:7:19
2525
|
2626
LL | pub const C: u8 = A as u8;
27-
| ------------------^^^^^^^-
27+
| ------------------^-------
2828
| |
2929
| referenced constant has errors
3030

3131
error: any use of this value will cause an error
32-
--> $DIR/const-err-multi.rs:9:19
32+
--> $DIR/const-err-multi.rs:9:24
3333
|
3434
LL | pub const D: i8 = 50 - A;
35-
| ------------------^^^^^^-
36-
| |
37-
| referenced constant has errors
35+
| -----------------------^-
36+
| |
37+
| referenced constant has errors
3838

3939
error: aborting due to 4 previous errors
4040

‎src/test/ui/consts/const-eval/erroneous-const.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ impl<T> PrintName<T> {
88
}
99

1010
const fn no_codegen<T>() {
11-
if false { //~ERROR evaluation of constant value failed
12-
let _ = PrintName::<T>::VOID;
11+
if false {
12+
let _ = PrintName::<T>::VOID; //~ERROR evaluation of constant value failed
1313
}
1414
}
1515

‎src/test/ui/consts/const-eval/erroneous-const.stderr

+3-5
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ LL | #![warn(const_err, unconditional_panic)]
2525
| ^^^^^^^^^
2626

2727
error[E0080]: evaluation of constant value failed
28-
--> $DIR/erroneous-const.rs:11:5
28+
--> $DIR/erroneous-const.rs:12:17
2929
|
30-
LL | / if false {
31-
LL | | let _ = PrintName::<T>::VOID;
32-
LL | | }
33-
| |_____^ referenced constant has errors
30+
LL | let _ = PrintName::<T>::VOID;
31+
| ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
3432

3533
error[E0080]: could not evaluate static initializer
3634
--> $DIR/erroneous-const.rs:16:22

‎src/test/ui/consts/uninhabited-const-issue-61744.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// build-fail
22

33
pub const unsafe fn fake_type<T>() -> T {
4-
hint_unreachable() //~ ERROR evaluation of constant value failed
4+
hint_unreachable()
55
}
66

77
pub const unsafe fn hint_unreachable() -> ! {
8-
fake_type()
8+
fake_type() //~ ERROR evaluation of constant value failed
99
}
1010

1111
trait Const {

‎src/test/ui/consts/uninhabited-const-issue-61744.stderr

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
error[E0080]: evaluation of constant value failed
2-
--> $DIR/uninhabited-const-issue-61744.rs:4:5
2+
--> $DIR/uninhabited-const-issue-61744.rs:8:5
33
|
44
LL | hint_unreachable()
5-
| ^^^^^^^^^^^^^^^^^^
5+
| ------------------
66
| |
7-
| reached the configured maximum number of stack frames
8-
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
97
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
108
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
119
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
@@ -72,8 +70,9 @@ LL | hint_unreachable()
7270
| inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
7371
...
7472
LL | fake_type()
75-
| -----------
73+
| ^^^^^^^^^^^
7674
| |
75+
| reached the configured maximum number of stack frames
7776
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
7877
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
7978
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5

0 commit comments

Comments
 (0)
Please sign in to comment.