mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
More precise false edges
This commit is contained in:
parent
8f80259f10
commit
8021192d34
@ -258,10 +258,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// To ensure this, we add false edges:
|
||||
/// We add false edges to act as if we were naively matching each arm in order. What we need is
|
||||
/// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
|
||||
/// block to next candidate D's pre-binding block. For maximum precision (needed for deref
|
||||
/// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
|
||||
/// avoid loops).
|
||||
///
|
||||
/// * From each pre-binding block to the next pre-binding block.
|
||||
/// * From each otherwise block to the next pre-binding block.
|
||||
/// This turns out to be easy to compute: that block is the `start_block` of the first call to
|
||||
/// `match_candidates` where D is the first candidate in the list.
|
||||
///
|
||||
/// For example:
|
||||
/// ```rust
|
||||
/// # let (x, y) = (true, true);
|
||||
/// match (x, y) {
|
||||
/// (true, true) => 1,
|
||||
/// (false, true) => 2,
|
||||
/// (true, false) => 3,
|
||||
/// _ => 4,
|
||||
/// }
|
||||
/// # ;
|
||||
/// ```
|
||||
/// In this example, the pre-binding block of arm 1 has a false edge to the block for result
|
||||
/// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
|
||||
/// of the next arm.
|
||||
///
|
||||
/// On top of this, we also add a false edge from the otherwise_block of each guard to the
|
||||
/// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
|
||||
/// guards may have run.
|
||||
#[instrument(level = "debug", skip(self, arms))]
|
||||
pub(crate) fn match_expr(
|
||||
&mut self,
|
||||
@ -407,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
for candidate in candidates {
|
||||
candidate.visit_leaves(|leaf_candidate| {
|
||||
if let Some(ref mut prev) = previous_candidate {
|
||||
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
|
||||
assert!(leaf_candidate.false_edge_start_block.is_some());
|
||||
prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
|
||||
}
|
||||
previous_candidate = Some(leaf_candidate);
|
||||
});
|
||||
@ -1052,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
|
||||
|
||||
/// The block before the `bindings` have been established.
|
||||
pre_binding_block: Option<BasicBlock>,
|
||||
/// The pre-binding block of the next candidate.
|
||||
next_candidate_pre_binding_block: Option<BasicBlock>,
|
||||
|
||||
/// The earliest block that has only candidates >= this one as descendents. Used for false
|
||||
/// edges, see the doc for [`Builder::match_expr`].
|
||||
false_edge_start_block: Option<BasicBlock>,
|
||||
/// The `false_edge_start_block` of the next candidate.
|
||||
next_candidate_start_block: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
||||
@ -1075,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
||||
or_span: None,
|
||||
otherwise_block: None,
|
||||
pre_binding_block: None,
|
||||
next_candidate_pre_binding_block: None,
|
||||
false_edge_start_block: None,
|
||||
next_candidate_start_block: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1367,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
otherwise_block: BasicBlock,
|
||||
candidates: &mut [&mut Candidate<'_, 'tcx>],
|
||||
) {
|
||||
if let [first, ..] = candidates {
|
||||
if first.false_edge_start_block.is_none() {
|
||||
first.false_edge_start_block = Some(start_block);
|
||||
}
|
||||
}
|
||||
|
||||
match candidates {
|
||||
[] => {
|
||||
// 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> {
|
||||
.into_iter()
|
||||
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
|
||||
.collect();
|
||||
candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
let any_matches = self.cfg.start_new_block();
|
||||
let or_span = candidate.or_span.take().unwrap();
|
||||
let source_info = self.source_info(or_span);
|
||||
if candidate.false_edge_start_block.is_none() {
|
||||
candidate.false_edge_start_block =
|
||||
candidate.subcandidates[0].false_edge_start_block;
|
||||
}
|
||||
for subcandidate in mem::take(&mut candidate.subcandidates) {
|
||||
let or_block = subcandidate.pre_binding_block.unwrap();
|
||||
self.cfg.goto(or_block, source_info, any_matches);
|
||||
@ -2021,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
let mut block = candidate.pre_binding_block.unwrap();
|
||||
|
||||
if candidate.next_candidate_pre_binding_block.is_some() {
|
||||
if candidate.next_candidate_start_block.is_some() {
|
||||
let fresh_block = self.cfg.start_new_block();
|
||||
self.false_edges(
|
||||
block,
|
||||
fresh_block,
|
||||
candidate.next_candidate_pre_binding_block,
|
||||
candidate.next_candidate_start_block,
|
||||
candidate_source_info,
|
||||
);
|
||||
block = fresh_block;
|
||||
@ -2174,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.false_edges(
|
||||
otherwise_post_guard_block,
|
||||
otherwise_block,
|
||||
candidate.next_candidate_pre_binding_block,
|
||||
candidate.next_candidate_start_block,
|
||||
source_info,
|
||||
);
|
||||
|
||||
|
@ -48,7 +48,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb15, imaginary: bb6];
|
||||
falseEdge -> [real: bb15, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
@ -40,7 +40,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb4: {
|
||||
falseEdge -> [real: bb12, imaginary: bb9];
|
||||
falseEdge -> [real: bb12, imaginary: bb7];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
@ -48,7 +48,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb6: {
|
||||
falseEdge -> [real: bb16, imaginary: bb3];
|
||||
falseEdge -> [real: bb16, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb9: {
|
||||
falseEdge -> [real: bb15, imaginary: bb6];
|
||||
falseEdge -> [real: bb15, imaginary: bb5];
|
||||
}
|
||||
|
||||
bb10: {
|
||||
@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
|
||||
bb14: {
|
||||
StorageDead(_10);
|
||||
falseEdge -> [real: bb5, imaginary: bb9];
|
||||
falseEdge -> [real: bb5, imaginary: bb7];
|
||||
}
|
||||
|
||||
bb15: {
|
||||
|
@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb9, imaginary: bb4];
|
||||
falseEdge -> [real: bb9, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb4: {
|
||||
falseEdge -> [real: bb12, imaginary: bb6];
|
||||
falseEdge -> [real: bb12, imaginary: bb5];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
|
||||
bb11: {
|
||||
StorageDead(_8);
|
||||
falseEdge -> [real: bb1, imaginary: bb4];
|
||||
falseEdge -> [real: bb1, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
|
@ -60,11 +60,11 @@
|
||||
}
|
||||
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb2];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
- falseEdge -> [real: bb8, imaginary: bb5];
|
||||
- falseEdge -> [real: bb8, imaginary: bb1];
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
@ -127,7 +127,7 @@
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb1, imaginary: bb5];
|
||||
- falseEdge -> [real: bb1, imaginary: bb1];
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb2];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
@ -60,11 +60,11 @@
|
||||
}
|
||||
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb2];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
- falseEdge -> [real: bb8, imaginary: bb5];
|
||||
- falseEdge -> [real: bb8, imaginary: bb1];
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
@ -127,7 +127,7 @@
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb1, imaginary: bb5];
|
||||
- falseEdge -> [real: bb1, imaginary: bb1];
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb2];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user