Skip to content

Commit 6d2cf96

Browse files
committed
Set up false edges in lower_match_tree
1 parent 3f729a0 commit 6d2cf96

File tree

53 files changed

+723
-707
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

+723
-707
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
@@ -1088,8 +1088,6 @@ struct Candidate<'pat, 'tcx> {
10881088
/// The earliest block that has only candidates >= this one as descendents. Used for false
10891089
/// edges, see the doc for [`Builder::match_expr`].
10901090
false_edge_start_block: Option<BasicBlock>,
1091-
/// The `false_edge_start_block` of the next candidate.
1092-
next_candidate_start_block: Option<BasicBlock>,
10931091
}
10941092

10951093
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1115,7 +1113,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
11151113
otherwise_block: None,
11161114
pre_binding_block: None,
11171115
false_edge_start_block: None,
1118-
next_candidate_start_block: None,
11191116
}
11201117
}
11211118

@@ -1325,12 +1322,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13251322
// This will generate code to test scrutinee_place and branch to the appropriate arm block
13261323
self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates);
13271324

1328-
// Link each leaf candidate to the `false_edge_start_block` of the next one. In the
1329-
// refutable case we also want a false edge to the failure block.
1325+
// Set up false edges so that the borrow-checker cannot make use of the specific CFG we
1326+
// generated. We falsely branch from each candidate to the one below it to make it as if we
1327+
// were testing match branches one by one in order. In the refutable case we also want a
1328+
// false edge to the final failure block.
13301329
let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None };
13311330
for candidate in candidates.iter_mut().rev() {
1331+
let has_guard = candidate.has_guard;
13321332
candidate.visit_leaves_rev(|leaf_candidate| {
1333-
leaf_candidate.next_candidate_start_block = next_candidate_start_block;
1333+
if let Some(next_candidate_start_block) = next_candidate_start_block {
1334+
let source_info = self.source_info(leaf_candidate.extra_data.span);
1335+
// Falsely branch to `next_candidate_start_block` before reaching pre_binding.
1336+
let old_pre_binding = leaf_candidate.pre_binding_block.unwrap();
1337+
let new_pre_binding = self.cfg.start_new_block();
1338+
self.false_edges(
1339+
old_pre_binding,
1340+
new_pre_binding,
1341+
next_candidate_start_block,
1342+
source_info,
1343+
);
1344+
leaf_candidate.pre_binding_block = Some(new_pre_binding);
1345+
if has_guard {
1346+
// Falsely branch to `next_candidate_start_block` also if the guard fails.
1347+
let new_otherwise = self.cfg.start_new_block();
1348+
let old_otherwise = leaf_candidate.otherwise_block.unwrap();
1349+
self.false_edges(
1350+
new_otherwise,
1351+
old_otherwise,
1352+
next_candidate_start_block,
1353+
source_info,
1354+
);
1355+
leaf_candidate.otherwise_block = Some(new_otherwise);
1356+
}
1357+
}
13341358
assert!(leaf_candidate.false_edge_start_block.is_some());
13351359
next_candidate_start_block = leaf_candidate.false_edge_start_block;
13361360
});
@@ -2147,20 +2171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21472171

21482172
debug_assert!(candidate.match_pairs.is_empty());
21492173

2150-
let candidate_source_info = self.source_info(candidate.extra_data.span);
2151-
2152-
let mut block = candidate.pre_binding_block.unwrap();
2153-
2154-
if candidate.next_candidate_start_block.is_some() {
2155-
let fresh_block = self.cfg.start_new_block();
2156-
self.false_edges(
2157-
block,
2158-
fresh_block,
2159-
candidate.next_candidate_start_block,
2160-
candidate_source_info,
2161-
);
2162-
block = fresh_block;
2163-
}
2174+
let block = candidate.pre_binding_block.unwrap();
21642175

21652176
if candidate.extra_data.is_never {
21662177
// This arm has a dummy body, we don't need to generate code for it. `block` is already
@@ -2304,16 +2315,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23042315
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
23052316
}
23062317

2307-
let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| {
2308-
let unreachable = self.cfg.start_new_block();
2309-
self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
2310-
unreachable
2311-
});
2312-
self.false_edges(
2318+
self.cfg.goto(
23132319
otherwise_post_guard_block,
2314-
otherwise_block,
2315-
candidate.next_candidate_start_block,
23162320
source_info,
2321+
candidate.otherwise_block.unwrap(),
23172322
);
23182323

23192324
// 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
@@ -80,18 +80,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8080
&mut self,
8181
from_block: BasicBlock,
8282
real_target: BasicBlock,
83-
imaginary_target: Option<BasicBlock>,
83+
imaginary_target: BasicBlock,
8484
source_info: SourceInfo,
8585
) {
86-
match imaginary_target {
87-
Some(target) if target != real_target => {
88-
self.cfg.terminate(
89-
from_block,
90-
source_info,
91-
TerminatorKind::FalseEdge { real_target, imaginary_target: target },
92-
);
93-
}
94-
_ => self.cfg.goto(from_block, source_info, real_target),
86+
if imaginary_target != real_target {
87+
self.cfg.terminate(
88+
from_block,
89+
source_info,
90+
TerminatorKind::FalseEdge { real_target, imaginary_target },
91+
);
92+
} else {
93+
self.cfg.goto(from_block, source_info, real_target)
9594
}
9695
}
9796
}

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

Lines changed: 32 additions & 28 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: bb16];
76+
_7 = guard() -> [return: bb10, unwind: bb17];
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,48 +96,37 @@ 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;
109+
goto -> bb9;
95110
}
96111

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: {
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: {
122-
goto -> bb14;
125+
bb16: {
126+
goto -> bb15;
123127
}
124128

125-
bb16 (cleanup): {
129+
bb17 (cleanup): {
126130
resume;
127131
}
128132
}

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

Lines changed: 26 additions & 22 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: bb16];
76+
_7 = guard() -> [return: bb10, unwind: bb17];
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,42 +96,37 @@ 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];
109+
goto -> bb9;
101110
}
102111

103-
bb12: {
104-
_1 = (const 3_i32, const 3_i32);
105-
goto -> bb13;
106-
}
107-
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: {
122-
goto -> bb14;
125+
bb16: {
126+
goto -> bb15;
123127
}
124128

125-
bb16 (cleanup): {
129+
bb17 (cleanup): {
126130
resume;
127131
}
128132
}

0 commit comments

Comments
 (0)