diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 0ff9d1b4af00..fc17da498ec8 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -338,7 +338,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // that for const fn! We certainly do *not* want to actually call the fn // though, so be sure we return here. return if ecx.hook_panic_fn(instance, args, dest)? { - ecx.goto_block(ret)?; // fully evaluated and done + ecx.return_to_block(ret)?; // callee is fully evaluated and done Ok(None) } else { throw_unsup_format!("calling non-const function `{}`", instance) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 08640476f7ab..3253b7758a91 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -553,6 +553,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + /// Jump to the given block. + #[inline] + pub fn go_to_block(&mut self, target: mir::BasicBlock) { + let frame = self.frame_mut(); + frame.block = Some(target); + frame.stmt = 0; + } + + /// *Return* to the given `target` basic block. + /// Do *not* use for unwinding! Use `unwind_to_block` instead. + /// + /// If `target` is `None`, that indicates the function cannot return, so we raise UB. + pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { + if let Some(target) = target { + Ok(self.go_to_block(target)) + } else { + throw_ub!(Unreachable) + } + } + + /// *Unwind* to the given `target` basic block. + /// Do *not* use for returning! Use `return_to_block` instead. + /// + /// 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) { + let frame = self.frame_mut(); + frame.block = target; + frame.stmt = 0; + } + /// Pops the current frame from the stack, deallocating the /// memory for allocated locals. /// @@ -628,10 +659,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if cur_unwinding { // Follow the unwind edge. let unwind = next_block.expect("Encounted StackPopCleanup::None when unwinding!"); - let next_frame = self.frame_mut(); - // If `unwind` is `None`, we'll leave that function immediately again. - next_frame.block = unwind; - next_frame.stmt = 0; + self.unwind_to_block(unwind); } else { // Follow the normal return edge. // Validate the return value. Do this after deallocating so that we catch dangling @@ -658,7 +686,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Jump to new block -- *after* validation so that the spans make more sense. if let Some(ret) = next_block { - self.goto_block(ret)?; + self.return_to_block(ret)?; } } diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 50c4a249c63c..f61fe7b5e38a 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -12,17 +12,6 @@ use super::{ }; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - #[inline] - pub fn goto_block(&mut self, target: Option) -> InterpResult<'tcx> { - if let Some(target) = target { - self.frame_mut().block = Some(target); - self.frame_mut().stmt = 0; - Ok(()) - } else { - throw_ub!(Unreachable) - } - } - pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, @@ -34,7 +23,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.pop_stack_frame(/* unwinding */ false)? } - Goto { target } => self.goto_block(Some(target))?, + Goto { target } => self.go_to_block(target), SwitchInt { ref discr, @@ -60,7 +49,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - self.goto_block(Some(target_block))?; + self.go_to_block(target_block); } Call { @@ -133,7 +122,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let cond_val = self.read_immediate(self.eval_operand(cond, None)?)? .to_scalar()?.to_bool()?; if expected == cond_val { - self.goto_block(Some(target))?; + self.go_to_block(target); } else { // Compute error message use rustc::mir::interpret::PanicInfo::*; @@ -272,7 +261,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // No stack frame gets pushed, the main loop will just act as if the // call completed. if ret.is_some() { - self.goto_block(ret)?; + self.return_to_block(ret)?; } else { // If this intrinsic call doesn't have a ret block, // then the intrinsic implementation should have