about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/transform/const_prop.rs91
-rw-r--r--src/test/mir-opt/const_prop/bad_op_div_by_zero.rs6
-rw-r--r--src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff117
-rw-r--r--src/test/mir-opt/const_prop/bad_op_mod_by_zero.rs6
-rw-r--r--src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff117
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs9
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff83
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff83
-rw-r--r--src/test/mir-opt/const_prop/scalar_literal_propagation.rs8
-rw-r--r--src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff55
-rw-r--r--src/test/mir-opt/const_prop/tuple_literal_propagation.rs9
-rw-r--r--src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff69
-rw-r--r--src/test/mir-opt/simplify-arm-identity.rs1
-rw-r--r--src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff53
-rw-r--r--src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff53
-rw-r--r--src/test/mir-opt/simplify_match.rs2
-rw-r--r--src/test/mir-opt/simplify_match/rustc.main.ConstProp.diff (renamed from src/test/mir-opt/simplify_match/rustc.main.SimplifyBranches-after-copy-prop.diff)45
-rw-r--r--src/test/run-fail/divide-by-zero.rs2
-rw-r--r--src/test/run-fail/dst-raw-slice.rs2
-rw-r--r--src/test/run-fail/mod-zero.rs2
-rw-r--r--src/test/ui/mir/mir_detects_invalid_ops.rs24
-rw-r--r--src/test/ui/mir/mir_detects_invalid_ops.stderr22
22 files changed, 818 insertions, 41 deletions
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index a38cf3bba85..09d8f89676a 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -274,6 +274,8 @@ struct ConstPropagator<'mir, 'tcx> {
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
+    // Locals we need to forget at the end of the current block
+    locals_of_current_block: BitSet<Local>,
 }
 
 impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -343,6 +345,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
             local_decls: body.local_decls.clone(),
             source_info: None,
+            locals_of_current_block: BitSet::new_empty(body.local_decls.len()),
         }
     }
 
@@ -357,8 +360,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn remove_const(&mut self, local: Local) {
-        self.ecx.frame_mut().locals[local] =
+    /// Remove `local` from the pool of `Locals`. Allows writing to them,
+    /// but not reading from them anymore.
+    fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
+        ecx.frame_mut().locals[local] =
             LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
     }
 
@@ -389,6 +394,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
+    /// Returns the value, if any, of evaluating `c`.
     fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
         // FIXME we need to revisit this for #67176
         if c.needs_subst() {
@@ -429,11 +435,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
+    /// Returns the value, if any, of evaluating `place`.
     fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
         trace!("eval_place(place={:?})", place);
         self.use_ecx(|this| this.ecx.eval_place_to_op(place, None))
     }
 
+    /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
+    /// or `eval_place`, depending on the variant of `Operand` used.
     fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
         match *op {
             Operand::Constant(ref c) => self.eval_constant(c, source_info),
@@ -592,6 +601,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         })
     }
 
