more precise span for erroneous consts during CTFE/Miri

This commit is contained in:
Ralf Jung 2020-08-11 14:54:02 +02:00
parent 4b4d43fe6a
commit d21e0118d0
5 changed files with 46 additions and 31 deletions

View File

@ -83,9 +83,11 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
////////////////////////////////////////////////////////////////////////////////
/// If this is `None`, we are unwinding and this function doesn't need any clean-up.
/// Just continue the same as with `Resume`.
pub loc: Option<mir::Location>,
/// If this is `Err`, we are not currently executing any particular statement in
/// this frame (can happen e.g. during frame initialziation, and during unwinding on
/// frames without cleanup code).
/// We basically abuse `Result` as `Either`.
pub(super) loc: Result<mir::Location, Span>,
}
/// What we store about a frame in an interpreter backtrace.
@ -189,11 +191,14 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> {
impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
/// Return the `SourceInfo` of the current instruction.
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
self.loc.map(|loc| self.body.source_info(loc))
self.loc.ok().map(|loc| self.body.source_info(loc))
}
pub fn current_span(&self) -> Span {
self.current_source_info().map(|si| si.span).unwrap_or(self.body.span)
match self.loc {
Ok(loc) => self.body.source_info(loc).span,
Err(span) => span,
}
}
}
@ -640,7 +645,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
loc: None, // `None` for errors generated before we start evaluating.
loc: Err(body.span), // Span used for errors caused during preamble.
return_to_block,
return_place,
// 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> {
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
for const_ in &body.required_consts {
let span = const_.span;
let const_ =
self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
self.const_to_op(const_, None)?;
self.const_to_op(const_, None).map_err(|err| {
// If there was an error, set the span of the current frame so this constant.
// Avoiding doing this when evaluation succeeds.
self.frame_mut().loc = Err(span);
err
})?;
}
// Locals are initially uninitialized.
@ -683,9 +694,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
// done
self.frame_mut().locals = locals;
self.frame_mut().loc = Some(mir::Location::START);
M::after_stack_push(self)?;
self.frame_mut().loc = Ok(mir::Location::START);
info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
Ok(())
@ -694,7 +704,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Jump to the given block.
#[inline]
pub fn go_to_block(&mut self, target: mir::BasicBlock) {
self.frame_mut().loc = Some(mir::Location { block: target, statement_index: 0 });
self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 });
}
/// *Return* to the given `target` basic block.
@ -716,7 +726,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// If `target` is `None`, that indicates the function does not need cleanup during
/// unwinding, and we will just keep propagating that upwards.
pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
self.frame_mut().loc = target.map(|block| mir::Location { block, statement_index: 0 });
self.frame_mut().loc = match target {
Some(block) => Ok(mir::Location { block, statement_index: 0 }),
None => Err(self.frame_mut().body.span),
};
}
/// Pops the current frame from the stack, deallocating the
@ -744,8 +757,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
assert_eq!(
unwinding,
match self.frame().loc {
None => true,
Some(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
Err(_) => true,
}
);

View File

@ -47,8 +47,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
let loc = match self.frame().loc {
Some(loc) => loc,
None => {
Ok(loc) => loc,
Err(_) => {
// We are unwinding and this fn has no cleanup code.
// Just go on unwinding.
trace!("unwinding: skipping frame");
@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.eval_terminator(terminator)?;
if !self.stack().is_empty() {
if let Some(loc) = self.frame().loc {
if let Ok(loc) = self.frame().loc {
info!("// executing {:?}", loc.block);
}
}

View File

@ -13,22 +13,28 @@ LL | #![deny(const_err)]
| ^^^^^^^^^
error: any use of this value will cause an error
--> $DIR/const-err-multi.rs:5:1
--> $DIR/const-err-multi.rs:5:19
|
LL | pub const B: i8 = A;
| ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
| ------------------^-
| |
| referenced constant has errors
error: any use of this value will cause an error
--> $DIR/const-err-multi.rs:7:1
--> $DIR/const-err-multi.rs:7:19
|
LL | pub const C: u8 = A as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
| ------------------^-------
| |
| referenced constant has errors
error: any use of this value will cause an error
--> $DIR/const-err-multi.rs:9:1
--> $DIR/const-err-multi.rs:9:24
|
LL | pub const D: i8 = 50 - A;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
| -----------------------^-
| |
| referenced constant has errors
error: aborting due to 4 previous errors

View File

@ -7,9 +7,9 @@ impl<T> PrintName<T> {
//~^ WARN this operation will panic at runtime
}
const fn no_codegen<T>() { //~ERROR evaluation of constant value failed
const fn no_codegen<T>() {
if false {
let _ = PrintName::<T>::VOID;
let _ = PrintName::<T>::VOID; //~ERROR evaluation of constant value failed
}
}

View File

@ -25,14 +25,10 @@ LL | #![warn(const_err, unconditional_panic)]
| ^^^^^^^^^
error[E0080]: evaluation of constant value failed
--> $DIR/erroneous-const.rs:10:1
--> $DIR/erroneous-const.rs:12:17
|
LL | / const fn no_codegen<T>() {
LL | | if false {
LL | | let _ = PrintName::<T>::VOID;
LL | | }
LL | | }
| |_^ referenced constant has errors
LL | let _ = PrintName::<T>::VOID;
| ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
error[E0080]: could not evaluate static initializer
--> $DIR/erroneous-const.rs:16:22