Skip to content

Commit 0abc695

Browse files
committed
GVN: Don't assume nested shared references are read-only.
1 parent 7e286d0 commit 0abc695

15 files changed

Lines changed: 167 additions & 76 deletions

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ use rustc_middle::mir::interpret::{AllocRange, GlobalAlloc};
116116
use rustc_middle::mir::visit::*;
117117
use rustc_middle::mir::*;
118118
use rustc_middle::ty::layout::HasTypingEnv;
119-
use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized};
119+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
120120
use rustc_mir_dataflow::{Analysis, ResultsCursor};
121121
use rustc_span::DUMMY_SP;
122122
use 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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,14 @@
5050
StorageDead(_9);
5151
StorageDead(_8);
5252
StorageLive(_10);
53-
- _10 = copy (*_1);
54-
+ _10 = copy _4;
53+
_10 = copy (*_1);
5554
StorageLive(_11);
5655
StorageLive(_12);
5756
_12 = copy _2;
5857
StorageLive(_13);
59-
- _13 = copy _10;
58+
_13 = copy _10;
6059
- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
61-
+ _13 = copy _4;
62-
+ _11 = copy _2(copy _4) -> [return: bb3, unwind unreachable];
60+
+ _11 = copy _2(copy _10) -> [return: bb3, unwind unreachable];
6361
}
6462

6563
bb3: {

tests/mir-opt/const_prop/indirect_ref.indirect_deref_1.GVN.diff

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,15 @@
3131
StorageLive(_5);
3232
StorageLive(_6);
3333
_6 = copy _2;
34-
- StorageLive(_7);
35-
+ nop;
34+
StorageLive(_7);
3635
_14 = no_retag copy (_4.0: &i32);
3736
_7 = copy (*_14);
3837
- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
39-
+ _5 = copy _2(copy _7) -> [return: bb1, unwind unreachable];
38+
+ _5 = copy _2(move _7) -> [return: bb1, unwind unreachable];
4039
}
4140

4241
bb1: {
43-
- StorageDead(_7);
44-
+ nop;
42+
StorageDead(_7);
4543
StorageDead(_6);
4644
StorageDead(_5);
4745
StorageLive(_8);
@@ -55,18 +53,15 @@
5553
StorageDead(_9);
5654
StorageDead(_8);
5755
StorageLive(_10);
58-
- _10 = copy (*_1);
59-
+ _10 = copy _4;
56+
_10 = copy (*_1);
6057
StorageLive(_11);
6158
StorageLive(_12);
6259
_12 = copy _2;
6360
StorageLive(_13);
64-
- _15 = no_retag copy (_10.0: &i32);
65-
- _13 = copy (*_15);
61+
_15 = no_retag copy (_10.0: &i32);
62+
_13 = copy (*_15);
6663
- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
67-
+ _15 = no_retag copy _14;
68-
+ _13 = copy _7;
69-
+ _11 = copy _2(copy _7) -> [return: bb3, unwind unreachable];
64+
+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
7065
}
7166

7267
bb3: {

tests/mir-opt/const_prop/indirect_ref.indirect_deref_2.GVN.diff

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,15 @@
2121
StorageLive(_4);
2222
StorageLive(_5);
2323
_5 = copy _2;
24-
- StorageLive(_6);
25-
+ nop;
24+
StorageLive(_6);
2625
_12 = no_retag copy ((*_1).0: &i32);
2726
_6 = copy (*_12);
2827
- _4 = move _5(move _6) -> [return: bb1, unwind unreachable];
29-
+ _4 = copy _2(copy _6) -> [return: bb1, unwind unreachable];
28+
+ _4 = copy _2(move _6) -> [return: bb1, unwind unreachable];
3029
}
3130

3231
bb1: {
33-
- StorageDead(_6);
34-
+ nop;
32+
StorageDead(_6);
3533
StorageDead(_5);
3634
StorageDead(_4);
3735
StorageLive(_7);
@@ -48,12 +46,10 @@
4846
StorageLive(_10);
4947
_10 = copy _2;
5048
StorageLive(_11);
51-
- _13 = no_retag copy ((*_1).0: &i32);
52-
- _11 = copy (*_13);
49+
_13 = no_retag copy ((*_1).0: &i32);
50+
_11 = copy (*_13);
5351
- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
54-
+ _13 = no_retag copy _12;
55-
+ _11 = copy _6;
56-
+ _9 = copy _2(copy _6) -> [return: bb3, unwind unreachable];
52+
+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
5753
}
5854

5955
bb3: {

tests/mir-opt/const_prop/indirect_ref.indirect_ref_1.GVN.diff

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,9 @@
4646
StorageLive(_10);
4747
_10 = copy _2;
4848
StorageLive(_11);
49-
- _13 = no_retag copy ((*_1).0: &i32);
50-
- _11 = &(*_13);
49+
_13 = no_retag copy ((*_1).0: &i32);
50+
_11 = &(*_13);
5151
- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
52-
+ _13 = no_retag copy _12;
53-
+ _11 = &(*_12);
5452
+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
5553
}
5654

