Skip to content

Commit ee38a2c

Browse files
committed
More precise false edges
1 parent 5d16139 commit ee38a2c

6 files changed

+66
-26
lines changed

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

+50-10
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
258258
/// };
259259
/// ```
260260
///
261-
/// To ensure this, we add false edges:
261+
/// We add false edges to act as if we were naively matching each arm in order. What we need is
262+
/// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
263+
/// block to next candidate D's pre-binding block. For maximum precision (needed for deref
264+
/// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
265+
/// avoid loops).
262266
///
263-
/// * From each pre-binding block to the next pre-binding block.
264-
/// * From each otherwise block to the next pre-binding block.
267+
/// This turns out to be easy to compute: that block is the `start_block` of the first call to
268+
/// `match_candidates` where D is the first candidate in the list.
269+
///
270+
/// For example:
271+
/// ```rust
272+
/// # let (x, y) = (true, true);
273+
/// match (x, y) {
274+
/// (true, true) => 1,
275+
/// (false, true) => 2,
276+
/// (true, false) => 3,
277+
/// _ => 4,
278+
/// }
279+
/// # ;
280+
/// ```
281+
/// In this example, the pre-binding block of arm 1 has a false edge to the block for result
282+
/// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
283+
/// of the next arm.
284+
///
285+
/// On top of this, we also add a false edge from the otherwise_block of each guard to the
286+
/// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
287+
/// guards may have run.
265288
#[instrument(level = "debug", skip(self, arms))]
266289
pub(crate) fn match_expr(
267290
&mut self,
@@ -407,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
407430
for candidate in candidates {
408431
candidate.visit_leaves(|leaf_candidate| {
409432
if let Some(ref mut prev) = previous_candidate {
410-
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
433+
assert!(leaf_candidate.false_edge_start_block.is_some());
434+
prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
411435
}
412436
previous_candidate = Some(leaf_candidate);
413437
});
@@ -1052,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
10521076

10531077
/// The block before the `bindings` have been established.
10541078
pre_binding_block: Option<BasicBlock>,
1055-
/// The pre-binding block of the next candidate.
1056-
next_candidate_pre_binding_block: Option<BasicBlock>,
1079+
1080+
/// The earliest block that has only candidates >= this one as descendents. Used for false
1081+
/// edges, see the doc for [`Builder::match_expr`].
1082+
false_edge_start_block: Option<BasicBlock>,
1083+
/// The `false_edge_start_block` of the next candidate.
1084+
next_candidate_start_block: Option<BasicBlock>,
10571085
}
10581086

10591087
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1075,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
10751103
or_span: None,
10761104
otherwise_block: None,
10771105
pre_binding_block: None,
1078-
next_candidate_pre_binding_block: None,
1106+
false_edge_start_block: None,
1107+
next_candidate_start_block: None,
10791108
}
10801109
}
10811110

