Skip to content

Commit e2fd9aa

Browse files
committed
Set up false edges in lower_match_tree
1 parent 9e05fb6 commit e2fd9aa

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

+33-28
Original file line numberDiff line numberDiff line change
@@ -1152,8 +1152,6 @@ struct Candidate<'pat, 'tcx> {
11521152
/// The earliest block that has only candidates >= this one as descendents. Used for false
11531153
/// edges, see the doc for [`Builder::match_expr`].
11541154
false_edge_start_block: Option<BasicBlock>,
1155-
/// The `false_edge_start_block` of the next candidate.
1156-
next_candidate_start_block: Option<BasicBlock>,
11571155
}
11581156

11591157
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1179,7 +1177,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
11791177
otherwise_block: None,
11801178
pre_binding_block: None,
11811179
false_edge_start_block: None,
1182-
next_candidate_start_block: None,
11831180
}
11841181
}
11851182

@@ -1444,12 +1441,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14441441
let otherwise_block =
14451442
self.match_candidates(match_start_span, scrutinee_span, block, candidates);
14461443

1447-
// Link each leaf candidate to the `false_edge_start_block` of the next one. In the
1448-
// refutable case we also want a false edge to the failure block.
1444+
// Set up false edges so that the borrow-checker cannot make use of the specific CFG we
1445+
// generated. We falsely branch from each candidate to the one below it to make it as if we
1446+
// were testing match branches one by one in order. In the refutable case we also want a
1447+
// false edge to the final failure block.
14491448
let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None };
14501449
for candidate in candidates.iter_mut().rev() {
1450+
let has_guard = candidate.has_guard;
14511451
candidate.visit_leaves_rev(|leaf_candidate| {
1452-
leaf_candidate.next_candidate_start_block = next_candidate_start_block;
1452+
if let Some(next_candidate_start_block) = next_candidate_start_block {
1453+
let source_info = self.source_info(leaf_candidate.extra_data.span);
1454+
// Falsely branch to `next_candidate_start_block` before reaching pre_binding.
1455+
let old_pre_binding = leaf_candidate.pre_binding_block.unwrap();
1456+
let new_pre_binding = self.cfg.start_new_block();
1457+
self.false_edges(
1458+
old_pre_binding,
1459+
new_pre_binding,
1460+
next_candidate_start_block,
1461+
source_info,
1462+
);
1463+
leaf_candidate.pre_binding_block = Some(new_pre_binding);
1464+
if has_guard {
1465+
// Falsely branch to `next_candidate_start_block` also if the guard fails.
1466+
let new_otherwise = self.cfg.start_new_block();
1467+
let old_otherwise = leaf_candidate.otherwise_block.unwrap();
1468+
self.false_edges(
1469+
new_otherwise,
1470+
old_otherwise,
1471+
next_candidate_start_block,
1472+
source_info,
1473+
);
1474+
leaf_candidate.otherwise_block = Some(new_otherwise);
1475+
}
1476+
}
14531477
assert!(leaf_candidate.false_edge_start_block.is_some());
14541478
next_candidate_start_block = leaf_candidate.false_edge_start_block;
14551479
});
@@ -2302,20 +2326,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23022326

23032327
debug_assert!(candidate.match_pairs.is_empty());
23042328

2305-
let candidate_source_info = self.source_info(candidate.extra_data.span);
2306-
2307-
let mut block = candidate.pre_binding_block.unwrap();
2308-
2309-
if candidate.next_candidate_start_block.is_some() {
2310-
let fresh_block = self.cfg.start_new_block();
2311-
self.false_edges(
2312-
block,
2313-
fresh_block,
2314-
candidate.next_candidate_start_block,
2315-
candidate_source_info,
2316-
);
2317-
block = fresh_block;
2318-
}
2329+
let block = candidate.pre_binding_block.unwrap();
23192330

23202331
if candidate.extra_data.is_never {
23212332
// This arm has a dummy body, we don't need to generate code for it. `block` is already
@@ -2382,16 +2393,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23822393
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
23832394
}
23842395

2385-
let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| {
2386-
let unreachable = self.cfg.start_new_block();
2387-
self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
2388-
unreachable
2389-
});
2390-
self.false_edges(
2396+
self.cfg.goto(
23912397
otherwise_post_guard_block,
2392-
otherwise_block,
2393-
candidate.next_candidate_start_block,
23942398
source_info,
2399+
candidate.otherwise_block.unwrap(),
23952400
);
23962401

23972402
// 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
@@ -18,18 +18,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1818
&mut self,
1919
from_block: BasicBlock,
2020
real_target: BasicBlock,
21-
imaginary_target: Option<BasicBlock>,
21+
imaginary_target: BasicBlock,
2222
source_info: SourceInfo,
2323
) {
24-
match imaginary_target {
25-
Some(target) if target != real_target => {
26-
self.cfg.terminate(
27-
from_block,
28-
source_info,
29-
TerminatorKind::FalseEdge { real_target, imaginary_target: target },
30-
);
31-
}
32-
_ => self.cfg.goto(from_block, source_info, real_target),
24+
if imaginary_target != real_target {
25+
self.cfg.terminate(
26+
from_block,
27+
source_info,
28+
TerminatorKind::FalseEdge { real_target, imaginary_target },
29+
);
30+
} else {
31+
self.cfg.goto(from_block, source_info, real_target)
3332
}
3433
}
3534
}

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

+30-26
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

+24-20
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)