summaryrefslogtreecommitdiffstats
path: root/tests/mir-opt/sroa
diff options
context:
space:
mode:
Diffstat (limited to 'tests/mir-opt/sroa')
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff214
-rw-r--r--tests/mir-opt/sroa/lifetimes.rs37
-rw-r--r--tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff46
-rw-r--r--tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff91
-rw-r--r--tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff43
-rw-r--r--tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff80
-rw-r--r--tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff56
-rw-r--r--tests/mir-opt/sroa/structs.rs122
-rw-r--r--tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff33
-rw-r--r--tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff23
12 files changed, 833 insertions, 0 deletions
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 000000000..579587a43
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,214 @@
+- // 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>, <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>; // 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<'_>; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _12: &[&str]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+ let mut _13: &[&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+ let _14: &[&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+ let _15: [&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+ let mut _16: &[core::fmt::ArgumentV1<'_>]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _17: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _18: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let _19: [core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _20: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23
+ let mut _21: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23
+ let _22: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23
+ let mut _23: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27
+ let mut _24: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27
+ let _25: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27
+ 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>, <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>, <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>; // in scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+ let mut _26: &[&str; 3]; // in scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ }
+ }
+ }
+ }
+
+ bb0: {
+ _27 = const false; // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+- StorageLive(_1); // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++ StorageLive(_31); // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++ StorageLive(_32); // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++ nop; // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+ StorageLive(_2); // scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+ StorageLive(_3); // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+ StorageLive(_4); // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+ _4 = Box::<u32>::new(const 5_u32) -> [return: bb1, unwind unreachable]; // 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> (Pointer(Unsize)); // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+ StorageDead(_4); // scope 0 at $DIR/lifetimes.rs:+2:29: +2:30
+ _2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3); // scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+ StorageDead(_3); // scope 0 at $DIR/lifetimes.rs:+2:30: +2:31
+- _1 = Foo::<T> { x: move _2, y: const 7_u32 }; // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++ _31 = move _2; // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++ _32 = const 7_u32; // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++ nop; // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
+ StorageDead(_2); // scope 0 at $DIR/lifetimes.rs:+4:5: +4:6
+ StorageLive(_5); // scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
+ _27 = const true; // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+- _5 = move (_1.0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>); // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
++ _5 = move _31; // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+ StorageLive(_6); // scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
+- _6 = (_1.1: u32); // scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
++ _6 = _32; // scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
+ _7 = discriminant(_5); // scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+ switchInt(move _7) -> [0: bb2, otherwise: bb7]; // scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+ }
+
+ bb2: {
+ StorageLive(_8); // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+ _27 = const false; // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+ _8 = move ((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>); // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+ StorageLive(_9); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_10); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_12); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ StorageLive(_13); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ StorageLive(_14); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ _26 = const _; // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ // mir::Constant
+ // + span: $DIR/lifetimes.rs:27:19: 27:28
+ // + literal: Const { ty: &[&str; 3], val: Unevaluated(foo, [T], Some(promoted[0])) }
+ _14 = &(*_26); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ _13 = &(*_14); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ _12 = move _13 as &[&str] (Pointer(Unsize)); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+ StorageDead(_13); // scope 4 at $DIR/lifetimes.rs:+10:27: +10:28
+ StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_20); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ StorageLive(_21); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ StorageLive(_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ _22 = &_8; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ _21 = &(*_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ _20 = core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _21) -> [return: bb3, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+ // mir::Constant
+ // + span: $DIR/lifetimes.rs:27:20: 27:23
+ // + user_ty: UserType(4)
+ // + literal: Const { ty: for<'b> fn(&'b Box<dyn std::fmt::Display>) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>}, val: Value(<ZST>) }
+ }
+
+ bb3: {
+ StorageDead(_21); // scope 4 at $DIR/lifetimes.rs:+10:22: +10:23
+ StorageLive(_23); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ StorageLive(_24); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ StorageLive(_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ _25 = &_6; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ _24 = &(*_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ _23 = core::fmt::ArgumentV1::<'_>::new_display::<u32>(move _24) -> [return: bb4, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+ // mir::Constant
+ // + span: $DIR/lifetimes.rs:27:24: 27:27
+ // + user_ty: UserType(5)
+ // + literal: Const { ty: for<'b> fn(&'b u32) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<u32>}, val: Value(<ZST>) }
+ }
+
+ bb4: {
+ StorageDead(_24); // scope 4 at $DIR/lifetimes.rs:+10:26: +10:27
+ _19 = [move _20, move _23]; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _18 = &_19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _17 = &(*_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _16 = move _17 as &[core::fmt::ArgumentV1<'_>] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _11 = Arguments::<'_>::new_v1(move _12, move _16) -> [return: bb5, unwind unreachable]; // 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(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1}, val: Value(<ZST>) }
+ }
+
+ bb5: {
+ StorageDead(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; // 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<'a> fn(Arguments<'a>) {_eprint}, val: Value(<ZST>) }
+ }
+
+ bb6: {
+ StorageDead(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_25); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_22); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_14); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_10); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _9 = const (); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_9); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _0 = const (); // scope 4 at $DIR/lifetimes.rs:+9:22: +11:6
+ drop(_8) -> [return: bb8, unwind unreachable]; // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+ }
+
+ bb7: {
+ _0 = const (); // scope 3 at $DIR/lifetimes.rs:+11:6: +11:6
+ goto -> bb9; // scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+ }
+
+ bb8: {
+ StorageDead(_8); // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+ goto -> bb9; // scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+ }
+
+ bb9: {
+ StorageDead(_6); // scope 2 at $DIR/lifetimes.rs:+12:1: +12:2
+ _28 = discriminant(_5); // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+ switchInt(move _28) -> [0: bb11, otherwise: bb13]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+ }
+
+ bb10: {
+ _27 = const false; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+ StorageDead(_5); // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+- StorageDead(_1); // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++ StorageDead(_31); // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++ StorageDead(_32); // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++ nop; // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+ return; // scope 0 at $DIR/lifetimes.rs:+12:2: +12:2
+ }
+
+ bb11: {
+ switchInt(_27) -> [0: bb10, otherwise: bb12]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+ }
+
+ bb12: {
+ drop(((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>)) -> [return: bb10, unwind unreachable]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+ }
+
+ bb13: {
+ drop(_5) -> [return: bb10, unwind unreachable]; // 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 000000000..2356d212f
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.rs
@@ -0,0 +1,37 @@
+// unit-test: ScalarReplacementOfAggregates
+// compile-flags: -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::<()>()
+}
diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..647681f0e
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,46 @@
+- // MIR for `constant` before ScalarReplacementOfAggregates
++ // MIR for `constant` after ScalarReplacementOfAggregates
+
+ fn constant() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:15: +0:15
+ let _1: (usize, u8); // in scope 0 at $DIR/structs.rs:+2:9: +2:10
++ let _4: usize; // in scope 0 at $DIR/structs.rs:+2:9: +2:10
++ let _5: u8; // in scope 0 at $DIR/structs.rs:+2:9: +2:10
+ scope 1 {
+- debug y => _1; // in scope 1 at $DIR/structs.rs:+2:9: +2:10
++ debug y => (usize, u8){ .0 => _4, .1 => _5, }; // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+ let _2: usize; // in scope 1 at $DIR/structs.rs:+3:9: +3:10
+ scope 2 {
+ debug t => _2; // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+ let _3: u8; // in scope 2 at $DIR/structs.rs:+4:9: +4:10
+ scope 3 {
+ debug u => _3; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
+ }
+ }
+ }
+
+ bb0: {
+- StorageLive(_1); // scope 0 at $DIR/structs.rs:+2:9: +2:10
++ StorageLive(_4); // scope 0 at $DIR/structs.rs:+2:9: +2:10
++ StorageLive(_5); // scope 0 at $DIR/structs.rs:+2:9: +2:10
++ nop; // scope 0 at $DIR/structs.rs:+2:9: +2:10
+ _1 = const _; // scope 0 at $DIR/structs.rs:+2:13: +2:14
++ _4 = move (_1.0: usize); // scope 1 at $DIR/structs.rs:+3:9: +3:10
++ _5 = move (_1.1: u8); // scope 1 at $DIR/structs.rs:+3:9: +3:10
+ StorageLive(_2); // scope 1 at $DIR/structs.rs:+3:9: +3:10
+- _2 = (_1.0: usize); // scope 1 at $DIR/structs.rs:+3:13: +3:16
++ _2 = _4; // scope 1 at $DIR/structs.rs:+3:13: +3:16
+ StorageLive(_3); // scope 2 at $DIR/structs.rs:+4:9: +4:10
+- _3 = (_1.1: u8); // scope 2 at $DIR/structs.rs:+4:13: +4:16
++ _3 = _5; // scope 2 at $DIR/structs.rs:+4:13: +4:16
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:15: +5:2
+ StorageDead(_3); // scope 2 at $DIR/structs.rs:+5:1: +5:2
+ StorageDead(_2); // scope 1 at $DIR/structs.rs:+5:1: +5:2
+- StorageDead(_1); // scope 0 at $DIR/structs.rs:+5:1: +5:2
++ StorageDead(_4); // scope 0 at $DIR/structs.rs:+5:1: +5:2
++ StorageDead(_5); // scope 0 at $DIR/structs.rs:+5:1: +5:2
++ nop; // scope 0 at $DIR/structs.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/structs.rs:+5:2: +5:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..b0b0da886
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,91 @@
+- // MIR for `copies` before ScalarReplacementOfAggregates
++ // MIR for `copies` after ScalarReplacementOfAggregates
+
+ fn copies(_1: Foo) -> () {
+ debug x => _1; // in scope 0 at $DIR/structs.rs:+0:11: +0:12
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+ let _2: Foo; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _11: u8; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _12: (); // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _13: &str; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _14: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
+ scope 1 {
+- debug y => _2; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
++ debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
+ let _3: u8; // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+ scope 2 {
+ debug t => _3; // in scope 2 at $DIR/structs.rs:+2:9: +2:10
+ let _4: &str; // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+ scope 3 {
+ debug u => _4; // in scope 3 at $DIR/structs.rs:+3:9: +3:10
+ let _5: Foo; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++ let _7: u8; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++ let _8: (); // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++ let _9: &str; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++ let _10: std::option::Option<isize>; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
+ scope 4 {
+- debug z => _5; // in scope 4 at $DIR/structs.rs:+4:9: +4:10
++ debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; // in scope 4 at $DIR/structs.rs:+4:9: +4:10
+ let _6: (); // in scope 4 at $DIR/structs.rs:+5:9: +5:10
+ scope 5 {
+ debug a => _6; // in scope 5 at $DIR/structs.rs:+5:9: +5:10
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+- StorageLive(_2); // scope 0 at $DIR/structs.rs:+1:9: +1:10
+- _2 = _1; // scope 0 at $DIR/structs.rs:+1:13: +1:14
++ StorageLive(_11); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_12); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_13); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_14); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ nop; // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ _11 = (_1.0: u8); // scope 0 at $DIR/structs.rs:+1:13: +1:14
++ _12 = (_1.1: ()); // scope 0 at $DIR/structs.rs:+1:13: +1:14
++ _13 = (_1.2: &str); // scope 0 at $DIR/structs.rs:+1:13: +1:14
++ _14 = (_1.3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:13: +1:14
++ nop; // scope 0 at $DIR/structs.rs:+1:13: +1:14
+ StorageLive(_3); // scope 1 at $DIR/structs.rs:+2:9: +2:10
+- _3 = (_2.0: u8); // scope 1 at $DIR/structs.rs:+2:13: +2:16
++ _3 = _11; // scope 1 at $DIR/structs.rs:+2:13: +2:16
+ StorageLive(_4); // scope 2 at $DIR/structs.rs:+3:9: +3:10
+- _4 = (_2.2: &str); // scope 2 at $DIR/structs.rs:+3:13: +3:16
+- StorageLive(_5); // scope 3 at $DIR/structs.rs:+4:9: +4:10
+- _5 = _2; // scope 3 at $DIR/structs.rs:+4:13: +4:14
++ _4 = _13; // scope 2 at $DIR/structs.rs:+3:13: +3:16
++ StorageLive(_7); // scope 3 at $DIR/structs.rs:+4:9: +4:10
++ StorageLive(_8); // scope 3 at $DIR/structs.rs:+4:9: +4:10
++ StorageLive(_9); // scope 3 at $DIR/structs.rs:+4:9: +4:10
++ StorageLive(_10); // scope 3 at $DIR/structs.rs:+4:9: +4:10
++ nop; // scope 3 at $DIR/structs.rs:+4:9: +4:10
++ _7 = _11; // scope 3 at $DIR/structs.rs:+4:13: +4:14
++ _8 = _12; // scope 3 at $DIR/structs.rs:+4:13: +4:14
++ _9 = _13; // scope 3 at $DIR/structs.rs:+4:13: +4:14
++ _10 = _14; // scope 3 at $DIR/structs.rs:+4:13: +4:14
++ nop; // scope 3 at $DIR/structs.rs:+4:13: +4:14
+ StorageLive(_6); // scope 4 at $DIR/structs.rs:+5:9: +5:10
+- _6 = (_5.1: ()); // scope 4 at $DIR/structs.rs:+5:13: +5:16
++ _6 = _8; // scope 4 at $DIR/structs.rs:+5:13: +5:16
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:19: +6:2
+ StorageDead(_6); // scope 4 at $DIR/structs.rs:+6:1: +6:2
+- StorageDead(_5); // scope 3 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_7); // scope 3 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_8); // scope 3 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_9); // scope 3 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_10); // scope 3 at $DIR/structs.rs:+6:1: +6:2
++ nop; // scope 3 at $DIR/structs.rs:+6:1: +6:2
+ StorageDead(_4); // scope 2 at $DIR/structs.rs:+6:1: +6:2
+ StorageDead(_3); // scope 1 at $DIR/structs.rs:+6:1: +6:2
+- StorageDead(_2); // scope 0 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_11); // scope 0 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_12); // scope 0 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_13); // scope 0 at $DIR/structs.rs:+6:1: +6:2
++ StorageDead(_14); // scope 0 at $DIR/structs.rs:+6:1: +6:2
++ nop; // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/structs.rs:+6:2: +6:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..d378c260a
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,44 @@
+- // MIR for `dropping` before ScalarReplacementOfAggregates
++ // MIR for `dropping` after ScalarReplacementOfAggregates
+
+ fn dropping() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+ let _1: Tag; // in scope 0 at $DIR/structs.rs:+1:5: +1:32
+ let mut _2: S; // in scope 0 at $DIR/structs.rs:+1:5: +1:30
+ let mut _3: Tag; // in scope 0 at $DIR/structs.rs:+1:7: +1:13
+ let mut _4: Tag; // in scope 0 at $DIR/structs.rs:+1:15: +1:21
+ let mut _5: Tag; // in scope 0 at $DIR/structs.rs:+1:23: +1:29
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/structs.rs:+1:5: +1:32
+ StorageLive(_2); // scope 0 at $DIR/structs.rs:+1:5: +1:30
+ StorageLive(_3); // scope 0 at $DIR/structs.rs:+1:7: +1:13
+ _3 = Tag(const 0_usize); // scope 0 at $DIR/structs.rs:+1:7: +1:13
+ StorageLive(_4); // scope 0 at $DIR/structs.rs:+1:15: +1:21
+ _4 = Tag(const 1_usize); // scope 0 at $DIR/structs.rs:+1:15: +1:21
+ StorageLive(_5); // scope 0 at $DIR/structs.rs:+1:23: +1:29
+ _5 = Tag(const 2_usize); // scope 0 at $DIR/structs.rs:+1:23: +1:29
+ _2 = S(move _3, move _4, move _5); // scope 0 at $DIR/structs.rs:+1:5: +1:30
+ StorageDead(_5); // scope 0 at $DIR/structs.rs:+1:29: +1:30
+ StorageDead(_4); // scope 0 at $DIR/structs.rs:+1:29: +1:30
+ StorageDead(_3); // scope 0 at $DIR/structs.rs:+1:29: +1:30
+ _1 = move (_2.1: Tag); // scope 0 at $DIR/structs.rs:+1:5: +1:32
+ drop(_1) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
+ }
+
+ bb1: {
+ drop((_2.0: Tag)) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
+ }
+
+ bb2: {
+ StorageDead(_2); // scope 0 at $DIR/structs.rs:+1:32: +1:33
+ StorageDead(_1); // scope 0 at $DIR/structs.rs:+1:32: +1:33
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:19: +2:2
+ return; // scope 0 at $DIR/structs.rs:+2:2: +2:2
+ }
+
+ bb3: {
+ drop((_2.2: Tag)) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..ff1e30c2d
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,43 @@
+- // MIR for `enums` before ScalarReplacementOfAggregates
++ // MIR for `enums` after ScalarReplacementOfAggregates
+
+ fn enums(_1: usize) -> usize {
+ debug a => _1; // in scope 0 at $DIR/structs.rs:+0:14: +0:15
+ let mut _0: usize; // return place in scope 0 at $DIR/structs.rs:+0:27: +0:32
+ let mut _2: std::option::Option<usize>; // in scope 0 at $DIR/structs.rs:+1:22: +1:29
+ let mut _3: usize; // in scope 0 at $DIR/structs.rs:+1:27: +1:28
+ let mut _4: isize; // in scope 0 at $DIR/structs.rs:+1:12: +1:19
+ scope 1 {
+ debug a => _5; // in scope 1 at $DIR/structs.rs:+1:17: +1:18
+ let _5: usize; // in scope 1 at $DIR/structs.rs:+1:17: +1:18
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 1 at $DIR/structs.rs:+1:22: +1:29
+ StorageLive(_3); // scope 1 at $DIR/structs.rs:+1:27: +1:28
+ _3 = _1; // scope 1 at $DIR/structs.rs:+1:27: +1:28
+ _2 = Option::<usize>::Some(move _3); // scope 1 at $DIR/structs.rs:+1:22: +1:29
+ StorageDead(_3); // scope 1 at $DIR/structs.rs:+1:28: +1:29
+ _4 = discriminant(_2); // scope 1 at $DIR/structs.rs:+1:12: +1:19
+ switchInt(move _4) -> [1: bb1, otherwise: bb2]; // scope 1 at $DIR/structs.rs:+1:12: +1:19
+ }
+
+ bb1: {
+ StorageLive(_5); // scope 1 at $DIR/structs.rs:+1:17: +1:18
+ _5 = ((_2 as Some).0: usize); // scope 1 at $DIR/structs.rs:+1:17: +1:18
+ _0 = _5; // scope 1 at $DIR/structs.rs:+1:32: +1:33
+ StorageDead(_5); // scope 0 at $DIR/structs.rs:+1:34: +1:35
+ goto -> bb3; // scope 0 at $DIR/structs.rs:+1:5: +1:46
+ }
+
+ bb2: {
+ _0 = const 0_usize; // scope 0 at $DIR/structs.rs:+1:43: +1:44
+ goto -> bb3; // scope 0 at $DIR/structs.rs:+1:5: +1:46
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/structs.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/structs.rs:+2:2: +2:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..3074fcbdf
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,44 @@
+- // MIR for `escaping` before ScalarReplacementOfAggregates
++ // MIR for `escaping` after ScalarReplacementOfAggregates
+
+ fn escaping() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+ let _1: (); // in scope 0 at $DIR/structs.rs:+1:5: +1:42
+ let mut _2: *const u32; // in scope 0 at $DIR/structs.rs:+1:7: +1:41
+ let _3: &u32; // in scope 0 at $DIR/structs.rs:+1:7: +1:41
+ let _4: Escaping; // in scope 0 at $DIR/structs.rs:+1:8: +1:39
+ let mut _5: u32; // in scope 0 at $DIR/structs.rs:+1:34: +1:37
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/structs.rs:+1:5: +1:42
+ StorageLive(_2); // scope 0 at $DIR/structs.rs:+1:7: +1:41
+ StorageLive(_3); // scope 0 at $DIR/structs.rs:+1:7: +1:41
+ StorageLive(_4); // scope 0 at $DIR/structs.rs:+1:8: +1:39
+ StorageLive(_5); // scope 0 at $DIR/structs.rs:+1:34: +1:37
+ _5 = g() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:34: +1:37
+ // mir::Constant
+ // + span: $DIR/structs.rs:78:34: 78:35
+ // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/structs.rs:+1:8: +1:39
+ StorageDead(_5); // scope 0 at $DIR/structs.rs:+1:38: +1:39
+ _3 = &(_4.0: u32); // scope 0 at $DIR/structs.rs:+1:7: +1:41
+ _2 = &raw const (*_3); // scope 0 at $DIR/structs.rs:+1:7: +1:41
+ _1 = f(move _2) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:5: +1:42
+ // mir::Constant
+ // + span: $DIR/structs.rs:78:5: 78:6
+ // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_2); // scope 0 at $DIR/structs.rs:+1:41: +1:42
+ StorageDead(_4); // scope 0 at $DIR/structs.rs:+1:42: +1:43
+ StorageDead(_3); // scope 0 at $DIR/structs.rs:+1:42: +1:43
+ StorageDead(_1); // scope 0 at $DIR/structs.rs:+1:42: +1:43
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:19: +2:2
+ return; // scope 0 at $DIR/structs.rs:+2:2: +2:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..1aa11d17b
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,80 @@
+- // MIR for `flat` before ScalarReplacementOfAggregates
++ // MIR for `flat` after ScalarReplacementOfAggregates
+
+ fn flat() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:15: +0:15
+ let _1: u8; // in scope 0 at $DIR/structs.rs:+1:15: +1:16
+ let _2: (); // in scope 0 at $DIR/structs.rs:+1:18: +1:19
+ let _3: &str; // in scope 0 at $DIR/structs.rs:+1:21: +1:22
+ let _4: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:24: +1:25
+ let mut _5: Foo; // in scope 0 at $DIR/structs.rs:+1:30: +1:70
+ let mut _6: (); // in scope 0 at $DIR/structs.rs:+1:45: +1:47
+ let mut _7: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:60: +1:68
++ let mut _8: u8; // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++ let mut _9: (); // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++ let mut _10: &str; // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++ let mut _11: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:30: +1:70
+ scope 1 {
+ debug a => _1; // in scope 1 at $DIR/structs.rs:+1:15: +1:16
+ debug b => _2; // in scope 1 at $DIR/structs.rs:+1:18: +1:19
+ debug c => _3; // in scope 1 at $DIR/structs.rs:+1:21: +1:22
+ debug d => _4; // in scope 1 at $DIR/structs.rs:+1:24: +1:25
+ scope 2 {
+ scope 3 {
+ scope 4 {
+ scope 5 {
+ }
+ }
+ }
+ }
+ }
+
+ bb0: {
+- StorageLive(_5); // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ StorageLive(_8); // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ StorageLive(_9); // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ StorageLive(_10); // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ StorageLive(_11); // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ nop; // scope 0 at $DIR/structs.rs:+1:30: +1:70
+ StorageLive(_6); // scope 0 at $DIR/structs.rs:+1:45: +1:47
+ _6 = (); // scope 0 at $DIR/structs.rs:+1:45: +1:47
+ StorageLive(_7); // scope 0 at $DIR/structs.rs:+1:60: +1:68
+ _7 = Option::<isize>::Some(const -4_isize); // scope 0 at $DIR/structs.rs:+1:60: +1:68
+- _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ _8 = const 5_u8; // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ _9 = move _6; // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ _10 = const "a"; // scope 0 at $DIR/structs.rs:+1:30: +1:70
+ // mir::Constant
+ // + span: $DIR/structs.rs:53:52: 53:55
+ // + literal: Const { ty: &str, val: Value(Slice(..)) }
++ _11 = move _7; // scope 0 at $DIR/structs.rs:+1:30: +1:70
++ nop; // scope 0 at $DIR/structs.rs:+1:30: +1:70
+ StorageDead(_7); // scope 0 at $DIR/structs.rs:+1:69: +1:70
+ StorageDead(_6); // scope 0 at $DIR/structs.rs:+1:69: +1:70
+ StorageLive(_1); // scope 0 at $DIR/structs.rs:+1:15: +1:16
+- _1 = (_5.0: u8); // scope 0 at $DIR/structs.rs:+1:15: +1:16
++ _1 = _8; // scope 0 at $DIR/structs.rs:+1:15: +1:16
+ StorageLive(_2); // scope 0 at $DIR/structs.rs:+1:18: +1:19
+- _2 = (_5.1: ()); // scope 0 at $DIR/structs.rs:+1:18: +1:19
++ _2 = _9; // scope 0 at $DIR/structs.rs:+1:18: +1:19
+ StorageLive(_3); // scope 0 at $DIR/structs.rs:+1:21: +1:22
+- _3 = (_5.2: &str); // scope 0 at $DIR/structs.rs:+1:21: +1:22
++ _3 = _10; // scope 0 at $DIR/structs.rs:+1:21: +1:22
+ StorageLive(_4); // scope 0 at $DIR/structs.rs:+1:24: +1:25
+- _4 = (_5.3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:24: +1:25
+- StorageDead(_5); // scope 0 at $DIR/structs.rs:+1:70: +1:71
++ _4 = _11; // scope 0 at $DIR/structs.rs:+1:24: +1:25
++ StorageDead(_8); // scope 0 at $DIR/structs.rs:+1:70: +1:71
++ StorageDead(_9); // scope 0 at $DIR/structs.rs:+1:70: +1:71
++ StorageDead(_10); // scope 0 at $DIR/structs.rs:+1:70: +1:71
++ StorageDead(_11); // scope 0 at $DIR/structs.rs:+1:70: +1:71
++ nop; // scope 0 at $DIR/structs.rs:+1:70: +1:71
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:15: +6:2
+ StorageDead(_4); // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ StorageDead(_3); // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ StorageDead(_2); // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ StorageDead(_1); // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/structs.rs:+6:2: +6:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..7b09ac182
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,56 @@
+- // MIR for `ref_copies` before ScalarReplacementOfAggregates
++ // MIR for `ref_copies` after ScalarReplacementOfAggregates
+
+ fn ref_copies(_1: &Foo) -> () {
+ debug x => _1; // in scope 0 at $DIR/structs.rs:+0:15: +0:16
+ let mut _0: (); // return place in scope 0 at $DIR/structs.rs:+0:24: +0:24
+ let _2: Foo; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _5: u8; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _6: (); // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _7: &str; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++ let _8: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
+ scope 1 {
+- debug y => _2; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
++ debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
+ let _3: u8; // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+ scope 2 {
+ debug t => _3; // in scope 2 at $DIR/structs.rs:+2:9: +2:10
+ let _4: &str; // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+ scope 3 {
+ debug u => _4; // in scope 3 at $DIR/structs.rs:+3:9: +3:10
+ }
+ }
+ }
+
+ bb0: {
+- StorageLive(_2); // scope 0 at $DIR/structs.rs:+1:9: +1:10
+- _2 = (*_1); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++ StorageLive(_5); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_6); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_7); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ StorageLive(_8); // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ nop; // scope 0 at $DIR/structs.rs:+1:9: +1:10
++ _5 = ((*_1).0: u8); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++ _6 = ((*_1).1: ()); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++ _7 = ((*_1).2: &str); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++ _8 = ((*_1).3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++ nop; // scope 0 at $DIR/structs.rs:+1:13: +1:15
+ StorageLive(_3); // scope 1 at $DIR/structs.rs:+2:9: +2:10
+- _3 = (_2.0: u8); // scope 1 at $DIR/structs.rs:+2:13: +2:16
++ _3 = _5; // scope 1 at $DIR/structs.rs:+2:13: +2:16
+ StorageLive(_4); // scope 2 at $DIR/structs.rs:+3:9: +3:10
+- _4 = (_2.2: &str); // scope 2 at $DIR/structs.rs:+3:13: +3:16
++ _4 = _7; // scope 2 at $DIR/structs.rs:+3:13: +3:16
+ _0 = const (); // scope 0 at $DIR/structs.rs:+0:24: +4:2
+ StorageDead(_4); // scope 2 at $DIR/structs.rs:+4:1: +4:2
+ StorageDead(_3); // scope 1 at $DIR/structs.rs:+4:1: +4:2
+- StorageDead(_2); // scope 0 at $DIR/structs.rs:+4:1: +4:2
++ StorageDead(_5); // scope 0 at $DIR/structs.rs:+4:1: +4:2
++ StorageDead(_6); // scope 0 at $DIR/structs.rs:+4:1: +4:2
++ StorageDead(_7); // scope 0 at $DIR/structs.rs:+4:1: +4:2
++ StorageDead(_8); // scope 0 at $DIR/structs.rs:+4:1: +4:2
++ nop; // scope 0 at $DIR/structs.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/structs.rs:+4:2: +4:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.rs b/tests/mir-opt/sroa/structs.rs
new file mode 100644
index 000000000..7946eeaea
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.rs
@@ -0,0 +1,122 @@
+// unit-test: ScalarReplacementOfAggregates
+// compile-flags: -Cpanic=abort
+// no-prefer-dynamic
+
+struct Tag(usize);
+
+#[repr(C)]
+struct S(Tag, Tag, Tag);
+
+impl Drop for Tag {
+ #[inline(never)]
+ fn drop(&mut self) {}
+}
+
+pub fn dropping() {
+ S(Tag(0), Tag(1), Tag(2)).1;
+}
+
+pub fn enums(a: usize) -> usize {
+ if let Some(a) = Some(a) { a } else { 0 }
+}
+
+pub fn structs(a: f32) -> f32 {
+ struct U {
+ _foo: usize,
+ a: f32,
+ }
+
+ U { _foo: 0, a }.a
+}
+
+pub fn unions(a: f32) -> u32 {
+ union Repr {
+ f: f32,
+ u: u32,
+ }
+ unsafe { Repr { f: a }.u }
+}
+
+#[derive(Copy, Clone)]
+struct Foo {
+ a: u8,
+ b: (),
+ c: &'static str,
+ d: Option<isize>,
+}
+
+fn g() -> u32 {
+ 3
+}
+
+pub fn flat() {
+ let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) };
+ let _ = a;
+ let _ = b;
+ let _ = c;
+ let _ = d;
+}
+
+#[repr(C)]
+struct Escaping {
+ a: u32,
+ b: u32,
+ c: u32,
+}
+
+fn f(a: *const u32) {
+ println!("{}", unsafe { *a.add(2) });
+}
+
+// `f` uses the `&e.a` to access `e.c`. This is UB according to Miri today; however,
+// T-opsem has not finalized that decision and as such rustc should not rely on
+// it. If SROA were to rely on it, it would be (almost) correct to turn `e` into
+// three distinct locals - one for each field - and pass a reference to only one
+// of them to `f`. However, this would lead to a miscompilation because `b` and `c`
+// might no longer appear right after `a` in memory.
+pub fn escaping() {
+ f(&Escaping { a: 1, b: 2, c: g() }.a);
+}
+
+fn copies(x: Foo) {
+ let y = x;
+ let t = y.a;
+ let u = y.c;
+ let z = y;
+ let a = z.b;
+}
+
+fn ref_copies(x: &Foo) {
+ let y = *x;
+ let t = y.a;
+ let u = y.c;
+}
+
+fn constant() {
+ const U: (usize, u8) = (5, 9);
+ let y = U;
+ let t = y.0;
+ let u = y.1;
+}
+
+fn main() {
+ dropping();
+ enums(5);
+ structs(5.);
+ unions(5.);
+ flat();
+ escaping();
+ copies(Foo { a: 5, b: (), c: "a", d: Some(-4) });
+ ref_copies(&Foo { a: 5, b: (), c: "a", d: Some(-4) });
+ constant();
+}
+
+// EMIT_MIR structs.dropping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.enums.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.structs.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.unions.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.flat.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.escaping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.copies.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.ref_copies.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.constant.ScalarReplacementOfAggregates.diff
diff --git a/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..c94e4b137
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,33 @@
+- // MIR for `structs` before ScalarReplacementOfAggregates
++ // MIR for `structs` after ScalarReplacementOfAggregates
+
+ fn structs(_1: f32) -> f32 {
+ debug a => _1; // in scope 0 at $DIR/structs.rs:+0:16: +0:17
+ let mut _0: f32; // return place in scope 0 at $DIR/structs.rs:+0:27: +0:30
+ let mut _2: structs::U; // in scope 0 at $DIR/structs.rs:+6:5: +6:21
+ let mut _3: f32; // in scope 0 at $DIR/structs.rs:+6:18: +6:19
++ let mut _4: usize; // in scope 0 at $DIR/structs.rs:+6:5: +6:21
++ let mut _5: f32; // in scope 0 at $DIR/structs.rs:+6:5: +6:21
+
+ bb0: {
+- StorageLive(_2); // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ StorageLive(_4); // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ StorageLive(_5); // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ nop; // scope 0 at $DIR/structs.rs:+6:5: +6:21
+ StorageLive(_3); // scope 0 at $DIR/structs.rs:+6:18: +6:19
+ _3 = _1; // scope 0 at $DIR/structs.rs:+6:18: +6:19
+- _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ _4 = const 0_usize; // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ _5 = move _3; // scope 0 at $DIR/structs.rs:+6:5: +6:21
++ nop; // scope 0 at $DIR/structs.rs:+6:5: +6:21
+ StorageDead(_3); // scope 0 at $DIR/structs.rs:+6:20: +6:21
+- _0 = (_2.1: f32); // scope 0 at $DIR/structs.rs:+6:5: +6:23
+- StorageDead(_2); // scope 0 at $DIR/structs.rs:+7:1: +7:2
++ _0 = _5; // scope 0 at $DIR/structs.rs:+6:5: +6:23
++ StorageDead(_4); // scope 0 at $DIR/structs.rs:+7:1: +7:2
++ StorageDead(_5); // scope 0 at $DIR/structs.rs:+7:1: +7:2
++ nop; // scope 0 at $DIR/structs.rs:+7:1: +7:2
+ return; // scope 0 at $DIR/structs.rs:+7:2: +7:2
+ }
+ }
+
diff --git a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
new file mode 100644
index 000000000..5aa054589
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,23 @@
+- // MIR for `unions` before ScalarReplacementOfAggregates
++ // MIR for `unions` after ScalarReplacementOfAggregates
+
+ fn unions(_1: f32) -> u32 {
+ debug a => _1; // in scope 0 at $DIR/structs.rs:+0:15: +0:16
+ let mut _0: u32; // return place in scope 0 at $DIR/structs.rs:+0:26: +0:29
+ let mut _2: unions::Repr; // in scope 0 at $DIR/structs.rs:+5:14: +5:27
+ let mut _3: f32; // in scope 0 at $DIR/structs.rs:+5:24: +5:25
+ scope 1 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 1 at $DIR/structs.rs:+5:14: +5:27
+ StorageLive(_3); // scope 1 at $DIR/structs.rs:+5:24: +5:25
+ _3 = _1; // scope 1 at $DIR/structs.rs:+5:24: +5:25
+ _2 = Repr { f: move _3 }; // scope 1 at $DIR/structs.rs:+5:14: +5:27
+ StorageDead(_3); // scope 1 at $DIR/structs.rs:+5:26: +5:27
+ _0 = (_2.1: u32); // scope 1 at $DIR/structs.rs:+5:14: +5:29
+ StorageDead(_2); // scope 0 at $DIR/structs.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/structs.rs:+6:2: +6:2
+ }
+ }
+