about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs124
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.rs13
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.diff126
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff48
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.rs5
5 files changed, 276 insertions, 40 deletions
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 403d658bccd..5ec9d13f7d2 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
-use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ConstValue, InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::TyAndLayout;
@@ -15,6 +15,7 @@ use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
 };
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
+use rustc_span::def_id::DefId;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Align, FieldIdx, VariantIdx};
 
@@ -78,7 +79,7 @@ struct ConstAnalysis<'a, 'tcx> {
 }
 
 impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
-    type Value = FlatSet<ScalarInt>;
+    type Value = FlatSet<Scalar>;
 
     const NAME: &'static str = "ConstAnalysis";
 
@@ -182,7 +183,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     if let Some(overflow_target) = overflow_target {
                         let overflow = match overflow {
                             FlatSet::Top => FlatSet::Top,
-                            FlatSet::Elem(overflow) => FlatSet::Elem(overflow.into()),
+                            FlatSet::Elem(overflow) => FlatSet::Elem(Scalar::from_bool(overflow)),
                             FlatSet::Bottom => FlatSet::Bottom,
                         };
                         // We have flooded `target` earlier.
@@ -204,7 +205,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     && let ty::Array(_, len) = operand_ty.ty.kind()
                     && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int()
                 {
-                    state.insert_value_idx(target_len, FlatSet::Elem(len), self.map());
+                    state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
                 }
             }
             _ => self.super_assign(target, rvalue, state),
@@ -222,7 +223,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 if let ty::Array(_, len) = place_ty.ty.kind() {
                     ConstantKind::Ty(*len)
                         .eval(self.tcx, self.param_env)
-                        .try_to_scalar_int()
+                        .try_to_scalar()
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
                     state.get_len(place.local.into(), self.map())
@@ -281,7 +282,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                         .bytes(),
                     _ => return ValueOrPlace::Value(FlatSet::Top),
                 };
-                ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
+                FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx))
             }
             Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
             _ => return self.super_rvalue(rvalue, state),
@@ -297,7 +298,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         constant
             .literal
             .eval(self.tcx, self.param_env)
-            .try_to_scalar_int()
+            .try_to_scalar()
             .map_or(FlatSet::Top, FlatSet::Elem)
     }
 