@@ -1367,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13671396
otherwise_block: BasicBlock,
13681397
candidates: &mut [&mut Candidate<'_, 'tcx>],
13691398
) {
1399+
if let [first, ..] = candidates {
1400+
if first.false_edge_start_block.is_none() {
1401+
first.false_edge_start_block = Some(start_block);
1402+
}
1403+
}
1404+
13701405
match candidates {
13711406
[] => {
13721407
// If there are no candidates that still need testing, we're done. Since all matches are
@@ -1587,6 +1622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15871622
.into_iter()
15881623
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
15891624
.collect();
1625+
candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
15901626
}
15911627

15921628
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
@@ -1606,6 +1642,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16061642
let any_matches = self.cfg.start_new_block();
16071643
let or_span = candidate.or_span.take().unwrap();
16081644
let source_info = self.source_info(or_span);
1645+
if candidate.false_edge_start_block.is_none() {
1646+
candidate.false_edge_start_block =
1647+
candidate.subcandidates[0].false_edge_start_block;
1648+
}
16091649
for subcandidate in mem::take(&mut candidate.subcandidates) {
16101650
let or_block = subcandidate.pre_binding_block.unwrap();
16111651
self.cfg.goto(or_block, source_info, any_matches);
@@ -2021,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20212061

20222062
let mut block = candidate.pre_binding_block.unwrap();
20232063

2024-
if candidate.next_candidate_pre_binding_block.is_some() {
2064+
if candidate.next_candidate_start_block.is_some() {
20252065
let fresh_block = self.cfg.start_new_block();
20262066
self.false_edges(
20272067
block,
20282068
fresh_block,
2029-
candidate.next_candidate_pre_binding_block,
2069+
candidate.next_candidate_start_block,
20302070
candidate_source_info,
20312071
);
20322072
block = fresh_block;
@@ -2174,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21742214
self.false_edges(
21752215
otherwise_post_guard_block,
21762216
otherwise_block,
2177-
candidate.next_candidate_pre_binding_block,
2217+
candidate.next_candidate_start_block,
21782218
source_info,
21792219
);
21802220

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn main() -> () {
4848
}
4949

5050
bb2: {
51-
falseEdge -> [real: bb15, imaginary: bb6];
51+
falseEdge -> [real: bb15, imaginary: bb3];
5252
}
5353

5454
bb3: {

tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
4040
}
4141

4242
bb4: {
43-
falseEdge -> [real: bb12, imaginary: bb9];
43+
falseEdge -> [real: bb12, imaginary: bb7];
4444
}
4545

4646
bb5: {
4747
switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6];
4848
}
4949

5050
bb6: {
51-
falseEdge -> [real: bb16, imaginary: bb3];
51+
falseEdge -> [real: bb16, imaginary: bb1];
5252
}
5353

5454
bb7: {
@@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
6060
}
6161

6262
bb9: {
63-
falseEdge -> [real: bb15, imaginary: bb6];
63+
falseEdge -> [real: bb15, imaginary: bb5];
6464
}
6565

6666
bb10: {
@@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
8989

9090
bb14: {
9191
StorageDead(_10);
92-
falseEdge -> [real: bb5, imaginary: bb9];
92+
falseEdge -> [real: bb5, imaginary: bb7];
9393
}
9494

9595
bb15: {

tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
2323
}
2424

2525
bb2: {
26-
falseEdge -> [real: bb9, imaginary: bb4];
26+
falseEdge -> [real: bb9, imaginary: bb3];
2727
}
2828

2929
bb3: {
@@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
3232
}
3333

3434
bb4: {
35-
falseEdge -> [real: bb12, imaginary: bb6];
35+
falseEdge -> [real: bb12, imaginary: bb5];
3636
}
3737

3838
bb5: {
@@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
6969

7070
bb11: {
7171
StorageDead(_8);
72-
falseEdge -> [real: bb1, imaginary: bb4];
72+
falseEdge -> [real: bb1, imaginary: bb3];
7373
}
7474

7575
bb12: {

tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff

+4-4
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@
6060
}
6161

6262
- bb5: {
63-
- falseEdge -> [real: bb13, imaginary: bb3];
63+
- falseEdge -> [real: bb13, imaginary: bb2];
6464
- }
6565
-
6666
- bb6: {
67-
- falseEdge -> [real: bb8, imaginary: bb5];
67+
- falseEdge -> [real: bb8, imaginary: bb1];
6868
- }
6969
-
7070
- bb7: {
@@ -127,7 +127,7 @@
127127
StorageDead(_9);
128128
StorageDead(_8);
129129
StorageDead(_6);
130-
- falseEdge -> [real: bb1, imaginary: bb5];
130+
- falseEdge -> [real: bb1, imaginary: bb1];
131131
+ goto -> bb1;
132132
}
133133

@@ -184,7 +184,7 @@
184184
StorageDead(_12);
185185
StorageDead(_8);
186186
StorageDead(_6);
187-
- falseEdge -> [real: bb2, imaginary: bb3];
187+
- falseEdge -> [real: bb2, imaginary: bb2];
188188
+ goto -> bb2;
189189
}
190190

tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff

+4-4
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@
6060
}
6161

6262
- bb5: {
63-
- falseEdge -> [real: bb13, imaginary: bb3];
63+
- falseEdge -> [real: bb13, imaginary: bb2];
6464
- }
6565
-
6666
- bb6: {
67-
- falseEdge -> [real: bb8, imaginary: bb5];
67+
- falseEdge -> [real: bb8, imaginary: bb1];
6868
- }
6969
-
7070
- bb7: {
@@ -127,7 +127,7 @@
127127
StorageDead(_9);
128128
StorageDead(_8);
129129
StorageDead(_6);
130-
- falseEdge -> [real: bb1, imaginary: bb5];
130+
- falseEdge -> [real: bb1, imaginary: bb1];
131131
+ goto -> bb1;
132132
}
133133

@@ -184,7 +184,7 @@
184184
StorageDead(_12);
185185
StorageDead(_8);
186186
StorageDead(_6);
187-
- falseEdge -> [real: bb2, imaginary: bb3];
187+
- falseEdge -> [real: bb2, imaginary: bb2];
188188
+ goto -> bb2;
189189
}
190190

0 commit comments

Comments
 (0)