authorbors <bors@rust-lang.org> 2026-06-21 19:44:38 UTC
committerbors <bors@rust-lang.org> 2026-06-21 19:44:38 UTC
log91fe22da8084a1c9e993d78d4a56f22ab8396236
tree6e969d74dfb228098642d2fe316a5b1abe54691d
parentd29dae8d17abb191a24f57eb00f68ebc1b168314
parent0abc69593c1f9a0c52a18e2aca73d61f82b7b595

Auto merge of #157346 - dianqk:gvn-nest-ref, r=cjgillot

GVN: Don't assume nested shared references are read-only. Fixes https://github.com/rust-lang/rust/issues/155884. https://github.com/rust-lang/rust/pull/150485 only checks the type, whether it is a reference, which is not enough. The PR extends to other types. cc @RalfJung @saethlin r? @cjgillot

15 files changed, 796 insertions(+), 15 deletions(-)

compiler/rustc_mir_transform/src/gvn.rs+62-5
......@@ -116,7 +116,7 @@ use rustc_middle::mir::interpret::{AllocRange, GlobalAlloc};
116116use rustc_middle::mir::visit::*;
117117use rustc_middle::mir::*;
118118use rustc_middle::ty::layout::HasTypingEnv;
119use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized};
119use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
120120use rustc_mir_dataflow::{Analysis, ResultsCursor};
121121use rustc_span::DUMMY_SP;
122122use smallvec::SmallVec;
......@@ -834,16 +834,20 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
834834 {
835835 return Some((projection_ty, value));
836836 }
837 // DO NOT reason the pointer value.
838 // We cannot unify two pointers that dereference same local, because they may
839 // have different lifetimes.
837 // We cannot unify two references produced by dereferencing the same nested reference,
838 // because they may have different lifetimes.
840839 // ```
841840 // let b: &T = *a;
842841 // ... `a` is allowed to be modified. `c` and `b` have different borrowing lifetime.
843842 // Unifying them will extend the lifetime of `b`.
844843 // let c: &T = *a;
845844 // ```
846 if projection_ty.ty.is_ref() {
845 // Furthermore, unifying them can also violate Stacked Borrows or Tree Borrows.
846 // We can only unify all `*b` and `*c` separately
847 // because nested shared references are not read-only.
848 // For more, see <https://github.com/rust-lang/rust/issues/155884> and
849 // <https://github.com/rust-lang/rust/issues/130853>.
850 if self.ty_may_have_ref(projection_ty.ty) {
847851 return None;
848852 }
849853
......@@ -1688,6 +1692,59 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
16881692 }
16891693 }
16901694
1695 fn ty_may_have_ref(&self, ty: Ty<'tcx>) -> bool {
1696 fn ty_may_have_ref_inner<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
1697 if !tcx.recursion_limit().value_within_limit(depth) {
1698 return true;
1699 }
1700 let depth = depth + 1;
1701 match ty.kind() {
1702 ty::Int(_)
1703 | ty::Uint(_)
1704 | ty::Float(_)
1705 | ty::Bool
1706 | ty::Char
1707 | ty::Str
1708 | ty::Never
1709 | ty::FnDef(..)
1710 | ty::Error(_)
1711 | ty::FnPtr(..) => false,
1712 ty::Tuple(fields) => {
1713 fields.iter().any(|field| ty_may_have_ref_inner(tcx, field, depth))
1714 }
1715 ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => {
1716 ty_may_have_ref_inner(tcx, *ty, depth)
1717 }
1718 ty::Adt(adt_def, args) => {
1719 adt_def.has_param()
1720 || adt_def.has_aliases()
1721 || adt_def.all_fields().any(|field| {
1722 ty_may_have_ref_inner(
1723 tcx,
1724 field.ty(tcx, args).skip_normalization(),
1725 depth,
1726 )
1727 })
1728 }
1729 ty::Ref(..)
1730 | ty::RawPtr(_, _)
1731 | ty::Bound(..)
1732 | ty::Closure(..)
1733 | ty::CoroutineClosure(..)
1734 | ty::Dynamic(..)
1735 | ty::Foreign(_)
1736 | ty::Coroutine(..)
1737 | ty::CoroutineWitness(..)
1738 | ty::UnsafeBinder(_)
1739 | ty::Infer(_)
1740 | ty::Alias(..)
1741 | ty::Param(_)
1742 | ty::Placeholder(_) => true,
1743 }
1744 }
1745 ty_may_have_ref_inner(self.tcx, ty, 0)
1746 }
1747
16911748 /// Returns `false` if we're confident that the middle type doesn't have an
16921749 /// interesting niche so we can skip that step when transmuting.
16931750 ///
tests/mir-opt/const_prop/indirect_ref.indirect_adt.GVN.diff created+73
......@@ -0,0 +1,73 @@
1- // MIR for `indirect_adt` before GVN
2+ // MIR for `indirect_adt` after GVN
3
4 fn indirect_adt(_1: &Adt<'_>, _2: for<'a> fn(Adt<'a>), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: Adt<'_>;
10 let _5: ();
11 let mut _6: for<'a> fn(Adt<'a>);
12 let mut _7: Adt<'_>;
13 let _8: ();
14 let mut _9: fn();
15 let _11: ();
16 let mut _12: for<'a> fn(Adt<'a>);
17 let mut _13: Adt<'_>;
18 scope 1 {
19 debug y1 => _4;
20 let _10: Adt<'_>;
21 scope 2 {
22 debug y2 => _10;
23 }
24 }
25
26 bb0: {
27 StorageLive(_4);
28 _4 = copy (*_1);
29 StorageLive(_5);
30 StorageLive(_6);
31 _6 = copy _2;
32 StorageLive(_7);
33 _7 = copy _4;
34- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
35+ _5 = copy _2(copy _4) -> [return: bb1, unwind unreachable];
36 }
37
38 bb1: {
39 StorageDead(_7);
40 StorageDead(_6);
41 StorageDead(_5);
42 StorageLive(_8);
43 StorageLive(_9);
44 _9 = copy _3;
45- _8 = move _9() -> [return: bb2, unwind unreachable];
46+ _8 = copy _3() -> [return: bb2, unwind unreachable];
47 }
48
49 bb2: {
50 StorageDead(_9);
51 StorageDead(_8);
52 StorageLive(_10);
53 _10 = copy (*_1);
54 StorageLive(_11);
55 StorageLive(_12);
56 _12 = copy _2;
57 StorageLive(_13);
58 _13 = copy _10;
59- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
60+ _11 = copy _2(copy _10) -> [return: bb3, unwind unreachable];
61 }
62
63 bb3: {
64 StorageDead(_13);
65 StorageDead(_12);
66 StorageDead(_11);
67 _0 = const ();
68 StorageDead(_10);
69 StorageDead(_4);
70 return;
71 }
72 }
73
tests/mir-opt/const_prop/indirect_ref.indirect_deref_1.GVN.diff created+77
......@@ -0,0 +1,77 @@
1- // MIR for `indirect_deref_1` before GVN
2+ // MIR for `indirect_deref_1` after GVN
3
4 fn indirect_deref_1(_1: &(&i32,), _2: fn(i32), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: (&i32,);
10 let _5: ();
11 let mut _6: fn(i32);
12 let mut _7: i32;
13 let _8: ();
14 let mut _9: fn();
15 let _11: ();
16 let mut _12: fn(i32);
17 let mut _13: i32;
18 let mut _14: &i32;
19 let mut _15: &i32;
20 scope 1 {
21 debug y1 => _4;
22 let _10: (&i32,);
23 scope 2 {
24 debug y2 => _10;
25 }
26 }
27
28 bb0: {
29 StorageLive(_4);
30 _4 = copy (*_1);
31 StorageLive(_5);
32 StorageLive(_6);
33 _6 = copy _2;
34 StorageLive(_7);
35 _14 = no_retag copy (_4.0: &i32);
36 _7 = copy (*_14);
37- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
38+ _5 = copy _2(move _7) -> [return: bb1, unwind unreachable];
39 }
40
41 bb1: {
42 StorageDead(_7);
43 StorageDead(_6);
44 StorageDead(_5);
45 StorageLive(_8);
46 StorageLive(_9);
47 _9 = copy _3;
48- _8 = move _9() -> [return: bb2, unwind unreachable];
49+ _8 = copy _3() -> [return: bb2, unwind unreachable];
50 }
51
52 bb2: {
53 StorageDead(_9);
54 StorageDead(_8);
55 StorageLive(_10);
56 _10 = copy (*_1);
57 StorageLive(_11);
58 StorageLive(_12);
59 _12 = copy _2;
60 StorageLive(_13);
61 _15 = no_retag copy (_10.0: &i32);
62 _13 = copy (*_15);
63- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
64+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
65 }
66
67 bb3: {
68 StorageDead(_13);
69 StorageDead(_12);
70 StorageDead(_11);
71 _0 = const ();
72 StorageDead(_10);
73 StorageDead(_4);
74 return;
75 }
76 }
77
tests/mir-opt/const_prop/indirect_ref.indirect_deref_2.GVN.diff created+63
......@@ -0,0 +1,63 @@
1- // MIR for `indirect_deref_2` before GVN
2+ // MIR for `indirect_deref_2` after GVN
3
4 fn indirect_deref_2(_1: &(&i32,), _2: fn(i32), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: ();
10 let mut _5: fn(i32);
11 let mut _6: i32;
12 let _7: ();
13 let mut _8: fn();
14 let _9: ();
15 let mut _10: fn(i32);
16 let mut _11: i32;
17 let mut _12: &i32;
18 let mut _13: &i32;
19
20 bb0: {
21 StorageLive(_4);
22 StorageLive(_5);
23 _5 = copy _2;
24 StorageLive(_6);
25 _12 = no_retag copy ((*_1).0: &i32);
26 _6 = copy (*_12);
27- _4 = move _5(move _6) -> [return: bb1, unwind unreachable];
28+ _4 = copy _2(move _6) -> [return: bb1, unwind unreachable];
29 }
30
31 bb1: {
32 StorageDead(_6);
33 StorageDead(_5);
34 StorageDead(_4);
35 StorageLive(_7);
36 StorageLive(_8);
37 _8 = copy _3;
38- _7 = move _8() -> [return: bb2, unwind unreachable];
39+ _7 = copy _3() -> [return: bb2, unwind unreachable];
40 }
41
42 bb2: {
43 StorageDead(_8);
44 StorageDead(_7);
45 StorageLive(_9);
46 StorageLive(_10);
47 _10 = copy _2;
48 StorageLive(_11);
49 _13 = no_retag copy ((*_1).0: &i32);
50 _11 = copy (*_13);
51- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
52+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
53 }
54
55 bb3: {
56 StorageDead(_11);
57 StorageDead(_10);
58 StorageDead(_9);
59 _0 = const ();
60 return;
61 }
62 }
63
tests/mir-opt/const_prop/indirect_ref.indirect_ref_1.GVN.diff created+63
......@@ -0,0 +1,63 @@
1- // MIR for `indirect_ref_1` before GVN
2+ // MIR for `indirect_ref_1` after GVN
3
4 fn indirect_ref_1(_1: &(&i32,), _2: for<'a> fn(&'a i32), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: ();
10 let mut _5: for<'a> fn(&'a i32);
11 let mut _6: &i32;
12 let _7: ();
13 let mut _8: fn();
14 let _9: ();
15 let mut _10: for<'a> fn(&'a i32);
16 let mut _11: &i32;
17 let mut _12: &i32;
18 let mut _13: &i32;
19
20 bb0: {
21 StorageLive(_4);
22 StorageLive(_5);
23 _5 = copy _2;
24 StorageLive(_6);
25 _12 = no_retag copy ((*_1).0: &i32);
26 _6 = &(*_12);
27- _4 = move _5(move _6) -> [return: bb1, unwind unreachable];
28+ _4 = copy _2(move _6) -> [return: bb1, unwind unreachable];
29 }
30
31 bb1: {
32 StorageDead(_6);
33 StorageDead(_5);
34 StorageDead(_4);
35 StorageLive(_7);
36 StorageLive(_8);
37 _8 = copy _3;
38- _7 = move _8() -> [return: bb2, unwind unreachable];
39+ _7 = copy _3() -> [return: bb2, unwind unreachable];
40 }
41
42 bb2: {
43 StorageDead(_8);
44 StorageDead(_7);
45 StorageLive(_9);
46 StorageLive(_10);
47 _10 = copy _2;
48 StorageLive(_11);
49 _13 = no_retag copy ((*_1).0: &i32);
50 _11 = &(*_13);
51- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
52+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
53 }
54
55 bb3: {
56 StorageDead(_11);
57 StorageDead(_10);
58 StorageDead(_9);
59 _0 = const ();
60 return;
61 }
62 }
63
tests/mir-opt/const_prop/indirect_ref.indirect_ref_2.GVN.diff created+77
......@@ -0,0 +1,77 @@
1- // MIR for `indirect_ref_2` before GVN
2+ // MIR for `indirect_ref_2` after GVN
3
4 fn indirect_ref_2(_1: &(&i32,), _2: for<'a> fn(&'a i32), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: (&i32,);
10 let _5: ();
11 let mut _6: for<'a> fn(&'a i32);
12 let mut _7: &i32;
13 let _8: ();
14 let mut _9: fn();
15 let _11: ();
16 let mut _12: for<'a> fn(&'a i32);
17 let mut _13: &i32;
18 let mut _14: &i32;
19 let mut _15: &i32;
20 scope 1 {
21 debug y1 => _4;
22 let _10: (&i32,);
23 scope 2 {
24 debug y2 => _10;
25 }
26 }
27
28 bb0: {
29 StorageLive(_4);
30 _4 = copy (*_1);
31 StorageLive(_5);
32 StorageLive(_6);
33 _6 = copy _2;
34 StorageLive(_7);
35 _14 = no_retag copy (_4.0: &i32);
36 _7 = &(*_14);
37- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
38+ _5 = copy _2(move _7) -> [return: bb1, unwind unreachable];
39 }
40
41 bb1: {
42 StorageDead(_7);
43 StorageDead(_6);
44 StorageDead(_5);
45 StorageLive(_8);
46 StorageLive(_9);
47 _9 = copy _3;
48- _8 = move _9() -> [return: bb2, unwind unreachable];
49+ _8 = copy _3() -> [return: bb2, unwind unreachable];
50 }
51
52 bb2: {
53 StorageDead(_9);
54 StorageDead(_8);
55 StorageLive(_10);
56 _10 = copy (*_1);
57 StorageLive(_11);
58 StorageLive(_12);
59 _12 = copy _2;
60 StorageLive(_13);
61 _15 = no_retag copy (_10.0: &i32);
62 _13 = &(*_15);
63- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
64+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
65 }
66
67 bb3: {
68 StorageDead(_13);
69 StorageDead(_12);
70 StorageDead(_11);
71 _0 = const ();
72 StorageDead(_10);
73 StorageDead(_4);
74 return;
75 }
76 }
77
tests/mir-opt/const_prop/indirect_ref.indirect_ref_t_1.GVN.diff created+59
......@@ -0,0 +1,59 @@
1- // MIR for `indirect_ref_t_1` before GVN
2+ // MIR for `indirect_ref_t_1` after GVN
3
4 fn indirect_ref_t_1(_1: &(T,), _2: fn(T), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: ();
10 let mut _5: fn(T);
11 let mut _6: T;
12 let _7: ();
13 let mut _8: fn();
14 let _9: ();
15 let mut _10: fn(T);
16 let mut _11: T;
17
18 bb0: {
19 StorageLive(_4);
20 StorageLive(_5);
21 _5 = copy _2;
22 StorageLive(_6);
23 _6 = copy ((*_1).0: T);
24- _4 = move _5(move _6) -> [return: bb1, unwind unreachable];
25+ _4 = copy _2(move _6) -> [return: bb1, unwind unreachable];
26 }
27
28 bb1: {
29 StorageDead(_6);
30 StorageDead(_5);
31 StorageDead(_4);
32 StorageLive(_7);
33 StorageLive(_8);
34 _8 = copy _3;
35- _7 = move _8() -> [return: bb2, unwind unreachable];
36+ _7 = copy _3() -> [return: bb2, unwind unreachable];
37 }
38
39 bb2: {
40 StorageDead(_8);
41 StorageDead(_7);
42 StorageLive(_9);
43 StorageLive(_10);
44 _10 = copy _2;
45 StorageLive(_11);
46 _11 = copy ((*_1).0: T);
47- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
48+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
49 }
50
51 bb3: {
52 StorageDead(_11);
53 StorageDead(_10);
54 StorageDead(_9);
55 _0 = const ();
56 return;
57 }
58 }
59
tests/mir-opt/const_prop/indirect_ref.indirect_ref_t_2.GVN.diff created+73
......@@ -0,0 +1,73 @@
1- // MIR for `indirect_ref_t_2` before GVN
2+ // MIR for `indirect_ref_t_2` after GVN
3
4 fn indirect_ref_t_2(_1: &(T,), _2: fn(T), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: (T,);
10 let _5: ();
11 let mut _6: fn(T);
12 let mut _7: T;
13 let _8: ();
14 let mut _9: fn();
15 let _11: ();
16 let mut _12: fn(T);
17 let mut _13: T;
18 scope 1 {
19 debug y1 => _4;
20 let _10: (T,);
21 scope 2 {
22 debug y2 => _10;
23 }
24 }
25
26 bb0: {
27 StorageLive(_4);
28 _4 = copy (*_1);
29 StorageLive(_5);
30 StorageLive(_6);
31 _6 = copy _2;
32 StorageLive(_7);
33 _7 = copy (_4.0: T);
34- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
35+ _5 = copy _2(move _7) -> [return: bb1, unwind unreachable];
36 }
37
38 bb1: {
39 StorageDead(_7);
40 StorageDead(_6);
41 StorageDead(_5);
42 StorageLive(_8);
43 StorageLive(_9);
44 _9 = copy _3;
45- _8 = move _9() -> [return: bb2, unwind unreachable];
46+ _8 = copy _3() -> [return: bb2, unwind unreachable];
47 }
48
49 bb2: {
50 StorageDead(_9);
51 StorageDead(_8);
52 StorageLive(_10);
53 _10 = copy (*_1);
54 StorageLive(_11);
55 StorageLive(_12);
56 _12 = copy _2;
57 StorageLive(_13);
58 _13 = copy (_10.0: T);
59- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
60+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
61 }
62
63 bb3: {
64 StorageDead(_13);
65 StorageDead(_12);
66 StorageDead(_11);
67 _0 = const ();
68 StorageDead(_10);
69 StorageDead(_4);
70 return;
71 }
72 }
73
tests/mir-opt/const_prop/indirect_ref.indirect_union.GVN.diff created+73
......@@ -0,0 +1,73 @@
1- // MIR for `indirect_union` before GVN
2+ // MIR for `indirect_union` after GVN
3
4 fn indirect_union(_1: &U<'_>, _2: for<'a> fn(U<'a>), _3: fn()) -> () {
5 debug x => _1;
6 debug out => _2;
7 debug clobber => _3;
8 let mut _0: ();
9 let _4: U<'_>;
10 let _5: ();
11 let mut _6: for<'a> fn(U<'a>);
12 let mut _7: U<'_>;
13 let _8: ();
14 let mut _9: fn();
15 let _11: ();
16 let mut _12: for<'a> fn(U<'a>);
17 let mut _13: U<'_>;
18 scope 1 {
19 debug y1 => _4;
20 let _10: U<'_>;
21 scope 2 {
22 debug y2 => _10;
23 }
24 }
25
26 bb0: {
27 StorageLive(_4);
28 _4 = copy (*_1);
29 StorageLive(_5);
30 StorageLive(_6);
31 _6 = copy _2;
32 StorageLive(_7);
33 _7 = copy _4;
34- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
35+ _5 = copy _2(copy _4) -> [return: bb1, unwind unreachable];
36 }
37
38 bb1: {
39 StorageDead(_7);
40 StorageDead(_6);
41 StorageDead(_5);
42 StorageLive(_8);
43 StorageLive(_9);
44 _9 = copy _3;
45- _8 = move _9() -> [return: bb2, unwind unreachable];
46+ _8 = copy _3() -> [return: bb2, unwind unreachable];
47 }
48
49 bb2: {
50 StorageDead(_9);
51 StorageDead(_8);
52 StorageLive(_10);
53 _10 = copy (*_1);
54 StorageLive(_11);
55 StorageLive(_12);
56 _12 = copy _2;
57 StorageLive(_13);
58 _13 = copy _10;
59- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
60+ _11 = copy _2(copy _10) -> [return: bb3, unwind unreachable];
61 }
62
63 bb3: {
64 StorageDead(_13);
65 StorageDead(_12);
66 StorageDead(_11);
67 _0 = const ();
68 StorageDead(_10);
69 StorageDead(_4);
70 return;
71 }
72 }
73
tests/mir-opt/const_prop/indirect_ref.rs created+170
......@@ -0,0 +1,170 @@
1//! Regression test for <https://github.com/rust-lang/rust/issues/155884>.
2//! Nested shared references may be NOT read-only.
3//@ test-mir-pass: GVN
4//@ compile-flags: -C panic=abort
5
6#![feature(freeze)]
7
8use std::marker::Freeze;
9
10#[derive(Clone, Copy)]
11pub union U<'a> {
12 pub i: i32,
13 pub f: &'a i32,
14}
15
16// EMIT_MIR indirect_ref.indirect_union.GVN.diff
17#[inline(never)]
18pub fn indirect_union(x: &U<'_>, out: fn(U<'_>), clobber: fn()) {
19 // CHECK-LABEL: fn indirect_union
20 // CHECK: out => [[out:_.*]];
21 // CHECK: [[y1:_.*]] = copy (*_1);
22 // CHECK: copy [[out]](copy [[y1]]) -> [
23 // CHECK: [[y2:_.*]] = copy (*_1);
24 // CHECK: copy [[out]](copy [[y2]]) -> [
25 let y1 = *x;
26 out(y1);
27 clobber();
28 let y2 = *x;
29 out(y2);
30}
31
32// EMIT_MIR indirect_ref.indirect_deref_1.GVN.diff
33#[inline(never)]
34pub fn indirect_deref_1(x: &(&i32,), out: fn(i32), clobber: fn()) {
35 // CHECK-LABEL: fn indirect_deref_1
36 // CHECK: out => [[out:_.*]];
37 // CHECK: [[y1:_.*]] = copy (*_1);
38 // CHECK: [[y1_0:_.*]] = no_retag copy ([[y1]].0: &i32);
39 // CHECK: [[deref_y1_0:_.*]] = copy (*[[y1_0]]);
40 // CHECK: copy [[out]](move [[deref_y1_0]]) -> [
41 // CHECK: [[y2:_.*]] = copy (*_1);
42 // CHECK: [[y2_0:_.*]] = no_retag copy ([[y2]].0: &i32);
43 // CHECK: [[deref_y2_0:_.*]] = copy (*[[y2_0]]);
44 // CHECK: copy [[out]](move [[deref_y2_0]]) -> [
45 let y1 = *x;
46 out(*(y1).0);
47 clobber();
48 let y2 = *x;
49 out(*(y2).0);
50}
51
52// EMIT_MIR indirect_ref.indirect_deref_2.GVN.diff
53#[inline(never)]
54pub fn indirect_deref_2(x: &(&i32,), out: fn(i32), clobber: fn()) {
55 // CHECK-LABEL: fn indirect_deref_2
56 // CHECK: out => [[out:_.*]];
57 // CHECK: [[y1_0:_.*]] = no_retag copy ((*_1).0: &i32);
58 // CHECK: [[deref_y1_0:_.*]] = copy (*[[y1_0]]);
59 // CHECK: copy [[out]](move [[deref_y1_0]]) -> [
60 // CHECK: [[y2_0:_.*]] = no_retag copy ((*_1).0: &i32);
61 // CHECK: [[deref_y2_0:_.*]] = copy (*[[y2_0]]);
62 // CHECK: copy [[out]](move [[deref_y2_0]]) -> [
63 out(*(*x).0);
64 clobber();
65 out(*(*x).0);
66}
67
68// EMIT_MIR indirect_ref.indirect_ref_1.GVN.diff
69#[inline(never)]
70pub fn indirect_ref_1(x: &(&i32,), out: fn(&i32), clobber: fn()) {
71 // CHECK-LABEL: fn indirect_ref_1
72 // CHECK: out => [[out:_.*]];
73 // CHECK: [[y1_0:_.*]] = no_retag copy ((*_1).0: &i32);
74 // CHECK: [[reborrow_y1_0:_.*]] = &(*[[y1_0]]);
75 // CHECK: copy [[out]](move [[reborrow_y1_0]]) -> [
76 // CHECK: [[y2_0:_.*]] = no_retag copy ((*_1).0: &i32);
77 // CHECK: [[reborrow_y2_0:_.*]] = &(*[[y2_0]]);
78 // CHECK: copy [[out]](move [[reborrow_y2_0]]) -> [
79 out((*x).0);
80 clobber();
81 out((*x).0);
82}
83
84// EMIT_MIR indirect_ref.indirect_ref_2.GVN.diff
85#[inline(never)]
86pub fn indirect_ref_2(x: &(&i32,), out: fn(&i32), clobber: fn()) {
87 // CHECK-LABEL: fn indirect_ref_2
88 // CHECK: out => [[out:_.*]];
89 // CHECK: [[y1:_.*]] = copy (*_1);
90 // CHECK: [[y1_0:_.*]] = no_retag copy ([[y1]].0: &i32);
91 // CHECK: [[reborrow_y1_0:_.*]] = &(*[[y1_0]]);
92 // CHECK: copy [[out]](move [[reborrow_y1_0]]) -> [
93 // CHECK: [[y2:_.*]] = copy (*_1);
94 // CHECK: [[y2_0:_.*]] = no_retag copy ([[y2]].0: &i32);
95 // CHECK: [[reborrow_y2_0:_.*]] = &(*[[y2_0]]);
96 // CHECK: copy [[out]](move [[reborrow_y2_0]]) -> [
97 let y1 = *x;
98 out((y1).0);
99 clobber();
100 let y2 = *x;
101 out((y2).0);
102}
103
104// EMIT_MIR indirect_ref.indirect_ref_t_1.GVN.diff
105#[inline(never)]
106pub fn indirect_ref_t_1<T: Copy + Freeze>(x: &(T,), out: fn(T), clobber: fn()) {
107 // CHECK-LABEL: fn indirect_ref_t_1
108 // CHECK: out => [[out:_.*]];
109 // CHECK: [[y1_0:_.*]] = copy ((*_1).0: T);
110 // CHECK: copy [[out]](move [[y1_0]]) -> [
111 // CHECK: [[y2_0:_.*]] = copy ((*_1).0: T);
112 // CHECK: copy [[out]](move [[y2_0]]) -> [
113 out((*x).0);
114 clobber();
115 out((*x).0);
116}
117
118// EMIT_MIR indirect_ref.indirect_ref_t_2.GVN.diff
119#[inline(never)]
120pub fn indirect_ref_t_2<T: Copy + Freeze>(x: &(T,), out: fn(T), clobber: fn()) {
121 // CHECK-LABEL: fn indirect_ref_t_2
122 // CHECK: out => [[out:_.*]];
123 // CHECK: [[y1:_.*]] = copy (*_1);
124 // CHECK: [[y1_0:_.*]] = copy ([[y1]].0: T);
125 // CHECK: copy [[out]](move [[y1_0]]) -> [
126 // CHECK: [[y2:_.*]] = copy (*_1);
127 // CHECK: [[y2_0:_.*]] = copy ([[y2]].0: T);
128 // CHECK: copy [[out]](move [[y2_0]]) -> [
129 let y1 = *x;
130 out((y1).0);
131 clobber();
132 let y2 = *x;
133 out((y2).0);
134}
135
136#[derive(Clone, Copy)]
137pub struct Adt<'a>(pub &'a i32);
138
139// EMIT_MIR indirect_ref.indirect_adt.GVN.diff
140#[inline(never)]
141pub fn indirect_adt(x: &Adt<'_>, out: fn(Adt), clobber: fn()) {
142 // CHECK-LABEL: fn indirect_adt
143 // CHECK: out => [[out:_.*]];
144 // CHECK: [[y1:_.*]] = copy (*_1);
145 // CHECK: copy [[out]](copy [[y1]]) -> [
146 // CHECK: [[y2:_.*]] = copy (*_1);
147 // CHECK: copy [[out]](copy [[y2]]) -> [
148 let y1 = *x;
149 out(y1);
150 clobber();
151 let y2 = *x;
152 out(y2);
153}
154
155static mut DATA: i32 = 0;
156
157fn main() {
158 let ptr = &raw mut DATA;
159 let nested_shr: &(&i32,) = unsafe { &*(&raw const ptr as *const (&i32,)) };
160 let u = U { f: nested_shr.0 };
161 indirect_union(&u, |x| assert_eq!(unsafe { *x.f }, unsafe { DATA }), || unsafe { DATA += 1 });
162 indirect_deref_1(nested_shr, |x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
163 indirect_deref_2(nested_shr, |x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
164 indirect_ref_1(nested_shr, |&x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
165 indirect_ref_2(nested_shr, |&x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
166 indirect_ref_t_1(nested_shr, |&x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
167 indirect_ref_t_2(nested_shr, |&x| assert_eq!(x, unsafe { DATA }), || unsafe { DATA += 1 });
168 let adt = Adt(nested_shr.0);
169 indirect_adt(&adt, |x| assert_eq!(*x.0, unsafe { DATA }), || unsafe { DATA += 1 });
170}
tests/mir-opt/gvn.field_borrow.GVN.panic-abort.diff+1-2
......@@ -17,8 +17,7 @@
1717 StorageLive(_2);
1818 _2 = copy ((*_1).0: &u8);
1919 StorageLive(_3);
20- _3 = copy ((*_1).0: &u8);
21+ _3 = copy _2;
20 _3 = copy ((*_1).0: &u8);
2221 _0 = const ();
2322 StorageDead(_3);
2423 StorageDead(_2);
tests/mir-opt/gvn.field_borrow.GVN.panic-unwind.diff+1-2
......@@ -17,8 +17,7 @@
1717 StorageLive(_2);
1818 _2 = copy ((*_1).0: &u8);
1919 StorageLive(_3);
20- _3 = copy ((*_1).0: &u8);
21+ _3 = copy _2;
20 _3 = copy ((*_1).0: &u8);
2221 _0 = const ();
2322 StorageDead(_3);
2423 StorageDead(_2);
tests/mir-opt/gvn.field_borrow_2.GVN.panic-abort.diff+1-2
......@@ -35,8 +35,7 @@
3535 StorageLive(_5);
3636 _5 = copy ((*_4).0: &u8);
3737 StorageLive(_6);
38- _6 = copy ((*_4).0: &u8);
39+ _6 = copy _5;
38 _6 = copy ((*_4).0: &u8);
4039 _0 = const ();
4140 StorageDead(_6);
4241 StorageDead(_5);
tests/mir-opt/gvn.field_borrow_2.GVN.panic-unwind.diff+1-2
......@@ -35,8 +35,7 @@
3535 StorageLive(_5);
3636 _5 = copy ((*_4).0: &u8);
3737 StorageLive(_6);
38- _6 = copy ((*_4).0: &u8);
39+ _6 = copy _5;
38 _6 = copy ((*_4).0: &u8);
4039 _0 = const ();
4140 StorageDead(_6);
4241 StorageDead(_5);
tests/mir-opt/gvn.rs+2-2
......@@ -1125,7 +1125,7 @@ fn field_borrow(a: &FieldBorrow<'_>) {
11251125 // CHECK: debug b => [[b:_.*]];
11261126 // CHECK: debug c => [[c:_.*]];
11271127 // CHECK: [[b]] = copy ((*_1).0: &u8);
1128 // CHECK: [[c]] = copy [[b]];
1128 // CHECK: [[c]] = copy ((*_1).0: &u8);
11291129 let b = a.0;
11301130 let c = a.0;
11311131}
......@@ -1142,7 +1142,7 @@ fn field_borrow_2(a: &&FieldBorrow<'_>) {
11421142 // CHECK: [[c]] = copy ((*[[b]]).0: &u8);
11431143 // CHECK: [[d]] = copy (*_1);
11441144 // CHECK: [[e]] = copy ((*[[d]]).0: &u8);
1145 // CHECK: [[f]] = copy [[e]];
1145 // CHECK: [[f]] = copy ((*[[d]]).0: &u8);
11461146 let b = *a;
11471147 let c = b.0;
11481148 let d = *a;