refactor goto_block and also add unwind_to_block

This commit is contained in:
Ralf Jung 2019-11-22 22:17:15 +01:00
parent d9025395c8
commit 7bfed2e32a
3 changed files with 38 additions and 21 deletions

View File

@ -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)

View File

@ -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<mir::BasicBlock>) -> 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<mir::BasicBlock>) {
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)?;
}
}

View File

@ -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<mir::BasicBlock>) -> 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