tests/mir-opt/const_prop/indirect_ref.indirect_ref_2.GVN.diff

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,14 @@
5353
StorageDead(_9);
5454
StorageDead(_8);
5555
StorageLive(_10);
56-
- _10 = copy (*_1);
57-
+ _10 = copy _4;
56+
_10 = copy (*_1);
5857
StorageLive(_11);
5958
StorageLive(_12);
6059
_12 = copy _2;
6160
StorageLive(_13);
62-
- _15 = no_retag copy (_10.0: &i32);
63-
- _13 = &(*_15);
61+
_15 = no_retag copy (_10.0: &i32);
62+
_13 = &(*_15);
6463
- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
65-
+ _15 = no_retag copy _14;
66-
+ _13 = &(*_14);
6764
+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
6865
}
6966

tests/mir-opt/const_prop/indirect_ref.indirect_ref_t_1.GVN.diff

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
StorageLive(_4);
2020
StorageLive(_5);
2121
_5 = copy _2;
22-
- StorageLive(_6);
23-
+ nop;
22+
StorageLive(_6);
2423
_6 = copy ((*_1).0: T);
2524
- _4 = move _5(move _6) -> [return: bb1, unwind unreachable];
26-
+ _4 = copy _2(copy _6) -> [return: bb1, unwind unreachable];
25+
+ _4 = copy _2(move _6) -> [return: bb1, unwind unreachable];
2726
}
2827

2928
bb1: {
30-
- StorageDead(_6);
31-
+ nop;
29+
StorageDead(_6);
3230
StorageDead(_5);
3331
StorageDead(_4);
3432
StorageLive(_7);
@@ -45,10 +43,9 @@
4543
StorageLive(_10);
4644
_10 = copy _2;
4745
StorageLive(_11);
48-
- _11 = copy ((*_1).0: T);
46+
_11 = copy ((*_1).0: T);
4947
- _9 = move _10(move _11) -> [return: bb3, unwind unreachable];
50-
+ _11 = copy _6;
51-
+ _9 = copy _2(copy _6) -> [return: bb3, unwind unreachable];
48+
+ _9 = copy _2(move _11) -> [return: bb3, unwind unreachable];
5249
}
5350

5451
bb3: {

tests/mir-opt/const_prop/indirect_ref.indirect_ref_t_2.GVN.diff

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,14 @@
2929
StorageLive(_5);
3030
StorageLive(_6);
3131
_6 = copy _2;
32-
- StorageLive(_7);
33-
+ nop;
32+
StorageLive(_7);
3433
_7 = copy (_4.0: T);
3534
- _5 = move _6(move _7) -> [return: bb1, unwind unreachable];
36-
+ _5 = copy _2(copy _7) -> [return: bb1, unwind unreachable];
35+
+ _5 = copy _2(move _7) -> [return: bb1, unwind unreachable];
3736
}
3837

3938
bb1: {
40-
- StorageDead(_7);
41-
+ nop;
39+
StorageDead(_7);
4240
StorageDead(_6);
4341
StorageDead(_5);
4442
StorageLive(_8);
@@ -52,16 +50,14 @@
5250
StorageDead(_9);
5351
StorageDead(_8);
5452
StorageLive(_10);
55-
- _10 = copy (*_1);
56-
+ _10 = copy _4;
53+
_10 = copy (*_1);
5754
StorageLive(_11);
5855
StorageLive(_12);
5956
_12 = copy _2;
6057
StorageLive(_13);
61-
- _13 = copy (_10.0: T);
58+
_13 = copy (_10.0: T);
6259
- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
63-
+ _13 = copy _7;
64-
+ _11 = copy _2(copy _7) -> [return: bb3, unwind unreachable];
60+
+ _11 = copy _2(move _13) -> [return: bb3, unwind unreachable];
6561
}
6662

6763
bb3: {

tests/mir-opt/const_prop/indirect_ref.indirect_union.GVN.diff

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,14 @@
5050
StorageDead(_9);
5151
StorageDead(_8);
5252
StorageLive(_10);
53-
- _10 = copy (*_1);
54-
+ _10 = copy _4;
53+
_10 = copy (*_1);
5554
StorageLive(_11);
5655
StorageLive(_12);
5756
_12 = copy _2;
5857
StorageLive(_13);
59-
- _13 = copy _10;
58+
_13 = copy _10;
6059
- _11 = move _12(move _13) -> [return: bb3, unwind unreachable];
61-
+ _13 = copy _4;
62-
+ _11 = copy _2(copy _4) -> [return: bb3, unwind unreachable];
60+
+ _11 = copy _2(copy _10) -> [return: bb3, unwind unreachable];
6361
}
6462

6563
bb3: {

0 commit comments

Comments
 (0)