Skip to content

Commit 58638a0

Browse files
committed
Set up false edges in lower_match_tree
1 parent 8f88a7c commit 58638a0

File tree

53 files changed

+1220
-614
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1220
-614
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+33-28
Original file line numberDiff line numberDiff line change
@@ -1093,8 +1093,6 @@ struct Candidate<'pat, 'tcx> {
10931093
/// The earliest block that has only candidates >= this one as descendents. Used for false
10941094
/// edges, see the doc for [`Builder::match_expr`].
10951095
false_edge_start_block: Option<BasicBlock>,
1096-
/// The `false_edge_start_block` of the next candidate.
1097-
next_candidate_start_block: Option<BasicBlock>,
10981096
}
10991097

11001098
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1120,7 +1118,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
11201118
otherwise_block: None,
11211119
pre_binding_block: None,
11221120
false_edge_start_block: None,
1123-
next_candidate_start_block: None,
11241121
}
11251122
}
11261123

@@ -1344,12 +1341,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13441341
let otherwise_block =
13451342
self.match_candidates(match_start_span, scrutinee_span, block, candidates);
13461343

1347-
// Link each leaf candidate to the `false_edge_start_block` of the next one. In the
1348-
// refutable case we also want a false edge to the failure block.
1344+
// Set up false edges so that the borrow-checker cannot make use of the specific CFG we
1345+
// generated. We falsely branch from each candidate to the one below it to make it as if we
1346+
// were testing match branches one by one in order. In the refutable case we also want a
1347+
// false edge to the final failure block.
13491348
let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None };
13501349
for candidate in candidates.iter_mut().rev() {
1350+
let has_guard = candidate.has_guard;
13511351
candidate.visit_leaves_rev(|leaf_candidate| {
1352-
leaf_candidate.next_candidate_start_block = next_candidate_start_block;
1352+
if let Some(next_candidate_start_block) = next_candidate_start_block {
1353+
let source_info = self.source_info(leaf_candidate.extra_data.span);
1354+
// Falsely branch to `next_candidate_start_block` before reaching pre_binding.
1355+
let old_pre_binding = leaf_candidate.pre_binding_block.unwrap();
1356+
let new_pre_binding = self.cfg.start_new_block();
1357+
self.false_edges(
1358+
old_pre_binding,
1359+
new_pre_binding,
1360+
next_candidate_start_block,
1361+
source_info,
1362+
);
1363+
leaf_candidate.pre_binding_block = Some(new_pre_binding);
1364+
if has_guard {
1365+
// Falsely branch to `next_candidate_start_block` also if the guard fails.
1366+
let new_otherwise = self.cfg.start_new_block();
1367+
let old_otherwise = leaf_candidate.otherwise_block.unwrap();
1368+
self.false_edges(
1369+
new_otherwise,
1370+
old_otherwise,
1371+
next_candidate_start_block,
1372+
source_info,
1373+
);
1374+
leaf_candidate.otherwise_block = Some(new_otherwise);
1375+
}
1376+
}
13531377
assert!(leaf_candidate.false_edge_start_block.is_some());
13541378
next_candidate_start_block = leaf_candidate.false_edge_start_block;
13551379
});
@@ -2135,20 +2159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21352159

21362160
debug_assert!(candidate.match_pairs.is_empty());
21372161

2138-
let candidate_source_info = self.source_info(candidate.extra_data.span);
2139-
2140-
let mut block = candidate.pre_binding_block.unwrap();
2141-
2142-
if candidate.next_candidate_start_block.is_some() {
2143-
let fresh_block = self.cfg.start_new_block();
2144-
self.false_edges(
2145-
block,
2146-
fresh_block,
2147-
candidate.next_candidate_start_block,
2148-
candidate_source_info,
2149-
);
2150-
block = fresh_block;
2151-
}
2162+
let block = candidate.pre_binding_block.unwrap();
21522163

21532164
if candidate.extra_data.is_never {
21542165
// This arm has a dummy body, we don't need to generate code for it. `block` is already
@@ -2292,16 +2303,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
22922303
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
22932304
}
22942305

2295-
let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| {
2296-
let unreachable = self.cfg.start_new_block();
2297-
self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
2298-
unreachable
2299-
});
2300-
self.false_edges(
2306+
self.cfg.goto(
23012307
otherwise_post_guard_block,
2302-
otherwise_block,
2303-
candidate.next_candidate_start_block,
23042308
source_info,
2309+
candidate.otherwise_block.unwrap(),
23052310
);
23062311

23072312
// We want to ensure that the matched candidates are bound

compiler/rustc_mir_build/src/build/matches/util.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1717
&mut self,
1818
from_block: BasicBlock,
1919
real_target: BasicBlock,
20-
imaginary_target: Option<BasicBlock>,
20+
imaginary_target: BasicBlock,
2121
source_info: SourceInfo,
2222
) {
23-
match imaginary_target {
24-
Some(target) if target != real_target => {
25-
self.cfg.terminate(
26-
from_block,
27-
source_info,
28-
TerminatorKind::FalseEdge { real_target, imaginary_target: target },
29-
);
30-
}
31-
_ => self.cfg.goto(from_block, source_info, real_target),
23+
if imaginary_target != real_target {
24+
self.cfg.terminate(
25+
from_block,
26+
source_info,
27+
TerminatorKind::FalseEdge { real_target, imaginary_target },
28+
);
29+
} else {
30+
self.cfg.goto(from_block, source_info, real_target)
3231
}
3332
}
3433
}

tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir

+53-21
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ fn full_tested_match() -> () {
3737
}
3838

3939
bb2: {
40-
falseEdge -> [real: bb7, imaginary: bb3];
40+
falseEdge -> [real: bb8, imaginary: bb3];
4141
}
4242

4343
bb3: {
44-
falseEdge -> [real: bb12, imaginary: bb5];
44+
falseEdge -> [real: bb7, imaginary: bb5];
4545
}
4646

4747
bb4: {
@@ -50,26 +50,55 @@ fn full_tested_match() -> () {
5050

5151
bb5: {
5252
_1 = (const 3_i32, const 3_i32);
53-
goto -> bb13;
53+
goto -> bb14;
5454
}
5555

5656
bb6: {
5757
goto -> bb1;
5858
}
5959

6060
bb7: {
61+
StorageLive(_9);
62+
_9 = ((_2 as Some).0: i32);
63+
StorageLive(_10);
64+
_10 = _9;
65+
_1 = (const 2_i32, move _10);
66+
StorageDead(_10);
67+
StorageDead(_9);
68+
goto -> bb14;
69+
}
70+
71+
bb8: {
6172
StorageLive(_6);
6273
_6 = &((_2 as Some).0: i32);
6374
_3 = &fake shallow _2;
6475
StorageLive(_7);
76+
<<<<<<< HEAD
6577
_7 = guard() -> [return: bb8, unwind: bb15];
6678
}
6779

6880
bb8: {
6981
switchInt(move _7) -> [0: bb10, otherwise: bb9];
82+
||||||| parent of 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
83+
_7 = guard() -> [return: bb8, unwind: bb16];
84+
}
85+
86+
bb8: {
87+
switchInt(move _7) -> [0: bb10, otherwise: bb9];
88+
=======
89+
_7 = guard() -> [return: bb10, unwind: bb17];
90+
>>>>>>> 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
7091
}
7192

7293
bb9: {
94+
goto -> bb3;
95+
}
96+
97+
bb10: {
98+
switchInt(move _7) -> [0: bb12, otherwise: bb11];
99+
}
100+
101+
bb11: {
73102
StorageDead(_7);
74103
FakeRead(ForMatchGuard, _3);
75104
FakeRead(ForGuardBinding, _6);
@@ -81,44 +110,47 @@ fn full_tested_match() -> () {
81110
StorageDead(_8);
82111
StorageDead(_5);
83112
StorageDead(_6);
84-
goto -> bb13;
113+
goto -> bb14;
85114
}
86115

87-
bb10: {
88-
goto -> bb11;
116+
bb12: {
117+
goto -> bb13;
89118
}
90119

91-
bb11: {
120+
bb13: {
92121
StorageDead(_7);
93122
StorageDead(_6);
94-
goto -> bb3;
123+
goto -> bb9;
95124
}
96125

97-
bb12: {
98-
StorageLive(_9);
99-
_9 = ((_2 as Some).0: i32);
100-
StorageLive(_10);
101-
_10 = _9;
102-
_1 = (const 2_i32, move _10);
103-
StorageDead(_10);
104-
StorageDead(_9);
105-
goto -> bb13;
106-
}
107-
108-
bb13: {
126+
bb14: {
109127
PlaceMention(_1);
110128
StorageDead(_2);
111129
StorageDead(_1);
112130
_0 = const ();
113131
return;
114132
}
115133

116-
bb14: {
134+
bb15: {
117135
FakeRead(ForMatchedPlace(None), _1);
118136
unreachable;
119137
}
120138

139+
<<<<<<< HEAD
121140
bb15 (cleanup): {
141+
||||||| parent of 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
142+
bb15: {
143+
goto -> bb14;
144+
}
145+
146+
bb16 (cleanup): {
147+
=======
148+
bb16: {
149+
goto -> bb15;
150+
}
151+
152+
bb17 (cleanup): {
153+
>>>>>>> 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
122154
resume;
123155
}
124156
}

tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir

+47-15
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn full_tested_match2() -> () {
3737
}
3838

3939
bb2: {
40-
falseEdge -> [real: bb7, imaginary: bb5];
40+
falseEdge -> [real: bb8, imaginary: bb5];
4141
}
4242

4343
bb3: {
@@ -48,34 +48,57 @@ fn full_tested_match2() -> () {
4848
_1 = (const 2_i32, move _10);
4949
StorageDead(_10);
5050
StorageDead(_9);
51-
goto -> bb13;
51+
goto -> bb14;
5252
}
5353

5454
bb4: {
5555
goto -> bb1;
5656
}
5757

5858
bb5: {
59-
falseEdge -> [real: bb12, imaginary: bb3];
59+
falseEdge -> [real: bb7, imaginary: bb3];
6060
}
6161

6262
bb6: {
6363
goto -> bb1;
6464
}
6565

6666
bb7: {
67+
_1 = (const 3_i32, const 3_i32);
68+
goto -> bb14;
69+
}
70+
71+
bb8: {
6772
StorageLive(_6);
6873
_6 = &((_2 as Some).0: i32);
6974
_3 = &fake shallow _2;
7075
StorageLive(_7);
76+
<<<<<<< HEAD
7177
_7 = guard() -> [return: bb8, unwind: bb15];
7278
}
7379

7480
bb8: {
7581
switchInt(move _7) -> [0: bb10, otherwise: bb9];
82+
||||||| parent of 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
83+
_7 = guard() -> [return: bb8, unwind: bb16];
84+
}
85+
86+
bb8: {
87+
switchInt(move _7) -> [0: bb10, otherwise: bb9];
88+
=======
89+
_7 = guard() -> [return: bb10, unwind: bb17];
90+
>>>>>>> 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
7691
}
7792

7893
bb9: {
94+
falseEdge -> [real: bb3, imaginary: bb5];
95+
}
96+
97+
bb10: {
98+
switchInt(move _7) -> [0: bb12, otherwise: bb11];
99+
}
100+
101+
bb11: {
79102
StorageDead(_7);
80103
FakeRead(ForMatchGuard, _3);
81104
FakeRead(ForGuardBinding, _6);
@@ -87,38 +110,47 @@ fn full_tested_match2() -> () {
87110
StorageDead(_8);
88111
StorageDead(_5);
89112
StorageDead(_6);
90-
goto -> bb13;
113+
goto -> bb14;
91114
}
92115

93-
bb10: {
94-
goto -> bb11;
116+
bb12: {
117+
goto -> bb13;
95118
}
96119

97-
bb11: {
120+
bb13: {
98121
StorageDead(_7);
99122
StorageDead(_6);
100-
falseEdge -> [real: bb3, imaginary: bb5];
123+
goto -> bb9;
101124
}
102125

103-
bb12: {
104-
_1 = (const 3_i32, const 3_i32);
105-
goto -> bb13;
106-
}
107-
108-
bb13: {
126+
bb14: {
109127
PlaceMention(_1);
110128
StorageDead(_2);
111129
StorageDead(_1);
112130
_0 = const ();
113131
return;
114132
}
115133

116-
bb14: {
134+
bb15: {
117135
FakeRead(ForMatchedPlace(None), _1);
118136
unreachable;
119137
}
120138

139+
<<<<<<< HEAD
121140
bb15 (cleanup): {
141+
||||||| parent of 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
142+
bb15: {
143+
goto -> bb14;
144+
}
145+
146+
bb16 (cleanup): {
147+
=======
148+
bb16: {
149+
goto -> bb15;
150+
}
151+
152+
bb17 (cleanup): {
153+
>>>>>>> 6d2cf963cc4 (Set up false edges in `lower_match_tree`)
122154
resume;
123155
}
124156
}

0 commit comments

Comments
 (0)