about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-11-22 22:17:15 +0100
committerRalf Jung <post@ralfj.de>2019-11-25 16:25:45 +0100
commit7bfed2e32a3b56a2a9035c64ed8fbfa021c86903 (patch)
tree065445d389f0d560ea3c99b27ca2437179d076eb
parentd9025395c8e46599f062216c818e3388e597d553 (diff)
downloadrust-7bfed2e32a3b56a2a9035c64ed8fbfa021c86903.tar.gz
rust-7bfed2e32a3b56a2a9035c64ed8fbfa021c86903.zip
refactor goto_block and also add unwind_to_block
-rw-r--r--src/librustc_mir/const_eval.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs38
-rw-r--r--src/librustc_mir/interpret/terminator.rs19
3 files changed, 38 insertions, 21 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 0ff9d1b4af0..fc17da498ec 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 08640476f7a..3253b7758a9 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<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)?;
             }
         }
 
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 50c4a249c63..f61fe7b5e38 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<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