+    /// Creates a new `Operand::Constant` from a `Scalar` value
     fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> {
         Operand::Constant(Box::new(Constant {
             span,
@@ -637,6 +647,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     // Found a value represented as a pair. For now only do cont-prop if type of
                     // Rvalue is also a pair with two scalars. The more general case is more
                     // complicated to implement so we'll do it later.
+                    // FIXME: implement the general case stated above ^.
                     let ty = &value.layout.ty.kind;
                     // Only do it for tuples
                     if let ty::Tuple(substs) = ty {
@@ -673,6 +684,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
+    /// Returns `true` if and only if this `op` should be const-propagated into.
     fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
         let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
 
@@ -704,6 +716,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 enum ConstPropMode {
     /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
     FullConstProp,
+    /// The `Local` can only be propagated into and from its own block.
+    OnlyInsideOwnBlock,
     /// The `Local` can be propagated into but reads cannot be propagated.
     OnlyPropagateInto,
     /// No propagation is allowed at all.
@@ -712,28 +726,41 @@ enum ConstPropMode {
 
 struct CanConstProp {
     can_const_prop: IndexVec<Local, ConstPropMode>,
-    // false at the beginning, once set, there are not allowed to be any more assignments
+    // False at the beginning. Once set, no more assignments are allowed to that local.
     found_assignment: BitSet<Local>,
+    // Cache of locals' information
+    local_kinds: IndexVec<Local, LocalKind>,
 }
 
 impl CanConstProp {
-    /// returns true if `local` can be propagated
+    /// Returns true if `local` can be propagated
     fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> {
         let mut cpv = CanConstProp {
             can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
             found_assignment: BitSet::new_empty(body.local_decls.len()),
+            local_kinds: IndexVec::from_fn_n(
+                |local| body.local_kind(local),
+                body.local_decls.len(),
+            ),
         };
         for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
-            // cannot use args at all
-            // cannot use locals because if x < y { y - x } else { x - y } would
+            // Cannot use args at all
+            // Cannot use locals because if x < y { y - x } else { x - y } would
             //        lint for x != y
             // FIXME(oli-obk): lint variables until they are used in a condition
             // FIXME(oli-obk): lint if return value is constant
-            let local_kind = body.local_kind(local);
-
-            if local_kind == LocalKind::Arg || local_kind == LocalKind::Var {
+            if cpv.local_kinds[local] == LocalKind::Arg {
                 *val = ConstPropMode::OnlyPropagateInto;
-                trace!("local {:?} can't be const propagated because it's not a temporary", local);
+                trace!(
+                    "local {:?} can't be const propagated because it's a function argument",
+                    local
+                );
+            } else if cpv.local_kinds[local] == LocalKind::Var {
+                *val = ConstPropMode::OnlyInsideOwnBlock;
+                trace!(
+                    "local {:?} will only be propagated inside its block, because it's a user variable",
+                    local
+                );
             }
         }
         cpv.visit_body(&body);
@@ -759,8 +786,12 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
             | NonMutatingUse(NonMutatingUseContext::Move)
             | NonMutatingUse(NonMutatingUseContext::Inspect)
             | NonMutatingUse(NonMutatingUseContext::Projection)
-            | MutatingUse(MutatingUseContext::Projection)
             | NonUse(_) => {}
+            MutatingUse(MutatingUseContext::Projection) => {
+                if self.local_kinds[local] != LocalKind::Temp {
+                    self.can_const_prop[local] = ConstPropMode::NoPropagation;
+                }
+            }
             _ => {
                 trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
                 self.can_const_prop[local] = ConstPropMode::NoPropagation;
@@ -797,25 +828,35 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                 if let Some(local) = place.as_local() {
                     let can_const_prop = self.can_const_prop[local];
                     if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
-                        if can_const_prop == ConstPropMode::FullConstProp
-                            || can_const_prop == ConstPropMode::OnlyPropagateInto
-                        {
+                        if can_const_prop != ConstPropMode::NoPropagation {
+                            // This will return None for Locals that are from other blocks,
+                            // so it should be okay to propagate from here on down.
                             if let Some(value) = self.get_const(local) {
                                 if self.should_const_prop(value) {
                                     trace!("replacing {:?} with {:?}", rval, value);
                                     self.replace_with_const(rval, value, statement.source_info);
-
-                                    if can_const_prop == ConstPropMode::FullConstProp {
+                                    if can_const_prop == ConstPropMode::FullConstProp
+                                        || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                                    {
                                         trace!("propagated into {:?}", local);
                                     }
                                 }
+                                if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
+                                    trace!(
+                                        "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
+                                        local
+                                    );
+                                    self.locals_of_current_block.insert(local);
+                                }
                             }
                         }
                     }
-                    if self.can_const_prop[local] != ConstPropMode::FullConstProp {
+                    if self.can_const_prop[local] == ConstPropMode::OnlyPropagateInto
+                        || self.can_const_prop[local] == ConstPropMode::NoPropagation
+                    {
                         trace!("can't propagate into {:?}", local);
                         if local != RETURN_PLACE {
-                            self.remove_const(local);
+                            Self::remove_const(&mut self.ecx, local);
                         }
                     }
                 }
@@ -850,11 +891,11 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                     let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
                     let value_const = self.ecx.read_scalar(value).unwrap();
                     if expected != value_const {
-                        // poison all places this operand references so that further code
+                        // Poison all places this operand references so that further code
                         // doesn't use the invalid value
                         match cond {
                             Operand::Move(ref place) | Operand::Copy(ref place) => {
-                                self.remove_const(place.local);
+                                Self::remove_const(&mut self.ecx, place.local);
                             }
                             Operand::Constant(_) => {}
                         }
@@ -916,7 +957,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                     }
                 }
             }
-            //none of these have Operands to const-propagate
+            // None of these have Operands to const-propagate
             TerminatorKind::Goto { .. }
             | TerminatorKind::Resume
             | TerminatorKind::Abort
@@ -931,5 +972,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
             //FIXME(wesleywiser) Call does have Operands that could be const-propagated
             TerminatorKind::Call { .. } => {}
         }
+        // We remove all Locals which are restricted in propagation to their containing blocks.
+        // We wouldn't need to clone, but the borrow checker can't see that we're not aliasing
+        // the locals_of_current_block field, so we need to clone it first.
+        // let ecx = &mut self.ecx;
+        for local in self.locals_of_current_block.iter() {
+            Self::remove_const(&mut self.ecx, local);
+        }
+        self.locals_of_current_block.clear();
     }
 }
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
new file mode 100644
index 00000000000..0cd1f37c9a7
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
@@ -0,0 +1,6 @@
+// EMIT_MIR rustc.main.ConstProp.diff
+#[allow(unconditional_panic)]
+fn main() {
+    let y = 0;
+    let _z = 1 / y;
+}
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..333bf0e320b
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff
@@ -0,0 +1,117 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10
+      let mut _3: i32;                     // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+      let mut _4: bool;                    // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+      let mut _5: bool;                    // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+      let mut _6: bool;                    // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+      scope 1 {
+          debug y => _1;                   // in scope 1 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10
+          let _2: i32;                     // in scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11
+          scope 2 {
+              debug _z => _2;              // in scope 2 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10
+          _1 = const 0i32;                 // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:4:13: 4:14
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          StorageLive(_2);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11
+          StorageLive(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+-         _3 = _1;                         // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+-         _4 = Eq(_3, const 0i32);         // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         _3 = const 0i32;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+-                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + span: $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
++         _4 = const true;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          assert(!move _4, "attempt to divide by zero") -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+      }
+  
+      bb1: {
+-         _5 = Eq(_3, const -1i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         _5 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0xffffffff))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
+-         _6 = Eq(const 1i32, const std::i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _6 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0x00000001))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+-                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _7 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0x80000000))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
+-         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         assert(!const false, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+      }
+  
+      bb2: {
+          _2 = Div(const 1i32, move _3);   // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          StorageDead(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+          _0 = const ();                   // scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 6:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:3:11: 6:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_div_by_zero.rs:6:1: 6:2
+          return;                          // scope 0 at $DIR/bad_op_div_by_zero.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.rs b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.rs
new file mode 100644
index 00000000000..26bccbb90ec
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.rs
@@ -0,0 +1,6 @@
+// EMIT_MIR rustc.main.ConstProp.diff
+#[allow(unconditional_panic)]
+fn main() {
+    let y = 0;
+    let _z = 1 % y;
+}
diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..c081b46366e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff
@@ -0,0 +1,117 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10
+      let mut _3: i32;                     // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+      let mut _4: bool;                    // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+      let mut _5: bool;                    // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+      let mut _6: bool;                    // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+      scope 1 {
+          debug y => _1;                   // in scope 1 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10
+          let _2: i32;                     // in scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11
+          scope 2 {
+              debug _z => _2;              // in scope 2 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10
+          _1 = const 0i32;                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11
+          StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+-         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+-         _4 = Eq(_3, const 0i32);         // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         _3 = const 0i32;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+-                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
++         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          assert(!move _4, "attempt to calculate the remainder with a divisor of zero") -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+      }
+  
+      bb1: {
+-         _5 = Eq(_3, const -1i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0xffffffff))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
+-         _6 = Eq(const 1i32, const std::i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0x00000001))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+-                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+-                                          // + ty: i32
+-                                          // + val: Value(Scalar(0x80000000))
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
+-         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         assert(!const false, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+      }
+  
+      bb2: {
+          _2 = Rem(const 1i32, move _3);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+          _0 = const ();                   // scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 6:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:3:11: 6:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:1: 6:2
+          return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
new file mode 100644
index 00000000000..e517e467c37
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -0,0 +1,9 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR rustc.main.ConstProp.diff
+#[allow(unconditional_panic)]
+fn main() {
+    let a: *const [_] = &[1, 2, 3];
+    unsafe {
+        let _b = (*a)[3];
+    }
+}
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..8ecb77752bb
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
@@ -0,0 +1,83 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11
+      let _1: *const [i32] as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+      let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+          scope 2 {
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+              scope 3 {
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+          StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+                                           // ty::Const
+                                           // + ty: &[i32; 3]
+                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+          _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:34: 5:35
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+          _6 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x00000003))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
+-         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x00000003))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      }
+  
+      bb1: {
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..2778ec02724
--- /dev/null
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
@@ -0,0 +1,83 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11
+      let _1: *const [i32] as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+      let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+          scope 2 {
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+              scope 3 {
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10
+          StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+                                           // ty::Const
+                                           // + ty: &[i32; 3]
+                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+          _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
+          StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:34: 5:35
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+          _6 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x0000000000000003))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
+-         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x0000000000000003))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+      }
+  
+      bb1: {
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:25: 7:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:5: 8:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:8:5: 8:6
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation.rs b/src/test/mir-opt/const_prop/scalar_literal_propagation.rs
new file mode 100644
index 00000000000..a740e69dca2
--- /dev/null
+++ b/src/test/mir-opt/const_prop/scalar_literal_propagation.rs
@@ -0,0 +1,8 @@
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let x = 1;
+    consume(x);
+}
+
+#[inline(never)]
+fn consume(_: u32) { }
diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..0183ff7716c
--- /dev/null
+++ b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff
@@ -0,0 +1,55 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/scalar_literal_propagation.rs:2:11: 2:11
+      let _1: u32;                         // in scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10
+      let _2: ();                          // in scope 0 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
+      let mut _3: u32;                     // in scope 0 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/scalar_literal_propagation.rs:3:9: 3:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10
+          _1 = const 1u32;                 // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/scalar_literal_propagation.rs:3:13: 3:14
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
+          StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
+-         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++         _3 = const 1u32;                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000001))
++                                          // mir::Constant
++                                          // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+          _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
+                                           // ty::Const
+                                           // + ty: fn(u32) {consume}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12
+                                           // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:14: 4:15
+          StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:15: 4:16
+          _0 = const ();                   // scope 0 at $DIR/scalar_literal_propagation.rs:2:11: 5:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/scalar_literal_propagation.rs:2:11: 5:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:5:1: 5:2
+          return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:5:2: 5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.rs b/src/test/mir-opt/const_prop/tuple_literal_propagation.rs
new file mode 100644
index 00000000000..015607cbab1
--- /dev/null
+++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -0,0 +1,9 @@
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let x = (1, 2);
+
+    consume(x);
+}
+
+#[inline(never)]
+fn consume(_: (u32, u32)) { }
diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..1511b361f58
--- /dev/null
+++ b/src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff
@@ -0,0 +1,69 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/tuple_literal_propagation.rs:2:11: 2:11
+      let _1: (u32, u32);                  // in scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
+      let _2: ();                          // in scope 0 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
+      let mut _3: (u32, u32);              // in scope 0 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
+          _1 = (const 1u32, const 2u32);   // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/tuple_literal_propagation.rs:3:14: 3:15
++                                          // + span: $DIR/tuple_literal_propagation.rs:3:13: 3:19
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+-                                          // + span: $DIR/tuple_literal_propagation.rs:3:17: 3:18
++                                          // + span: $DIR/tuple_literal_propagation.rs:3:13: 3:19
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
+          StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
+          StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
+-         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++         _3 = (const 1u32, const 2u32);   // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000001))
++                                          // mir::Constant
++                                          // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000002))
++                                          // mir::Constant
++                                          // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
+          _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
+                                           // ty::Const
+                                           // + ty: fn((u32, u32)) {consume}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
+                                           // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:14: 5:15
+          StorageDead(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:15: 5:16
+          _0 = const ();                   // scope 0 at $DIR/tuple_literal_propagation.rs:2:11: 6:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/tuple_literal_propagation.rs:2:11: 6:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:6:1: 6:2
+          return;                          // scope 0 at $DIR/tuple_literal_propagation.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm-identity.rs b/src/test/mir-opt/simplify-arm-identity.rs
index cc6aab7523f..24e91b3ff61 100644
--- a/src/test/mir-opt/simplify-arm-identity.rs
+++ b/src/test/mir-opt/simplify-arm-identity.rs
@@ -2,6 +2,7 @@
 // Regression test for issue #66856.
 //
 // compile-flags: -Zmir-opt-level=2
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 enum Src {
     Foo(u8),
diff --git a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..bf24bfb2c57
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
@@ -0,0 +1,53 @@
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
+      let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+      scope 1 {
+          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          scope 2 {
+          }
+          scope 3 {
+              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // ty::Const
+                                           // + ty: isize
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
+          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
+          _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
+          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..ff7183e57d2
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
@@ -0,0 +1,53 @@
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
+      let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+      scope 1 {
+          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          scope 2 {
+          }
+          scope 3 {
+              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // ty::Const
+                                           // + ty: isize
+                                           // + val: Value(Scalar(0x0000000000000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
+          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
+          _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
+          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_match.rs b/src/test/mir-opt/simplify_match.rs
index 233f9ff4c40..b8e1ea6f981 100644
--- a/src/test/mir-opt/simplify_match.rs
+++ b/src/test/mir-opt/simplify_match.rs
@@ -1,7 +1,7 @@
 #[inline(never)]
 fn noop() {}
 
-// EMIT_MIR rustc.main.SimplifyBranches-after-copy-prop.diff
+// EMIT_MIR rustc.main.ConstProp.diff
 fn main() {
     match { let x = false; x } {
         true => noop(),
diff --git a/src/test/mir-opt/simplify_match/rustc.main.SimplifyBranches-after-copy-prop.diff b/src/test/mir-opt/simplify_match/rustc.main.ConstProp.diff
index 68b1b70c52a..8003112c46c 100644
--- a/src/test/mir-opt/simplify_match/rustc.main.SimplifyBranches-after-copy-prop.diff
+++ b/src/test/mir-opt/simplify_match/rustc.main.ConstProp.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before SimplifyBranches-after-copy-prop
-+ // MIR for `main` after SimplifyBranches-after-copy-prop
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/simplify_match.rs:5:11: 5:11
@@ -10,19 +10,32 @@
       }
   
       bb0: {
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:11: 6:31
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:17: 6:18
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:21: 6:26
-          nop;                             // scope 1 at $DIR/simplify_match.rs:6:28: 6:29
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:30: 6:31
--         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
--                                          // ty::Const
--                                          // + ty: bool
--                                          // + val: Value(Scalar(0x00))
--                                          // mir::Constant
--                                          // + span: $DIR/simplify_match.rs:6:21: 6:26
--                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         goto -> bb1;                     // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
+          StorageLive(_1);                 // scope 0 at $DIR/simplify_match.rs:6:11: 6:31
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_match.rs:6:17: 6:18
+          _2 = const false;                // scope 0 at $DIR/simplify_match.rs:6:21: 6:26
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_match.rs:6:21: 6:26
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+-         _1 = _2;                         // scope 1 at $DIR/simplify_match.rs:6:28: 6:29
++         _1 = const false;                // scope 1 at $DIR/simplify_match.rs:6:28: 6:29
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/simplify_match.rs:6:28: 6:29
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_match.rs:6:30: 6:31
+-         switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
++         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/simplify_match.rs:7:9: 7:13
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
       }
   
       bb1: {
@@ -47,7 +60,7 @@
       }
   
       bb3: {
-          nop;                             // scope 0 at $DIR/simplify_match.rs:10:1: 10:2
+          StorageDead(_1);                 // scope 0 at $DIR/simplify_match.rs:10:1: 10:2
           return;                          // scope 0 at $DIR/simplify_match.rs:10:2: 10:2
       }
   }
diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs
index fdb3f4842e5..ba93563154a 100644
--- a/src/test/run-fail/divide-by-zero.rs
+++ b/src/test/run-fail/divide-by-zero.rs
@@ -1,5 +1,5 @@
 // error-pattern:attempt to divide by zero
-
+#[allow(unconditional_panic)]
 fn main() {
     let y = 0;
     let _z = 1 / y;
diff --git a/src/test/run-fail/dst-raw-slice.rs b/src/test/run-fail/dst-raw-slice.rs
index 561b1fb42ed..2575de7cc58 100644
--- a/src/test/run-fail/dst-raw-slice.rs
+++ b/src/test/run-fail/dst-raw-slice.rs
@@ -1,6 +1,6 @@
 // Test bounds checking for DST raw slices
 // error-pattern:index out of bounds
-
+#[allow(unconditional_panic)]
 fn main() {
     let a: *const [_] = &[1, 2, 3];
     unsafe {
diff --git a/src/test/run-fail/mod-zero.rs b/src/test/run-fail/mod-zero.rs
index ac2959fcd38..f70b3ac920c 100644
--- a/src/test/run-fail/mod-zero.rs
+++ b/src/test/run-fail/mod-zero.rs
@@ -1,5 +1,5 @@
 // error-pattern:attempt to calculate the remainder with a divisor of zero
-
+#[allow(unconditional_panic)]
 fn main() {
     let y = 0;
     let _z = 1 % y;
diff --git a/src/test/ui/mir/mir_detects_invalid_ops.rs b/src/test/ui/mir/mir_detects_invalid_ops.rs
new file mode 100644
index 00000000000..0940dbe6a5e
--- /dev/null
+++ b/src/test/ui/mir/mir_detects_invalid_ops.rs
@@ -0,0 +1,24 @@
+// build-fail
+
+fn main() {
+    divide_by_zero();
+    mod_by_zero();
+    oob_error_for_slices();
+}
+
+fn divide_by_zero() {
+    let y = 0;
+    let _z = 1 / y; //~ ERROR this operation will panic at runtime [unconditional_panic]
+}
+
+fn mod_by_zero() {
+    let y = 0;
+    let _z = 1 % y; //~ ERROR this operation will panic at runtime [unconditional_panic]
+}
+
+fn oob_error_for_slices() {
+    let a: *const [_] = &[1, 2, 3];
+    unsafe {
+        let _b = (*a)[3]; //~ ERROR this operation will panic at runtime [unconditional_panic]
+    }
+}
diff --git a/src/test/ui/mir/mir_detects_invalid_ops.stderr b/src/test/ui/mir/mir_detects_invalid_ops.stderr
new file mode 100644
index 00000000000..41f03789f23
--- /dev/null
+++ b/src/test/ui/mir/mir_detects_invalid_ops.stderr
@@ -0,0 +1,22 @@
+error: this operation will panic at runtime
+  --> $DIR/mir_detects_invalid_ops.rs:11:14
+   |
+LL |     let _z = 1 / y;
+   |              ^^^^^ attempt to divide by zero
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/mir_detects_invalid_ops.rs:16:14
+   |
+LL |     let _z = 1 % y;
+   |              ^^^^^ attempt to calculate the remainder with a divisor of zero
+
+error: this operation will panic at runtime
+  --> $DIR/mir_detects_invalid_ops.rs:22:18
+   |
+LL |         let _b = (*a)[3];
+   |                  ^^^^^^^ index out of bounds: the len is 3 but the index is 3
+
+error: aborting due to 3 previous errors
+