about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-11 07:23:31 +0000
committerbors <bors@rust-lang.org>2020-05-11 07:23:31 +0000
commit3fe4dd2dda2826643c4ce4ee7307707a90e08d25 (patch)
tree9a81226aa858ac18140897ddf90e4e6174bdfb6d
parentaeb473803d1ead96fab51224ba3e366f44883423 (diff)
parenta1ebb94775daa63cb105cc1c410022c20002667b (diff)
downloadrust-3fe4dd2dda2826643c4ce4ee7307707a90e08d25.tar.gz
rust-3fe4dd2dda2826643c4ce4ee7307707a90e08d25.zip
Auto merge of #71953 - oli-obk:const_prop_deaggregates, r=wesleywiser
Const prop aggregates even if partially or fully modified

r? @wesleywiser

cc @rust-lang/wg-mir-opt I'm moderately scared of this change, but I'm confident in having reviewed all the cases.
-rw-r--r--src/librustc_mir/transform/const_prop.rs100
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable.rs8
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff53
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate.rs8
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff67
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs9
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff58
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop.rs12
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff69
9 files changed, 342 insertions, 42 deletions
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 4be95b69850..e898f22ec23 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -349,8 +349,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn get_const(&self, local: Local) -> Option<OpTy<'tcx>> {
-        let op = self.ecx.access_local(self.ecx.frame(), local, None).ok();
+    fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
+        let op = self.ecx.eval_place_to_op(place, None).ok();
 
         // Try to read the local as an immediate so that if it is representable as a scalar, we can
         // handle it as such, but otherwise, just return the value as is.
@@ -772,13 +772,25 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
-            // Constants must have at most one write
-            // FIXME(oli-obk): we could be more powerful here, if the multiple writes
-            // only occur in independent execution paths
-            MutatingUse(MutatingUseContext::Store) => {
+            // Projections are fine, because `&mut foo.x` will be caught by
+            // `MutatingUseContext::Borrow` elsewhere.
+            MutatingUse(MutatingUseContext::Projection)
+            | MutatingUse(MutatingUseContext::Store) => {
                 if !self.found_assignment.insert(local) {
-                    trace!("local {:?} can't be propagated because of multiple assignments", local);
-                    self.can_const_prop[local] = ConstPropMode::NoPropagation;
+                    match &mut self.can_const_prop[local] {
+                        // If the local can only get propagated in its own block, then we don't have
+                        // to worry about multiple assignments, as we'll nuke the const state at the
+                        // end of the block anyway, and inside the block we overwrite previous
+                        // states as applicable.
+                        ConstPropMode::OnlyInsideOwnBlock => {}
+                        other => {
+                            trace!(
+                                "local {:?} can't be propagated because of multiple assignments",
+                                local,
+                            );
+                            *other = ConstPropMode::NoPropagation;
+                        }
+                    }
                 }
             }
             // Reading constants is allowed an arbitrary number of times
@@ -787,12 +799,6 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
             | NonMutatingUse(NonMutatingUseContext::Inspect)
             | NonMutatingUse(NonMutatingUseContext::Projection)
             | NonUse(_) => {}
-            // FIXME(felix91gr): explain the reasoning behind this
-            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;
@@ -826,40 +832,50 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
         if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
             if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
-                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::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
-                                        || 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);
+                let can_const_prop = self.can_const_prop[place.local];
+                if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
+                    if can_const_prop != ConstPropMode::NoPropagation {
+                        // This will return None for variables that are from other blocks,
+                        // so it should be okay to propagate from here on down.
+                        if let Some(value) = self.get_const(place) {
+                            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
+                                    || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                                {
+                                    trace!("propagated into {:?}", place);
                                 }
                             }
+                            if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
+                                trace!(
+                                    "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
+                                    place.local
+                                );
+                                self.locals_of_current_block.insert(place.local);
+                            }
                         }
                     }
-                    if self.can_const_prop[local] == ConstPropMode::OnlyPropagateInto
-                        || self.can_const_prop[local] == ConstPropMode::NoPropagation
+                    if can_const_prop == ConstPropMode::OnlyPropagateInto
+                        || can_const_prop == ConstPropMode::NoPropagation
                     {
-                        trace!("can't propagate into {:?}", local);
-                        if local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, local);
+                        trace!("can't propagate into {:?}", place);
+                        if place.local != RETURN_PLACE {
+                            Self::remove_const(&mut self.ecx, place.local);
                         }
                     }
