about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs9
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs8
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff225
-rw-r--r--tests/mir-opt/sroa/lifetimes.rs37
4 files changed, 272 insertions, 7 deletions
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 401db890a98..34c60b5ff3c 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -690,7 +690,7 @@ impl Map {
         }
 
         // Recurse with all fields of this place.
-        iter_fields(ty, tcx, |variant, field, ty| {
+        iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
             if let Some(variant) = variant {
                 projection.push(PlaceElem::Downcast(None, variant));
                 let _ = self.make_place(local, projection);
@@ -939,6 +939,7 @@ impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
 pub fn iter_fields<'tcx>(
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     mut f: impl FnMut(Option<VariantIdx>, Field, Ty<'tcx>),
 ) {
     match ty.kind() {
@@ -956,14 +957,14 @@ pub fn iter_fields<'tcx>(
                 for (f_index, f_def) in v_def.fields.iter().enumerate() {
                     let field_ty = f_def.ty(tcx, substs);
                     let field_ty = tcx
-                        .try_normalize_erasing_regions(ty::ParamEnv::reveal_all(), field_ty)
-                        .unwrap_or(field_ty);
+                        .try_normalize_erasing_regions(param_env, field_ty)
+                        .unwrap_or_else(|_| tcx.erase_regions(field_ty));
                     f(variant, f_index.into(), field_ty);
                 }
             }
         }
         ty::Closure(_, substs) => {
-            iter_fields(substs.as_closure().tupled_upvars_ty(), tcx, f);
+            iter_fields(substs.as_closure().tupled_upvars_ty(), tcx, param_env, f);
         }
         _ => (),
     }
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 13168e9a268..ca2221520c8 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -4,7 +4,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields};
 
 pub struct ScalarReplacementOfAggregates;
@@ -18,11 +18,12 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!(def_id = ?body.source.def_id());
         let mut excluded = excluded_locals(body);
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         loop {
             debug!(?excluded);
             let escaping = escaping_locals(&excluded, body);
             debug!(?escaping);
-            let replacements = compute_flattening(tcx, body, escaping);
+            let replacements = compute_flattening(tcx, param_env, body, escaping);
             debug!(?replacements);
             let all_dead_locals = replace_flattened_locals(tcx, body, replacements);
             if !all_dead_locals.is_empty() {
@@ -144,6 +145,7 @@ impl<'tcx> ReplacementMap<'tcx> {
 /// The replacement will be done later in `ReplacementVisitor`.
 fn compute_flattening<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     escaping: BitSet<Local>,
 ) -> ReplacementMap<'tcx> {
@@ -155,7 +157,7 @@ fn compute_flattening<'tcx>(
         }
         let decl = body.local_decls[local].clone();
         let ty = decl.ty;
-        iter_fields(ty, tcx, |variant, field, field_ty| {
+        iter_fields(ty, tcx, param_env, |variant, field, field_ty| {
             if variant.is_some() {
                 // Downcasts are currently not supported.
                 return;
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..d41cdc09cac
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,225 @@
+- // MIR for `foo` before ScalarReplacementOfAggregates
++ // MIR for `foo` after ScalarReplacementOfAggregates
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lifetimes.rs:+0:18: +0:18
+      let _1: Foo<T>;                      // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+      let mut _2: std::result::Result<std::boxed::Box<(dyn std::fmt::Display + ReErased)>, <T as Err>::Err>; // in scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+      let mut _3: std::boxed::Box<(dyn std::fmt::Display + ReErased)>; // in scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+      let mut _4: std::boxed::Box<u32>;    // in scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+      let mut _7: isize;                   // in scope 0 at $DIR/lifetimes.rs:+9:12: +9:17
+      let _9: ();                          // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _10: ();                         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _11: std::fmt::Arguments<ReErased>; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _12: &ReErased [&ReErased str]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let mut _13: &ReErased [&ReErased str; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let _14: &ReErased [&ReErased str; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let _15: [&ReErased str; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let mut _16: &ReErased [core::fmt::ArgumentV1<ReErased>]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _17: &ReErased [core::fmt::ArgumentV1<ReErased>; Const(Value(Leaf(0x0000000000000002)): usize)]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _18: &ReErased [core::fmt::ArgumentV1<ReErased>; Const(Value(Leaf(0x0000000000000002)): usize)]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _19: [core::fmt::ArgumentV1<ReErased>; Const(Value(Leaf(0x0000000000000002)): usize)]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _20: core::fmt::ArgumentV1<ReErased>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let mut _21: &ReErased std::boxed::Box<(dyn std::fmt::Display + ReErased)>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let _22: &ReErased std::boxed::Box<(dyn std::fmt::Display + ReErased)>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let mut _23: core::fmt::ArgumentV1<ReErased>; // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let mut _24: &ReErased u32;          // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let _25: &ReErased u32;              // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let mut _27: bool;                   // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _28: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _29: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _30: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++     let _31: std::result::Result<std::boxed::Box<(dyn std::fmt::Display + ReErased)>, <T as Err>::Err>; // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++     let _32: u32;                        // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+      scope 1 {
+-         debug foo => _1;                 // in scope 1 at $DIR/lifetimes.rs:+1:9: +1:12
++         debug foo => Foo<T>{ .0 => _31, .1 => _32, }; // in scope 1 at $DIR/lifetimes.rs:+1:9: +1:12
+          let _5: std::result::Result<std::boxed::Box<(dyn std::fmt::Display + ReErased)>, <T as Err>::Err>; // in scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
+          scope 2 {
+              debug x => _5;               // in scope 2 at $DIR/lifetimes.rs:+6:9: +6:10
+              let _6: u32;                 // in scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
+              scope 3 {
+                  debug y => _6;           // in scope 3 at $DIR/lifetimes.rs:+7:9: +7:10
+                  scope 4 {
+                      debug x => _8;       // in scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+                      let _8: std::boxed::Box<(dyn std::fmt::Display + ReErased)>; // in scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+                      let mut _26: &ReErased [&ReErased str; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          _27 = const ConstValue(Scalar(0x00): bool); // bb0[0]: scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+-         StorageLive(_1);                 // bb0[1]: scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+-         StorageLive(_2);                 // bb0[2]: scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+-         StorageLive(_3);                 // bb0[3]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+-         StorageLive(_4);                 // bb0[4]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+-         _4 = ConstValue(ZeroSized: fn(u32) -> Box<u32> {Box::<u32>::new})(const ConstValue(Scalar(0x00000005): u32)) -> bb1; // bb0[5]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
++         StorageLive(_31);                // bb0[1]: scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         StorageLive(_32);                // bb0[2]: scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         nop;                             // bb0[3]: scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         StorageLive(_2);                 // bb0[4]: scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
++         StorageLive(_3);                 // bb0[5]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
++         StorageLive(_4);                 // bb0[6]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
++         _4 = ConstValue(ZeroSized: fn(u32) -> Box<u32> {Box::<u32>::new})(const ConstValue(Scalar(0x00000005): u32)) -> bb1; // bb0[7]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:19:15: 19:23
+                                           // + user_ty: UserType(1)
+                                           // + literal: Const { ty: fn(u32) -> Box<u32> {Box::<u32>::new}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _3 = move _4 as std::boxed::Box<(dyn std::fmt::Display + ReErased)> (Pointer(Unsize)); // bb1[0]: scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+          StorageDead(_4);                 // bb1[1]: scope 0 at $DIR/lifetimes.rs:+2:29: +2:30
+          _2 = Result::<Box<(dyn std::fmt::Display + ReErased)>, <T as Err>::Err>::Ok(move _3); // bb1[2]: scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+          StorageDead(_3);                 // bb1[3]: scope 0 at $DIR/lifetimes.rs:+2:30: +2:31
+-         _1 = Foo::<T> { x: move _2, y: const ConstValue(Scalar(0x00000007): u32) }; // bb1[4]: scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
+-         StorageDead(_2);                 // bb1[5]: scope 0 at $DIR/lifetimes.rs:+4:5: +4:6
+-         StorageLive(_5);                 // bb1[6]: scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
+-         _27 = const ConstValue(Scalar(0x01): bool); // bb1[7]: scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+-         _5 = move (_1.0: std::result::Result<std::boxed::Box<(dyn std::fmt::Display + ReErased)>, <T as Err>::Err>); // bb1[8]: scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+-         StorageLive(_6);                 // bb1[9]: scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
+-         _6 = (_1.1: u32);                // bb1[10]: scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
+-         _7 = discriminant(_5);           // bb1[11]: scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+-         switchInt(move _7) -> [0: bb2, otherwise: bb7]; // bb1[12]: scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
++         _31 = move _2;                   // bb1[4]: scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         _32 = const ConstValue(Scalar(0x00000007): u32); // bb1[5]: scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         nop;                             // bb1[6]: scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         StorageDead(_2);                 // bb1[7]: scope 0 at $DIR/lifetimes.rs:+4:5: +4:6
++         StorageLive(_5);                 // bb1[8]: scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
++         _27 = const ConstValue(Scalar(0x01): bool); // bb1[9]: scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
++         _5 = move _31;                   // bb1[10]: scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
++         StorageLive(_6);                 // bb1[11]: scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
++         _6 = _32;                        // bb1[12]: scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
++         _7 = discriminant(_5);           // bb1[13]: scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
++         switchInt(move _7) -> [0: bb2, otherwise: bb7]; // bb1[14]: scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+      }
+  
+      bb2: {
+          StorageLive(_8);                 // bb2[0]: scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          _27 = const ConstValue(Scalar(0x00): bool); // bb2[1]: scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          _8 = move ((_5 as Ok).0: std::boxed::Box<(dyn std::fmt::Display + ReErased)>); // bb2[2]: scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          StorageLive(_9);                 // bb2[3]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_10);                // bb2[4]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_11);                // bb2[5]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_12);                // bb2[6]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageLive(_13);                // bb2[7]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageLive(_14);                // bb2[8]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _26 = const _;                   // bb2[9]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:19: 27:28
+                                           // + literal: Const { ty: &ReErased [&ReErased str; Const(Value(Leaf(0x0000000000000003)): usize)], val: Unevaluated(foo, [T], Some(promoted[0])) }
+          _14 = &ReErased (*_26);          // bb2[10]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _13 = &ReErased (*_14);          // bb2[11]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _12 = move _13 as &ReErased [&ReErased str] (Pointer(Unsize)); // bb2[12]: scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageDead(_13);                // bb2[13]: scope 4 at $DIR/lifetimes.rs:+10:27: +10:28
+          StorageLive(_16);                // bb2[14]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_17);                // bb2[15]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_18);                // bb2[16]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_19);                // bb2[17]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_20);                // bb2[18]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_21);                // bb2[19]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_22);                // bb2[20]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _22 = &ReErased _8;              // bb2[21]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _21 = &ReErased (*_22);          // bb2[22]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _20 = ConstValue(ZeroSized: for<Region(BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b))> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) }) Box<(dyn std::fmt::Display + ReErased)>) -> core::fmt::ArgumentV1<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) })> {core::fmt::ArgumentV1::<ReErased>::new_display::<Box<(dyn std::fmt::Display + ReErased)>>})(move _21) -> bb3; // bb2[23]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:21: 27:22
+                                           // + user_ty: UserType(4)
+                                           // + literal: Const { ty: for<Region(BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b))> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) }) Box<(dyn std::fmt::Display + ReErased)>) -> core::fmt::ArgumentV1<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) })> {core::fmt::ArgumentV1::<ReErased>::new_display::<Box<(dyn std::fmt::Display + ReErased)>>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_21);                // bb3[0]: scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_23);                // bb3[1]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          StorageLive(_24);                // bb3[2]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          StorageLive(_25);                // bb3[3]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _25 = &ReErased _6;              // bb3[4]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _24 = &ReErased (*_25);          // bb3[5]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _23 = ConstValue(ZeroSized: for<Region(BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b))> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) }) u32) -> core::fmt::ArgumentV1<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) })> {core::fmt::ArgumentV1::<ReErased>::new_display::<u32>})(move _24) -> bb4; // bb3[6]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:25: 27:26
+                                           // + user_ty: UserType(5)
+                                           // + literal: Const { ty: for<Region(BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b))> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) }) u32) -> core::fmt::ArgumentV1<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(2:49824 ~ core[0bcc]::fmt::{impl#3}::new_display::'b), 'b) })> {core::fmt::ArgumentV1::<ReErased>::new_display::<u32>}, val: Value(<ZST>) }
+      }
+  
+      bb4: {
+          StorageDead(_24);                // bb4[0]: scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _19 = [move _20, move _23];      // bb4[1]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_23);                // bb4[2]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_20);                // bb4[3]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _18 = &ReErased _19;             // bb4[4]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _17 = &ReErased (*_18);          // bb4[5]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _16 = move _17 as &ReErased [core::fmt::ArgumentV1<ReErased>] (Pointer(Unsize)); // bb4[6]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_17);                // bb4[7]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _11 = ConstValue(ZeroSized: fn(&ReErased [&ReStatic str], &ReErased [core::fmt::ArgumentV1<ReErased>]) -> Arguments<ReErased> {Arguments::<ReErased>::new_v1})(move _12, move _16) -> bb5; // bb4[8]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // + user_ty: UserType(3)
+                                           // + literal: Const { ty: fn(&ReErased [&ReStatic str], &ReErased [core::fmt::ArgumentV1<ReErased>]) -> Arguments<ReErased> {Arguments::<ReErased>::new_v1}, val: Value(<ZST>) }
+      }
+  
+      bb5: {
+          StorageDead(_16);                // bb5[0]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_12);                // bb5[1]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _10 = ConstValue(ZeroSized: for<Region(BrNamed(DefId(1:13237 ~ std[b4ed]::io::stdio::_eprint::'_), '_))> fn(Arguments<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(1:13237 ~ std[b4ed]::io::stdio::_eprint::'_), '_) })>) {_eprint})(move _11) -> bb6; // bb5[2]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // + literal: Const { ty: for<Region(BrNamed(DefId(1:13237 ~ std[b4ed]::io::stdio::_eprint::'_), '_))> fn(Arguments<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(1:13237 ~ std[b4ed]::io::stdio::_eprint::'_), '_) })>) {_eprint}, val: Value(<ZST>) }
+      }
+  
+      bb6: {
+          StorageDead(_11);                // bb6[0]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_25);                // bb6[1]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_22);                // bb6[2]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // bb6[3]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_18);                // bb6[4]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_14);                // bb6[5]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_10);                // bb6[6]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _9 = const ConstValue(ZeroSized: ()); // bb6[7]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_9);                 // bb6[8]: scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _0 = const ConstValue(ZeroSized: ()); // bb6[9]: scope 4 at $DIR/lifetimes.rs:+9:22: +11:6
+          drop(_8) -> bb8;                 // bb6[10]: scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+      }
+  
+      bb7: {
+          _0 = const ConstValue(ZeroSized: ()); // bb7[0]: scope 3 at $DIR/lifetimes.rs:+11:6: +11:6
+          goto -> bb9;                     // bb7[1]: scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+      }
+  
+      bb8: {
+          StorageDead(_8);                 // bb8[0]: scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+          goto -> bb9;                     // bb8[1]: scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+      }
+  
+      bb9: {
+          StorageDead(_6);                 // bb9[0]: scope 2 at $DIR/lifetimes.rs:+12:1: +12:2
+          _28 = discriminant(_5);          // bb9[1]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          switchInt(move _28) -> [0: bb11, otherwise: bb13]; // bb9[2]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb10: {
+          _27 = const ConstValue(Scalar(0x00): bool); // bb10[0]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          StorageDead(_5);                 // bb10[1]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+-         StorageDead(_1);                 // bb10[2]: scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+-         return;                          // bb10[3]: scope 0 at $DIR/lifetimes.rs:+12:2: +12:2
++         StorageDead(_31);                // bb10[2]: scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         StorageDead(_32);                // bb10[3]: scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         nop;                             // bb10[4]: scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         return;                          // bb10[5]: scope 0 at $DIR/lifetimes.rs:+12:2: +12:2
+      }
+  
+      bb11: {
+          switchInt(_27) -> [0: bb10, otherwise: bb12]; // bb11[0]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb12: {
+          drop(((_5 as Ok).0: std::boxed::Box<(dyn std::fmt::Display + ReErased)>)) -> bb10; // bb12[0]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb13: {
+          drop(_5) -> bb10;                // bb13[0]: scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/lifetimes.rs b/tests/mir-opt/sroa/lifetimes.rs
new file mode 100644
index 00000000000..bf9b57fbfbd
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.rs
@@ -0,0 +1,37 @@
+// unit-test: ScalarReplacementOfAggregates
+// compile-flags: -Zverbose -Cpanic=abort
+// no-prefer-dynamic
+
+trait Err {
+    type Err;
+}
+
+struct Foo<T: Err> {
+    // Check that the `'static` lifetime is erased when creating the local for `x`,
+    // even if we fail to normalize the type.
+    x: Result<Box<dyn std::fmt::Display + 'static>, <T as Err>::Err>,
+    y: u32,
+}
+
+// EMIT_MIR lifetimes.foo.ScalarReplacementOfAggregates.diff
+fn foo<T: Err>() {
+    let foo: Foo<T> = Foo {
+        x: Ok(Box::new(5_u32)),
+        y: 7_u32,
+    };
+
+    let x = foo.x;
+    let y = foo.y;
+
+    if let Ok(x) = x {
+        eprintln!("{x} {y}");
+    }
+}
+
+impl Err for () {
+    type Err = ();
+}
+
+fn main() {
+    foo::<()>()
+}