about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-11-29 09:59:52 +0100
committerRalf Jung <post@ralfj.de>2019-12-02 08:55:42 +0100
commitb1aa3cac5b7f5ac3e527f32431fa82e1c7d00c52 (patch)
treeefca9b1a29e82e88500252349b3ff42022ba4b93
parentf5c81e0a986e4285d3d0fd781a1bd475753eb12c (diff)
downloadrust-b1aa3cac5b7f5ac3e527f32431fa82e1c7d00c52.tar.gz
rust-b1aa3cac5b7f5ac3e527f32431fa82e1c7d00c52.zip
Miri: add machine hook for MIR-level assertion panics
-rw-r--r--src/librustc_mir/const_eval.rs35
-rw-r--r--src/librustc_mir/interpret/machine.rs9
-rw-r--r--src/librustc_mir/interpret/terminator.rs54
-rw-r--r--src/librustc_mir/transform/const_prop.rs8
4 files changed, 67 insertions, 39 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 0967b257885..18b965f4c34 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -23,7 +23,7 @@ use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol};
 use crate::interpret::{self,
     PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
     RawConst, ConstValue, Machine,
-    InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
+    InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, AssertMessage,
     Allocation, AllocId, MemoryKind, Memory,
     snapshot, RefTracking, intern_const_alloc_recursive,
 };
@@ -395,6 +395,39 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         )
     }
 
+    fn assert_panic(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        msg: &AssertMessage<'tcx>,
+        _unwind: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx> {
+        use rustc::mir::interpret::PanicInfo::*;
+        Err(match msg {
+            BoundsCheck { ref len, ref index } => {
+                let len = ecx
+                    .read_immediate(ecx.eval_operand(len, None)?)
+                    .expect("can't eval len")
+                    .to_scalar()?
+                    .to_machine_usize(&*ecx)?;
+                let index = ecx
+                    .read_immediate(ecx.eval_operand(index, None)?)
+                    .expect("can't eval index")
+                    .to_scalar()?
+                    .to_machine_usize(&*ecx)?;
+                err_panic!(BoundsCheck { len, index })
+            }
+            Overflow(op) => err_panic!(Overflow(*op)),
+            OverflowNeg => err_panic!(OverflowNeg),
+            DivisionByZero => err_panic!(DivisionByZero),
+            RemainderByZero => err_panic!(RemainderByZero),
+            ResumedAfterReturn(generator_kind)
+                => err_panic!(ResumedAfterReturn(*generator_kind)),
+            ResumedAfterPanic(generator_kind)
+                => err_panic!(ResumedAfterPanic(*generator_kind)),
+            Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
+        }
+        .into())
+    }
+
     fn ptr_to_int(
         _mem: &Memory<'mir, 'tcx, Self>,
         _ptr: Pointer,
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index b7cde626415..42d5140e348 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -11,7 +11,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use syntax_pos::Span;
 
 use super::{
-    Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
+    Allocation, AllocId, InterpResult, Scalar, AllocationExtra, AssertMessage,
     InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
     Frame, Operand,
 };
@@ -175,6 +175,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx>;
 
+    /// Called to evaluate `Assert` MIR terminators that trigger a panic.
+    fn assert_panic(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        msg: &AssertMessage<'tcx>,
+        unwind: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx>;
+
     /// Called for read access to a foreign static item.
     ///
     /// This will only be called once per static and machine; the result is cached in
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 50cd3188510..a4748252403 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -7,8 +7,8 @@ use syntax::source_map::Span;
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    GlobalId, InterpResult, PointerArithmetic,
-    InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
+    GlobalId, InterpResult, InterpCx, Machine,
+    OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
 };
 
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -115,40 +115,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 expected,
                 ref msg,
                 target,
-                ..
+                cleanup,
             } => {
                 let cond_val = self.read_immediate(self.eval_operand(cond, None)?)?
                     .to_scalar()?.to_bool()?;
                 if expected == cond_val {
                     self.go_to_block(target);
                 } else {
-                    // Compute error message
-                    use rustc::mir::interpret::PanicInfo::*;
-                    return Err(match msg {
-                        BoundsCheck { ref len, ref index } => {
-                            let len = self
-                                .read_immediate(self.eval_operand(len, None)?)
-                                .expect("can't eval len")
-                                .to_scalar()?
-                                .to_bits(self.memory.pointer_size())? as u64;
-                            let index = self
-                                .read_immediate(self.eval_operand(index, None)?)
-                                .expect("can't eval index")
-                                .to_scalar()?
-                                .to_bits(self.memory.pointer_size())? as u64;
-                            err_panic!(BoundsCheck { len, index })
-                        }
-                        Overflow(op) => err_panic!(Overflow(*op)),
-                        OverflowNeg => err_panic!(OverflowNeg),
-                        DivisionByZero => err_panic!(DivisionByZero),
-                        RemainderByZero => err_panic!(RemainderByZero),
-                        ResumedAfterReturn(generator_kind)
-                            => err_panic!(ResumedAfterReturn(*generator_kind)),
-                        ResumedAfterPanic(generator_kind)
-                            => err_panic!(ResumedAfterPanic(*generator_kind)),
-                        Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
-                    }
-                    .into());
+                    M::assert_panic(self, msg, cleanup)?;
                 }
             }
 
@@ -164,15 +138,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 return Ok(())
             },
 
+            // It is UB to ever encounter this.
+            Unreachable => throw_ub!(Unreachable),
+
+            // These should never occur for MIR we actually run.
+            DropAndReplace { .. } |
+            FalseEdges { .. } |
+            FalseUnwind { .. } =>
+                bug!("{:#?} should have been eliminated by MIR pass", terminator.kind),
+
+            // These are not (yet) supported. It is unclear if they even can occur in
+            // MIR that we actually run.
             Yield { .. } |
             GeneratorDrop |
-            DropAndReplace { .. } |
-            Abort => unimplemented!("{:#?}", terminator.kind),
-            FalseEdges { .. } => bug!("should have been eliminated by\
-                                      `simplify_branches` mir pass"),
-            FalseUnwind { .. } => bug!("should have been eliminated by\
-                                       `simplify_branches` mir pass"),
-            Unreachable => throw_ub!(Unreachable),
+            Abort =>
+                throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind),
         }
 
         Ok(())
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 67958af3460..1fb254fb69f 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -156,6 +156,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"));
     }
 
+    fn assert_panic(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _msg: &rustc::mir::interpret::AssertMessage<'tcx>,
+        _unwind: Option<rustc::mir::BasicBlock>,
+    ) -> InterpResult<'tcx> {
+        throw_unsup_format!("panics are not supported in ConstProp");
+    }
+
     fn ptr_to_int(
         _mem: &Memory<'mir, 'tcx, Self>,
         _ptr: Pointer,