diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6267012dc275..148442deaad7e 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -492,15 +492,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let frame = self.stack.pop().expect( "tried to pop a stack frame, but there were none", ); + // Abort early if we do not want to clean up: We also avoid validation in that case, + // because this is CTFE and the final value will be thoroughly validated anyway. match frame.return_to_block { - StackPopCleanup::Goto(block) => { - self.goto_block(block)?; - } + StackPopCleanup::Goto(_) => {}, StackPopCleanup::None { cleanup } => { if !cleanup { - // Leak the locals. Also skip validation, this is only used by - // static/const computation which does its own (stronger) final - // validation. + assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked"); + // Leak the locals, skip validation. return Ok(()); } } @@ -509,7 +508,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc for local in frame.locals { self.deallocate_local(local)?; } - // Validate the return value. + // Validate the return value. Do this after deallocating so that we catch dangling + // references. if let Some(return_place) = frame.return_place { if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! @@ -530,6 +530,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // Uh, that shouldn't happen... the function did not intend to return return err!(Unreachable); } + // Jump to new block -- *after* validation so that the spans make more sense. + match frame.return_to_block { + StackPopCleanup::Goto(block) => { + self.goto_block(block)?; + } + StackPopCleanup::None { .. } => {} + } if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc... debug!("CONTINUING({}) {}", self.cur_frame(), self.frame().instance);