Skip to content

Commit 263abf6

Browse files
committed
Set up false edges in lower_match_tree
1 parent 80968f9 commit 263abf6

File tree

54 files changed

+720
-700
lines changed

Some content is hidden

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

54 files changed

+720
-700
lines changed

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

Lines changed: 33 additions & 28 deletions
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
@@ -2215,16 +2226,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
22152226
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
22162227
}
22172228

2218-
let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| {
2219-
let unreachable = self.cfg.start_new_block();
2220-
self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
2221-
unreachable
2222-
});
2223-
self.false_edges(
2229+
self.cfg.goto(
22242230
otherwise_post_guard_block,
2225-
otherwise_block,
2226-
candidate.next_candidate_start_block,
22272231
source_info,
2232+
candidate.otherwise_block.unwrap(),
22282233
);
22292234

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

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

Lines changed: 9 additions & 10 deletions
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

Lines changed: 30 additions & 26 deletions
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,41 @@ 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);
65-
_7 = guard() -> [return: bb8, unwind: bb15];
76+
_7 = guard() -> [return: bb10, unwind: bb16];
6677
}
6778

68-
bb8: {
69-
switchInt(move _7) -> [0: bb10, otherwise: bb9];
79+
bb9: {
80+
goto -> bb3;
7081
}
7182

72-
bb9: {
83+
bb10: {
84+
switchInt(move _7) -> [0: bb12, otherwise: bb11];
85+
}
86+
87+
bb11: {
7388
StorageDead(_7);
7489
FakeRead(ForMatchGuard, _3);
7590
FakeRead(ForGuardBinding, _6);
@@ -81,44 +96,33 @@ fn full_tested_match() -> () {
8196
StorageDead(_8);
8297
StorageDead(_5);
8398
StorageDead(_6);
84-
goto -> bb13;
99+
goto -> bb14;
85100
}
86101

87-
bb10: {
88-
goto -> bb11;
102+
bb12: {
103+
goto -> bb13;
89104
}
90105

91-
bb11: {
106+
bb13: {
92107
StorageDead(_7);
93108
StorageDead(_6);
94-
goto -> bb3;
95-
}
96-
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;
109+
goto -> bb9;
106110
}
107111

108-
bb13: {
112+
bb14: {
109113
PlaceMention(_1);
110114
StorageDead(_2);
111115
StorageDead(_1);
112116
_0 = const ();
113117
return;
114118
}
115119

116-
bb14: {
120+
bb15: {
117121
FakeRead(ForMatchedPlace(None), _1);
118122
unreachable;
119123
}
120124

121-
bb15 (cleanup): {
125+
bb16 (cleanup): {
122126
resume;
123127
}
124128
}

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

Lines changed: 24 additions & 20 deletions
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,43 @@ 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);
71-
_7 = guard() -> [return: bb8, unwind: bb15];
76+
_7 = guard() -> [return: bb10, unwind: bb16];
7277
}
7378

74-
bb8: {
75-
switchInt(move _7) -> [0: bb10, otherwise: bb9];
79+
bb9: {
80+
falseEdge -> [real: bb3, imaginary: bb5];
7681
}
7782

78-
bb9: {
83+
bb10: {
84+
switchInt(move _7) -> [0: bb12, otherwise: bb11];
85+
}
86+
87+
bb11: {
7988
StorageDead(_7);
8089
FakeRead(ForMatchGuard, _3);
8190
FakeRead(ForGuardBinding, _6);
@@ -87,38 +96,33 @@ fn full_tested_match2() -> () {
8796
StorageDead(_8);
8897
StorageDead(_5);
8998
StorageDead(_6);
90-
goto -> bb13;
99+
goto -> bb14;
91100
}
92101

93-
bb10: {
94-
goto -> bb11;
102+
bb12: {
103+
goto -> bb13;
95104
}
96105

97-
bb11: {
106+
bb13: {
98107
StorageDead(_7);
99108
StorageDead(_6);
100-
falseEdge -> [real: bb3, imaginary: bb5];
101-
}
102-
103-
bb12: {
104-
_1 = (const 3_i32, const 3_i32);
105-
goto -> bb13;
109+
goto -> bb9;
106110
}
107111

108-
bb13: {
112+
bb14: {
109113
PlaceMention(_1);
110114
StorageDead(_2);
111115
StorageDead(_1);
112116
_0 = const ();
113117
return;
114118
}
115119

116-
bb14: {
120+
bb15: {
117121
FakeRead(ForMatchedPlace(None), _1);
118122
unreachable;
119123
}
120124

121-
bb15 (cleanup): {
125+
bb16 (cleanup): {
122126
resume;
123127
}
124128
}

0 commit comments

Comments
 (0)