Skip to content

Commit 3c0f3b0

Browse files
committed
Only assume Stacked Borrows if -Zunsound-mir-opts is given
1 parent 111324e commit 3c0f3b0

File tree

7 files changed

+137
-86
lines changed

7 files changed

+137
-86
lines changed

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,15 @@ impl PlaceContext {
13201320
)
13211321
}
13221322

1323+
/// Returns `true` if this place context represents an address-of.
1324+
pub fn is_address_of(&self) -> bool {
1325+
matches!(
1326+
self,
1327+
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
1328+
| PlaceContext::MutatingUse(MutatingUseContext::AddressOf)
1329+
)
1330+
}
1331+
13231332
/// Returns `true` if this place context represents a storage live or storage dead marker.
13241333
#[inline]
13251334
pub fn is_storage_marker(&self) -> bool {

compiler/rustc_mir_dataflow/src/value_analysis.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use std::fmt::{Debug, Formatter};
7070
use rustc_data_structures::fx::FxHashMap;
7171
use rustc_index::vec::IndexVec;
7272
use rustc_middle::mir::tcx::PlaceTy;
73+
use rustc_middle::mir::visit::{PlaceContext, Visitor};
7374
use rustc_middle::mir::*;
7475
use rustc_middle::ty::{self, Ty, TyCtxt};
7576
use rustc_span::DUMMY_SP;
@@ -567,7 +568,17 @@ impl Map {
567568
filter: impl FnMut(Ty<'tcx>) -> bool,
568569
) -> Self {
569570
let mut map = Self::new();
570-
map.register_with_filter(tcx, body, 3, filter);
571+
572+
// If `-Zunsound-mir-opts` is given, tracking through references, and tracking of places
573+
// that have their reference taken is allowed. This would be "unsound" in the sense that
574+
// the correctness relies on an aliasing model similar to Stacked Borrows (which is
575+
// not yet guaranteed).
576+
if tcx.sess.opts.unstable_opts.unsound_mir_opts {
577+
map.register_with_filter(tcx, body, 3, filter, &[]);
578+
} else {
579+
map.register_with_filter(tcx, body, 0, filter, &escaped_places(body));
580+
}
581+
571582
map
572583
}
573584

@@ -577,6 +588,7 @@ impl Map {
577588
body: &Body<'tcx>,
578589
max_derefs: u32,
579590
mut filter: impl FnMut(Ty<'tcx>) -> bool,
591+
exclude: &[Place<'tcx>],
580592
) {
581593
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
582594
let mut projection = Vec::new();
@@ -589,6 +601,7 @@ impl Map {
589601
decl.ty,
590602
&mut filter,
591603
param_env,
604+
exclude,
592605
);
593606
}
594607
}
@@ -602,11 +615,18 @@ impl Map {
602615
ty: Ty<'tcx>,
603616
filter: &mut impl FnMut(Ty<'tcx>) -> bool,
604617
param_env: ty::ParamEnv<'tcx>,
618+
exclude: &[Place<'tcx>],
605619
) {
620+
// This check could be improved.
621+
if exclude.contains(&Place { local, projection: tcx.intern_place_elems(projection) }) {
622+
return;
623+
}
624+
606625
if filter(ty) {
607626
// This might fail if `ty` is not scalar.
608627
let _ = self.register_with_ty(local, projection, ty);
609628
}
629+
610630
if max_derefs > 0 {
611631
if let Some(ty::TypeAndMut { ty: deref_ty, .. }) = ty.builtin_deref(false) {
612632
// References can only be tracked if the target is `!Freeze`.
@@ -620,6 +640,7 @@ impl Map {
620640
deref_ty,
621641
filter,
622642
param_env,
643+
exclude,
623644
);
624645
projection.pop();
625646
}
@@ -632,7 +653,7 @@ impl Map {
632653
}
633654
projection.push(PlaceElem::Field(field, ty));
634655
self.register_with_filter_rec(
635-
tcx, max_derefs, local, projection, ty, filter, param_env,
656+
tcx, max_derefs, local, projection, ty, filter, param_env, exclude,
636657
);
637658
projection.pop();
638659
});
@@ -751,6 +772,25 @@ impl PlaceInfo {
751772
}
752773
}
753774

775+
/// Returns all places, that have their reference or address taken.
776+
fn escaped_places<'tcx>(body: &Body<'tcx>) -> Vec<Place<'tcx>> {
777+
struct Collector<'tcx> {
778+
result: Vec<Place<'tcx>>,
779+
}
780+
781+
impl<'tcx> Visitor<'tcx> for Collector<'tcx> {
782+
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
783+
if context.is_borrow() || context.is_address_of() {
784+
self.result.push(*place);
785+
}
786+
}
787+
}
788+
789+
let mut collector = Collector { result: Vec::new() };
790+
collector.visit_body(body);
791+
collector.result
792+
}
793+
754794
struct Children<'a> {
755795
map: &'a Map,
756796
next: Option<PlaceIndex>,