+                } else {
+                    // Const prop failed, so erase the destination, ensuring that whatever happens
+                    // from here on, does not know about the previous value.
+                    // This is important in case we have
+                    // ```rust
+                    // let mut x = 42;
+                    // x = SOME_MUTABLE_STATIC;
+                    // // x must now be undefined
+                    // ```
+                    // FIXME: we overzealously erase the entire local, because that's easier to
+                    // implement.
+                    Self::remove_const(&mut self.ecx, place.local);
                 }
             }
         } else {
@@ -993,7 +1009,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                           arguments are of the variant `Operand::Copy`. This allows us to
                           simplify our handling of `Operands` in this case.
                         */
-                        if let Some(l) = opr.place().and_then(|p| p.as_local()) {
+                        if let Some(l) = opr.place() {
                             if let Some(value) = self.get_const(l) {
                                 if self.should_const_prop(value) {
                                     // FIXME(felix91gr): this code only handles `Scalar` cases.
diff --git a/src/test/mir-opt/const_prop/mutable_variable.rs b/src/test/mir-opt/const_prop/mutable_variable.rs
new file mode 100644
index 00000000000..b3a2d80fa95
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = 42;
+    x = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..c6c5b0cf726
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
@@ -0,0 +1,53 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable.rs:4:11: 4:11
+      let mut _1: i32;                     // in scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable.rs:5:9: 5:14
+          let _2: i32;                     // in scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/mutable_variable.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
+          _1 = const 42i32;                // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable.rs:5:17: 5:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+          _1 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+-                                          // + span: $DIR/mutable_variable.rs:6:9: 6:11
++                                          // + span: $DIR/mutable_variable.rs:6:5: 6:11
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
+-         _2 = _1;                         // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++         _2 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000063))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable.rs:4:11: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable.rs:4:11: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/mutable_variable.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
new file mode 100644
index 00000000000..3c5fb4574b6
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = (42, 43);
+    x.1 = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..26f0250d94c
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
@@ -0,0 +1,67 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 4:11
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+          let _2: (i32, i32);              // in scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+          _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+-                                          // + span: $DIR/mutable_variable_aggregate.rs:5:18: 5:20
++                                          // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002b))
+                                           // mir::Constant
+-                                          // + span: $DIR/mutable_variable_aggregate.rs:5:22: 5:24
++                                          // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
+          (_1.1: i32) = const 99i32;       // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+-                                          // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13
++                                          // + span: $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
+-         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++         _2 = (const 42i32, const 99i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x0000002a))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000063))
++                                          // mir::Constant
++                                          // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_aggregate.rs:4:11: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate.rs:4:11: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/mutable_variable_aggregate.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
new file mode 100644
index 00000000000..fc13cbf2abd
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -0,0 +1,9 @@
+// compile-flags: -O
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = (42, 43);
+    let z = &mut x;
+    z.1 = 99;
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..44203ac327a
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff
@@ -0,0 +1,58 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 4:11
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+          let _2: &mut (i32, i32);         // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+          scope 2 {
+              debug z => _2;               // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+              let _3: (i32, i32);          // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+              scope 3 {
+                  debug y => _3;           // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+          _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x0000002b))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
+          _2 = &mut _1;                    // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
+          ((*_2).1: i32) = const 99i32;    // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000063))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:7:11: 7:13
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
+          StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:9: 8:10
+          _3 = _1;                         // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:8:13: 8:14
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:4:11: 9:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
new file mode 100644
index 00000000000..8c9cd005096
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
@@ -0,0 +1,12 @@
+// compile-flags: -O
+
+static mut STATIC: u32 = 42;
+
+// EMIT_MIR rustc.main.ConstProp.diff
+fn main() {
+    let mut x = 42;
+    unsafe {
+        x = STATIC;
+    }
+    let y = x;
+}
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff
new file mode 100644
index 00000000000..1e9cbe6024c
--- /dev/null
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop/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/mutable_variable_no_prop.rs:6:11: 6:11
+      let mut _1: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+      let _2: ();                          // in scope 0 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+      let mut _3: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+      let mut _4: *mut u32;                // in scope 0 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+          let _5: u32;                     // in scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          scope 2 {
+          }
+          scope 3 {
+              debug y => _5;               // in scope 3 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
+          _1 = const 42u32;                // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x0000002a))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
+          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+          StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          _4 = const {alloc0+0x0: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // ty::Const
+                                           // + ty: *mut u32
+                                           // + val: Value(Scalar(alloc0+0x0))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc0+0x0)) }
+          _3 = (*_4);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+          _1 = move _3;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:9:9: 9:19
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:18: 9:19
+          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:19: 9:20
+          _2 = const ();                   // scope 2 at $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:8:5: 10:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:10:5: 10:6
+          StorageLive(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:11:9: 11:10
+          _5 = _1;                         // scope 1 at $DIR/mutable_variable_no_prop.rs:11:13: 11:14
+          _0 = const ();                   // scope 0 at $DIR/mutable_variable_no_prop.rs:6:11: 12:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/mutable_variable_no_prop.rs:6:11: 12:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2
+          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:12:1: 12:2
+          return;                          // scope 0 at $DIR/mutable_variable_no_prop.rs:12:2: 12:2
+      }
+  }
+  
+  alloc0 (static: STATIC, size: 4, align: 4) {
+      2a 00 00 00                                     │ *...
+  }
+