@@ -339,14 +340,21 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     /// The caller must have flooded `place`.
     fn assign_operand(
         &self,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
         place: PlaceIndex,
         operand: &Operand<'tcx>,
     ) {
         match operand {
             Operand::Copy(rhs) | Operand::Move(rhs) => {
                 if let Some(rhs) = self.map.find(rhs.as_ref()) {
-                    state.insert_place_idx(place, rhs, &self.map)
+                    state.insert_place_idx(place, rhs, &self.map);
+                } else if rhs.projection.first() == Some(&PlaceElem::Deref)
+                    && let FlatSet::Elem(pointer) = state.get(rhs.local.into(), &self.map)
+                    && let rhs_ty = self.local_decls[rhs.local].ty
+                    && let Ok(rhs_layout) = self.tcx.layout_of(self.param_env.and(rhs_ty))
+                {
+                    let op = ImmTy::from_scalar(pointer, rhs_layout).into();
+                    self.assign_constant(state, place, op, &rhs.projection);
                 }
             }
             Operand::Constant(box constant) => {
@@ -363,7 +371,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     #[instrument(level = "trace", skip(self, state))]
     fn assign_constant(
         &self,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
         place: PlaceIndex,
         mut operand: OpTy<'tcx>,
         projection: &[PlaceElem<'tcx>],
@@ -371,7 +379,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         for &(mut proj_elem) in projection {
             if let PlaceElem::Index(index) = proj_elem {
                 if let FlatSet::Elem(index) = state.get(index.into(), &self.map)
-                    && let Ok(offset) = index.try_to_target_usize(self.tcx)
+                    && let Ok(offset) = index.to_target_usize(&self.tcx)
                     && let Some(min_length) = offset.checked_add(1)
                 {
                     proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false };
@@ -406,7 +414,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             &mut |place, op| {
                 if let Ok(imm) = self.ecx.read_immediate_raw(op)
                     && let Some(imm) = imm.right()
-                    && let Immediate::Scalar(Scalar::Int(scalar)) = *imm
+                    && let Immediate::Scalar(scalar) = *imm
                 {
                     state.insert_value_idx(place, FlatSet::Elem(scalar), &self.map);
                 }
@@ -418,11 +426,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
 
     fn binary_op(
         &self,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
         op: BinOp,
         left: &Operand<'tcx>,
         right: &Operand<'tcx>,
-    ) -> (FlatSet<ScalarInt>, FlatSet<bool>) {
+    ) -> (FlatSet<Scalar>, FlatSet<bool>) {
         let left = self.eval_operand(left, state);
         let right = self.eval_operand(right, state);
 
@@ -431,9 +439,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             // Both sides are known, do the actual computation.
             (FlatSet::Elem(left), FlatSet::Elem(right)) => {
                 match self.ecx.overflowing_binary_op(op, &left, &right) {
-                    Ok((Scalar::Int(val), overflow, _)) => {
-                        (FlatSet::Elem(val), FlatSet::Elem(overflow))
-                    }
+                    Ok((val, overflow, _)) => (FlatSet::Elem(val), FlatSet::Elem(overflow)),
                     _ => (FlatSet::Top, FlatSet::Top),
                 }
             }
@@ -445,9 +451,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
 
                 let arg_scalar = const_arg.to_scalar();
-                let Ok(arg_scalar) = arg_scalar.try_to_int() else {
-                    return (FlatSet::Top, FlatSet::Top);
-                };
                 let Ok(arg_value) = arg_scalar.to_bits(layout.size) else {
                     return (FlatSet::Top, FlatSet::Top);
                 };
@@ -473,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     fn eval_operand(
         &self,
         op: &Operand<'tcx>,
-        state: &mut State<FlatSet<ScalarInt>>,
+        state: &mut State<FlatSet<Scalar>>,
     ) -> FlatSet<ImmTy<'tcx>> {
         let value = match self.handle_operand(op, state) {
             ValueOrPlace::Value(value) => value,
@@ -492,24 +495,24 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         }
     }
 
-    fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<ScalarInt> {
+    fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<Scalar> {
         if !enum_ty.is_enum() {
             return None;
         }
         let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
         let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
-        let discr_value = ScalarInt::try_from_uint(discr.val, discr_layout.size)?;
+        let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?;
         Some(discr_value)
     }
 
-    fn wrap_immediate(&self, imm: Immediate) -> FlatSet<ScalarInt> {
+    fn wrap_immediate(&self, imm: Immediate) -> FlatSet<Scalar> {
         match imm {
-            Immediate::Scalar(Scalar::Int(scalar)) => FlatSet::Elem(scalar),
+            Immediate::Scalar(scalar) => FlatSet::Elem(scalar),
             _ => FlatSet::Top,
         }
     }
 
-    fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarInt> {
+    fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<Scalar> {
         self.wrap_immediate(*val)
     }
 }
@@ -550,7 +553,7 @@ impl<'mir, 'tcx>
     ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
     for CollectAndPatch<'tcx, '_>
 {
-    type FlowState = State<FlatSet<ScalarInt>>;
+    type FlowState = State<FlatSet<Scalar>>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
@@ -580,14 +583,10 @@ impl<'mir, 'tcx>
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
             StatementKind::Assign(box (place, _)) => {
-                match state.get(place.as_ref(), &results.analysis.0.map) {
-                    FlatSet::Top => (),
-                    FlatSet::Elem(value) => {
-                        self.assignments.insert(location, value);
-                    }
-                    FlatSet::Bottom => {
-                        // This assignment is either unreachable, or an uninitialized value is assigned.
-                    }
+                if let FlatSet::Elem(Scalar::Int(value)) =
+                    state.get(place.as_ref(), &results.analysis.0.map)
+                {
+                    self.assignments.insert(location, value);
                 }
             }
             _ => (),
@@ -657,7 +656,7 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
 }
 
 struct OperandCollector<'tcx, 'map, 'locals, 'a> {
-    state: &'a State<FlatSet<ScalarInt>>,
+    state: &'a State<FlatSet<Scalar>>,
     visitor: &'a mut CollectAndPatch<'tcx, 'locals>,
     map: &'map Map,
 }
@@ -665,7 +664,7 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> {
 impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         if let Some(place) = operand.place() {
-            if let FlatSet::Elem(value) = self.state.get(place.as_ref(), self.map) {
+            if let FlatSet::Elem(Scalar::Int(value)) = self.state.get(place.as_ref(), self.map) {
                 self.visitor.before_effect.insert((location, place), value);
             } else if !place.projection.is_empty() {
                 // Try to propagate into `Index` projections.
@@ -676,7 +675,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
 
     fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) {
         if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt
-            && let FlatSet::Elem(value) = self.state.get(local.into(), self.map)
+            && let FlatSet::Elem(Scalar::Int(value)) = self.state.get(local.into(), self.map)
         {
             self.visitor.before_effect.insert((location, local.into()), value);
         }
@@ -685,6 +684,34 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
 
 struct DummyMachine;
 
+/// Macro for machine-specific `InterpError` without allocation.
+/// (These will never be shown to the user, but they help diagnose ICEs.)
+macro_rules! throw_machine_stop_str {
+    ($($tt:tt)*) => {{
+        // We make a new local type for it. The type itself does not carry any information,
+        // but its vtable (for the `MachineStopType` trait) does.
+        #[derive(Debug)]
+        struct Zst;
+        // Printing this type shows the desired string.
+        impl std::fmt::Display for Zst {
+            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(f, $($tt)*)
+            }
+        }
+        impl rustc_middle::mir::interpret::MachineStopType for Zst {
+            fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
+                self.to_string().into()
+            }
+
+            fn add_args(
+                self: Box<Self>,
+                _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>),
+            ) {}
+        }
+        throw_machine_stop!(Zst)
+    }};
+}
+
 impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine {
     rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>);
     type MemoryKind = !;
@@ -714,6 +741,27 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         unimplemented!()
     }
 
+    fn before_access_global(
+        _tcx: TyCtxt<'tcx>,
+        _machine: &Self,
+        _alloc_id: AllocId,
+        alloc: ConstAllocation<'tcx>,
+        _static_def_id: Option<DefId>,
+        is_write: bool,
+    ) -> InterpResult<'tcx> {
+        if is_write {
+            throw_machine_stop_str!("can't write to global");
+        }
+
+        // If the static allocation is mutable, then we can't const prop it as its content
+        // might be different at runtime.
+        if alloc.inner().mutability.is_mut() {
+            throw_machine_stop_str!("can't access mutable globals in ConstProp");
+        }
+
+        Ok(())
+    }
+
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs
index a70c0abee5b..6b745707592 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.rs
+++ b/tests/mir-opt/dataflow-const-prop/enum.rs
@@ -4,6 +4,7 @@
 
 use std::intrinsics::mir::*;
 
+#[derive(Copy, Clone)]
 enum E {
     V1(i32),
     V2(i32)
@@ -22,6 +23,17 @@ fn constant() {
     let x = match e { E::V1(x) => x, E::V2(x) => x };
 }
 
+// EMIT_MIR enum.statics.DataflowConstProp.diff
+fn statics() {
+    static C: E = E::V1(0);
+    let e = C;
+    let x = match e { E::V1(x) => x, E::V2(x) => x };
+
+    static RC: &E = &E::V2(4);
+    let e = RC;
+    let x = match e { E::V1(x) => x, E::V2(x) => x };
+}
+
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
 struct NonZeroUsize(usize);
@@ -71,6 +83,7 @@ fn multiple(x: bool, i: u8) {
 fn main() {
     simple();
     constant();
+    statics();
     mutate_discriminant();
     multiple(false, 5);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.diff
new file mode 100644
index 00000000000..63799b3bac3
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.diff
@@ -0,0 +1,126 @@
+- // MIR for `statics` before DataflowConstProp
++ // MIR for `statics` after DataflowConstProp
+  
+  fn statics() -> () {
+      let mut _0: ();
+      let _1: E;
+      let mut _2: &E;
+      let mut _4: isize;
+      let mut _8: &&E;
+      let mut _10: isize;
+      scope 1 {
+          debug e => _1;
+          let _3: i32;
+          let _5: i32;
+          let _6: i32;
+          scope 2 {
+              debug x => _3;
+              let _7: &E;
+              scope 5 {
+                  debug e => _7;
+                  let _9: &i32;
+                  let _11: &i32;
+                  let _12: &i32;
+                  scope 6 {
+                      debug x => _9;
+                  }
+                  scope 7 {
+                      debug x => _11;
+                  }
+                  scope 8 {
+                      debug x => _12;
+                  }
+              }
+          }
+          scope 3 {
+              debug x => _5;
+          }
+          scope 4 {
+              debug x => _6;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = const {alloc1: &E};
+          _1 = (*_2);
+          StorageDead(_2);
+          StorageLive(_3);
+-         _4 = discriminant(_1);
+-         switchInt(move _4) -> [0: bb3, 1: bb1, otherwise: bb2];
++         _4 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = ((_1 as V2).0: i32);
+          _3 = _6;
+          StorageDead(_6);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          StorageLive(_5);
+-         _5 = ((_1 as V1).0: i32);
+-         _3 = _5;
++         _5 = const 0_i32;
++         _3 = const 0_i32;
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = const {alloc2: &&E};
+          _7 = (*_8);
+          StorageDead(_8);
+          StorageLive(_9);
+          _10 = discriminant((*_7));
+          switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb2];
+      }
+  
+      bb5: {
+          StorageLive(_12);
+          _12 = &(((*_7) as V2).0: i32);
+          _9 = &(*_12);
+          StorageDead(_12);
+          goto -> bb7;
+      }
+  
+      bb6: {
+          StorageLive(_11);
+          _11 = &(((*_7) as V1).0: i32);
+          _9 = _11;
+          StorageDead(_11);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_7);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
+  alloc2 (static: RC, size: 8, align: 8) {
+      ╾───────alloc14───────╼                         │ ╾──────╼
+  }
+  
+  alloc14 (size: 8, align: 4) {
+      01 00 00 00 04 00 00 00                         │ ........
+  }
+  
+  alloc1 (static: statics::C, size: 8, align: 4) {
+      00 00 00 00 00 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
index d65221158e4..89e37cc04dc 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
@@ -8,6 +8,12 @@
       let mut _5: i32;
       let mut _6: i32;
       let mut _11: BigStruct;
+      let mut _16: &&BigStruct;
+      let mut _17: &BigStruct;
+      let mut _18: &BigStruct;
+      let mut _19: &BigStruct;
+      let mut _20: &BigStruct;
+      let mut _21: &BigStruct;
       scope 1 {
           debug s => _1;
           let _2: i32;
@@ -25,6 +31,16 @@
                       debug b => _8;
                       debug c => _9;
                       debug d => _10;
+                      let _12: S;
+                      let _13: u8;
+                      let _14: f32;
+                      let _15: S;
+                      scope 5 {
+                          debug a => _12;
+                          debug b => _13;
+                          debug c => _14;
+                          debug d => _15;
+                      }
                   }
               }
           }
@@ -55,7 +71,7 @@
           StorageLive(_11);
           _11 = const _;
           StorageLive(_7);
--         _7 = move (_11.0: S);
+-         _7 = (_11.0: S);
 +         _7 = const S(1_i32);
           StorageLive(_8);
 -         _8 = (_11.1: u8);
@@ -64,10 +80,30 @@
 -         _9 = (_11.2: f32);
 +         _9 = const 7f32;
           StorageLive(_10);
--         _10 = move (_11.3: S);
+-         _10 = (_11.3: S);
 +         _10 = const S(13_i32);
           StorageDead(_11);
+          StorageLive(_16);
+          _16 = const {alloc1: &&BigStruct};
+          _17 = deref_copy (*_16);
+          StorageLive(_12);
+          _18 = deref_copy (*_16);
+          _12 = ((*_18).0: S);
+          StorageLive(_13);
+          _19 = deref_copy (*_16);
+          _13 = ((*_19).1: u8);
+          StorageLive(_14);
+          _20 = deref_copy (*_16);
+          _14 = ((*_20).2: f32);
+          StorageLive(_15);
+          _21 = deref_copy (*_16);
+          _15 = ((*_21).3: S);
+          StorageDead(_16);
           _0 = const ();
+          StorageDead(_15);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
           StorageDead(_10);
           StorageDead(_9);
           StorageDead(_8);
@@ -79,3 +115,11 @@
       }
   }
   
+  alloc1 (static: STAT, size: 8, align: 8) {
+      ╾───────alloc15───────╼                         │ ╾──────╼
+  }
+  
+  alloc15 (size: 16, align: 4) {
+      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs
index d2cd697db25..c171ed74c54 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.rs
+++ b/tests/mir-opt/dataflow-const-prop/struct.rs
@@ -1,7 +1,9 @@
 // unit-test: DataflowConstProp
 
+#[derive(Copy, Clone)]
 struct S(i32);
 
+#[derive(Copy, Clone)]
 struct BigStruct(S, u8, f32, S);
 
 // EMIT_MIR struct.main.DataflowConstProp.diff
@@ -13,4 +15,7 @@ fn main() {
 
     const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13));
     let BigStruct(a, b, c, d) = VAL;
+
+    static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13));
+    let BigStruct(a, b, c, d) = *STAT;
 }