src/test/mir-opt/dataflow-const-prop/cast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// unit-test: DataflowConstProp
2+
// compile-flags: -Zunsound-mir-opts
23

34
// EMIT_MIR cast.main.DataflowConstProp.diff
45
fn main() {

src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff

Lines changed: 82 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,118 +3,118 @@
33

44
fn main() -> () {
55
let mut _0: (); // return place in scope 0 at $DIR/if.rs:+0:11: +0:11
6-
let _1: i32; // in scope 0 at $DIR/if.rs:+2:9: +2:10
7-
let mut _3: bool; // in scope 0 at $DIR/if.rs:+3:16: +3:24
8-
let mut _4: i32; // in scope 0 at $DIR/if.rs:+3:16: +3:19
9-
let mut _5: &i32; // in scope 0 at $DIR/if.rs:+3:17: +3:19
10-
let mut _7: i32; // in scope 0 at $DIR/if.rs:+4:13: +4:14
11-
let mut _9: bool; // in scope 0 at $DIR/if.rs:+6:16: +6:24
12-
let mut _10: i32; // in scope 0 at $DIR/if.rs:+6:16: +6:19
13-
let mut _11: &i32; // in scope 0 at $DIR/if.rs:+6:17: +6:19
14-
let mut _12: i32; // in scope 0 at $DIR/if.rs:+6:38: +6:39
15-
let mut _14: i32; // in scope 0 at $DIR/if.rs:+7:13: +7:14
6+
let _1: i32; // in scope 0 at $DIR/if.rs:+1:9: +1:10
7+
let mut _3: bool; // in scope 0 at $DIR/if.rs:+2:16: +2:24
8+
let mut _4: i32; // in scope 0 at $DIR/if.rs:+2:16: +2:19
9+
let mut _5: &i32; // in scope 0 at $DIR/if.rs:+2:17: +2:19
10+
let mut _7: i32; // in scope 0 at $DIR/if.rs:+3:13: +3:14
11+
let mut _9: bool; // in scope 0 at $DIR/if.rs:+5:16: +5:24
12+
let mut _10: i32; // in scope 0 at $DIR/if.rs:+5:16: +5:19
13+
let mut _11: &i32; // in scope 0 at $DIR/if.rs:+5:17: +5:19
14+
let mut _12: i32; // in scope 0 at $DIR/if.rs:+5:38: +5:39
15+
let mut _14: i32; // in scope 0 at $DIR/if.rs:+6:13: +6:14
1616
scope 1 {
17-
debug a => _1; // in scope 1 at $DIR/if.rs:+2:9: +2:10
18-
let _2: i32; // in scope 1 at $DIR/if.rs:+3:9: +3:10
17+
debug a => _1; // in scope 1 at $DIR/if.rs:+1:9: +1:10
18+
let _2: i32; // in scope 1 at $DIR/if.rs:+2:9: +2:10
1919
scope 2 {
20-
debug b => _2; // in scope 2 at $DIR/if.rs:+3:9: +3:10
21-
let _6: i32; // in scope 2 at $DIR/if.rs:+4:9: +4:10
20+
debug b => _2; // in scope 2 at $DIR/if.rs:+2:9: +2:10
21+
let _6: i32; // in scope 2 at $DIR/if.rs:+3:9: +3:10
2222
scope 3 {
23-
debug c => _6; // in scope 3 at $DIR/if.rs:+4:9: +4:10
24-
let _8: i32; // in scope 3 at $DIR/if.rs:+6:9: +6:10
23+
debug c => _6; // in scope 3 at $DIR/if.rs:+3:9: +3:10
24+
let _8: i32; // in scope 3 at $DIR/if.rs:+5:9: +5:10
2525
scope 4 {
26-
debug d => _8; // in scope 4 at $DIR/if.rs:+6:9: +6:10
27-
let _13: i32; // in scope 4 at $DIR/if.rs:+7:9: +7:10
26+
debug d => _8; // in scope 4 at $DIR/if.rs:+5:9: +5:10
27+
let _13: i32; // in scope 4 at $DIR/if.rs:+6:9: +6:10
2828
scope 5 {
29-
debug e => _13; // in scope 5 at $DIR/if.rs:+7:9: +7:10
29+
debug e => _13; // in scope 5 at $DIR/if.rs:+6:9: +6:10
3030
}
3131
}
3232
}
3333
}
3434
}
3535

3636
bb0: {
37-
StorageLive(_1); // scope 0 at $DIR/if.rs:+2:9: +2:10
38-
_1 = const 1_i32; // scope 0 at $DIR/if.rs:+2:13: +2:14
39-
StorageLive(_2); // scope 1 at $DIR/if.rs:+3:9: +3:10
40-
StorageLive(_3); // scope 1 at $DIR/if.rs:+3:16: +3:24
41-
StorageLive(_4); // scope 1 at $DIR/if.rs:+3:16: +3:19
42-
StorageLive(_5); // scope 1 at $DIR/if.rs:+3:17: +3:19
43-
_5 = &_1; // scope 1 at $DIR/if.rs:+3:17: +3:19
44-
- _4 = (*_5); // scope 1 at $DIR/if.rs:+3:16: +3:19
45-
- _3 = Eq(move _4, const 1_i32); // scope 1 at $DIR/if.rs:+3:16: +3:24
46-
+ _4 = const 1_i32; // scope 1 at $DIR/if.rs:+3:16: +3:19
47-
+ _3 = const true; // scope 1 at $DIR/if.rs:+3:16: +3:24
48-
StorageDead(_5); // scope 1 at $DIR/if.rs:+3:23: +3:24
49-
StorageDead(_4); // scope 1 at $DIR/if.rs:+3:23: +3:24
50-
- switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+3:16: +3:24
51-
+ switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+3:16: +3:24
37+
StorageLive(_1); // scope 0 at $DIR/if.rs:+1:9: +1:10
38+
_1 = const 1_i32; // scope 0 at $DIR/if.rs:+1:13: +1:14
39+
StorageLive(_2); // scope 1 at $DIR/if.rs:+2:9: +2:10
40+
StorageLive(_3); // scope 1 at $DIR/if.rs:+2:16: +2:24
41+
StorageLive(_4); // scope 1 at $DIR/if.rs:+2:16: +2:19
42+
StorageLive(_5); // scope 1 at $DIR/if.rs:+2:17: +2:19
43+
_5 = &_1; // scope 1 at $DIR/if.rs:+2:17: +2:19
44+
- _4 = (*_5); // scope 1 at $DIR/if.rs:+2:16: +2:19
45+
- _3 = Eq(move _4, const 1_i32); // scope 1 at $DIR/if.rs:+2:16: +2:24
46+
+ _4 = const 1_i32; // scope 1 at $DIR/if.rs:+2:16: +2:19
47+
+ _3 = const true; // scope 1 at $DIR/if.rs:+2:16: +2:24
48+
StorageDead(_5); // scope 1 at $DIR/if.rs:+2:23: +2:24
49+
StorageDead(_4); // scope 1 at $DIR/if.rs:+2:23: +2:24
50+
- switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:24
51+
+ switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:24
5252
}
5353

5454
bb1: {
55-
_2 = const 2_i32; // scope 1 at $DIR/if.rs:+3:27: +3:28
56-
goto -> bb3; // scope 1 at $DIR/if.rs:+3:13: +3:41
55+
_2 = const 2_i32; // scope 1 at $DIR/if.rs:+2:27: +2:28
56+
goto -> bb3; // scope 1 at $DIR/if.rs:+2:13: +2:41
5757
}
5858

5959
bb2: {
60-
_2 = const 3_i32; // scope 1 at $DIR/if.rs:+3:38: +3:39
61-
goto -> bb3; // scope 1 at $DIR/if.rs:+3:13: +3:41
60+
_2 = const 3_i32; // scope 1 at $DIR/if.rs:+2:38: +2:39
61+
goto -> bb3; // scope 1 at $DIR/if.rs:+2:13: +2:41
6262
}
6363

6464
bb3: {
65-
StorageDead(_3); // scope 1 at $DIR/if.rs:+3:40: +3:41
66-
StorageLive(_6); // scope 2 at $DIR/if.rs:+4:9: +4:10
67-
StorageLive(_7); // scope 2 at $DIR/if.rs:+4:13: +4:14
68-
- _7 = _2; // scope 2 at $DIR/if.rs:+4:13: +4:14
69-
- _6 = Add(move _7, const 1_i32); // scope 2 at $DIR/if.rs:+4:13: +4:18
70-
+ _7 = const 2_i32; // scope 2 at $DIR/if.rs:+4:13: +4:14
71-
+ _6 = const 3_i32; // scope 2 at $DIR/if.rs:+4:13: +4:18
72-
StorageDead(_7); // scope 2 at $DIR/if.rs:+4:17: +4:18
73-
StorageLive(_8); // scope 3 at $DIR/if.rs:+6:9: +6:10
74-
StorageLive(_9); // scope 3 at $DIR/if.rs:+6:16: +6:24
75-
StorageLive(_10); // scope 3 at $DIR/if.rs:+6:16: +6:19
76-
StorageLive(_11); // scope 3 at $DIR/if.rs:+6:17: +6:19
77-
_11 = &_1; // scope 3 at $DIR/if.rs:+6:17: +6:19
78-
- _10 = (*_11); // scope 3 at $DIR/if.rs:+6:16: +6:19
79-
- _9 = Eq(move _10, const 1_i32); // scope 3 at $DIR/if.rs:+6:16: +6:24
80-
+ _10 = const 1_i32; // scope 3 at $DIR/if.rs:+6:16: +6:19
81-
+ _9 = const true; // scope 3 at $DIR/if.rs:+6:16: +6:24
82-
StorageDead(_11); // scope 3 at $DIR/if.rs:+6:23: +6:24
83-
StorageDead(_10); // scope 3 at $DIR/if.rs:+6:23: +6:24
84-
- switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+6:16: +6:24
85-
+ switchInt(const true) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+6:16: +6:24
65+
StorageDead(_3); // scope 1 at $DIR/if.rs:+2:40: +2:41
66+
StorageLive(_6); // scope 2 at $DIR/if.rs:+3:9: +3:10
67+
StorageLive(_7); // scope 2 at $DIR/if.rs:+3:13: +3:14
68+
- _7 = _2; // scope 2 at $DIR/if.rs:+3:13: +3:14
69+
- _6 = Add(move _7, const 1_i32); // scope 2 at $DIR/if.rs:+3:13: +3:18
70+
+ _7 = const 2_i32; // scope 2 at $DIR/if.rs:+3:13: +3:14
71+
+ _6 = const 3_i32; // scope 2 at $DIR/if.rs:+3:13: +3:18
72+
StorageDead(_7); // scope 2 at $DIR/if.rs:+3:17: +3:18
73+
StorageLive(_8); // scope 3 at $DIR/if.rs:+5:9: +5:10
74+
StorageLive(_9); // scope 3 at $DIR/if.rs:+5:16: +5:24
75+
StorageLive(_10); // scope 3 at $DIR/if.rs:+5:16: +5:19
76+
StorageLive(_11); // scope 3 at $DIR/if.rs:+5:17: +5:19
77+
_11 = &_1; // scope 3 at $DIR/if.rs:+5:17: +5:19
78+
- _10 = (*_11); // scope 3 at $DIR/if.rs:+5:16: +5:19
79+
- _9 = Eq(move _10, const 1_i32); // scope 3 at $DIR/if.rs:+5:16: +5:24
80+
+ _10 = const 1_i32; // scope 3 at $DIR/if.rs:+5:16: +5:19
81+
+ _9 = const true; // scope 3 at $DIR/if.rs:+5:16: +5:24
82+
StorageDead(_11); // scope 3 at $DIR/if.rs:+5:23: +5:24
83+
StorageDead(_10); // scope 3 at $DIR/if.rs:+5:23: +5:24
84+
- switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:24
85+
+ switchInt(const true) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:24
8686
}
8787

8888
bb4: {
89-
- _8 = _1; // scope 3 at $DIR/if.rs:+6:27: +6:28
90-
+ _8 = const 1_i32; // scope 3 at $DIR/if.rs:+6:27: +6:28
91-
goto -> bb6; // scope 3 at $DIR/if.rs:+6:13: +6:45
89+
- _8 = _1; // scope 3 at $DIR/if.rs:+5:27: +5:28
90+
+ _8 = const 1_i32; // scope 3 at $DIR/if.rs:+5:27: +5:28
91+
goto -> bb6; // scope 3 at $DIR/if.rs:+5:13: +5:45
9292
}
9393

9494
bb5: {
95-
StorageLive(_12); // scope 3 at $DIR/if.rs:+6:38: +6:39
96-
_12 = _1; // scope 3 at $DIR/if.rs:+6:38: +6:39
97-
_8 = Add(move _12, const 1_i32); // scope 3 at $DIR/if.rs:+6:38: +6:43
98-
StorageDead(_12); // scope 3 at $DIR/if.rs:+6:42: +6:43
99-
goto -> bb6; // scope 3 at $DIR/if.rs:+6:13: +6:45
95+
StorageLive(_12); // scope 3 at $DIR/if.rs:+5:38: +5:39
96+
_12 = _1; // scope 3 at $DIR/if.rs:+5:38: +5:39
97+
_8 = Add(move _12, const 1_i32); // scope 3 at $DIR/if.rs:+5:38: +5:43
98+
StorageDead(_12); // scope 3 at $DIR/if.rs:+5:42: +5:43
99+
goto -> bb6; // scope 3 at $DIR/if.rs:+5:13: +5:45
100100
}
101101

102102
bb6: {
103-
StorageDead(_9); // scope 3 at $DIR/if.rs:+6:44: +6:45
104-
StorageLive(_13); // scope 4 at $DIR/if.rs:+7:9: +7:10
105-
StorageLive(_14); // scope 4 at $DIR/if.rs:+7:13: +7:14
106-
- _14 = _8; // scope 4 at $DIR/if.rs:+7:13: +7:14
107-
- _13 = Add(move _14, const 1_i32); // scope 4 at $DIR/if.rs:+7:13: +7:18
108-
+ _14 = const 1_i32; // scope 4 at $DIR/if.rs:+7:13: +7:14
109-
+ _13 = const 2_i32; // scope 4 at $DIR/if.rs:+7:13: +7:18
110-
StorageDead(_14); // scope 4 at $DIR/if.rs:+7:17: +7:18
111-
_0 = const (); // scope 0 at $DIR/if.rs:+0:11: +8:2
112-
StorageDead(_13); // scope 4 at $DIR/if.rs:+8:1: +8:2
113-
StorageDead(_8); // scope 3 at $DIR/if.rs:+8:1: +8:2
114-
StorageDead(_6); // scope 2 at $DIR/if.rs:+8:1: +8:2
115-
StorageDead(_2); // scope 1 at $DIR/if.rs:+8:1: +8:2
116-
StorageDead(_1); // scope 0 at $DIR/if.rs:+8:1: +8:2
117-
return; // scope 0 at $DIR/if.rs:+8:2: +8:2
103+
StorageDead(_9); // scope 3 at $DIR/if.rs:+5:44: +5:45
104+
StorageLive(_13); // scope 4 at $DIR/if.rs:+6:9: +6:10
105+
StorageLive(_14); // scope 4 at $DIR/if.rs:+6:13: +6:14
106+
- _14 = _8; // scope 4 at $DIR/if.rs:+6:13: +6:14
107+
- _13 = Add(move _14, const 1_i32); // scope 4 at $DIR/if.rs:+6:13: +6:18
108+
+ _14 = const 1_i32; // scope 4 at $DIR/if.rs:+6:13: +6:14
109+
+ _13 = const 2_i32; // scope 4 at $DIR/if.rs:+6:13: +6:18
110+
StorageDead(_14); // scope 4 at $DIR/if.rs:+6:17: +6:18
111+
_0 = const (); // scope 0 at $DIR/if.rs:+0:11: +7:2
112+
StorageDead(_13); // scope 4 at $DIR/if.rs:+7:1: +7:2
113+
StorageDead(_8); // scope 3 at $DIR/if.rs:+7:1: +7:2
114+
StorageDead(_6); // scope 2 at $DIR/if.rs:+7:1: +7:2
115+
StorageDead(_2); // scope 1 at $DIR/if.rs:+7:1: +7:2
116+
StorageDead(_1); // scope 0 at $DIR/if.rs:+7:1: +7:2
117+
return; // scope 0 at $DIR/if.rs:+7:2: +7:2
118118
}
119119
}
120120

src/test/mir-opt/dataflow-const-prop/if.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// unit-test: DataflowConstProp
2+
// compile-flags: -Zunsound-mir-opts
23

34
// EMIT_MIR if.main.DataflowConstProp.diff
45
fn main() {
5-
// This does not work (yet). Needs perhaps additional state to track unreachability.
66
let a = 1;
77
let b = if *&a == 1 { 2 } else { 3 };
88
let c = b + 1;

src/test/mir-opt/dataflow-const-prop/ref.main.DataflowConstProp.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
StorageLive(_6); // scope 2 at $DIR/ref.rs:+3:16: +3:34
3838
_6 = id() -> bb1; // scope 2 at $DIR/ref.rs:+3:16: +3:34
3939
// mir::Constant
40-
// + span: $DIR/ref.rs:7:16: 7:32
40+
// + span: $DIR/ref.rs:8:16: 8:32
4141
// + literal: Const { ty: fn() -> u32 {id}, val: Value(<ZST>) }
4242
}
4343

src/test/mir-opt/dataflow-const-prop/ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// unit-test: DataflowConstProp
2+
// compile-flags: -Zunsound-mir-opts
23

34
// EMIT_MIR ref.main.DataflowConstProp.diff
45
fn main() {

0 commit comments

Comments
 (0)