mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Always set otherwise_block
s
This commit is contained in:
parent
e74b30e3a9
commit
5fe2ca65cf
@ -1074,12 +1074,9 @@ struct Candidate<'pat, 'tcx> {
|
|||||||
// because that would break binding consistency.
|
// because that would break binding consistency.
|
||||||
subcandidates: Vec<Candidate<'pat, 'tcx>>,
|
subcandidates: Vec<Candidate<'pat, 'tcx>>,
|
||||||
|
|
||||||
/// ...and the guard must be evaluated if there is one.
|
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
|
||||||
has_guard: bool,
|
has_guard: bool,
|
||||||
|
|
||||||
/// If the guard is `false` then branch to `otherwise_block`.
|
|
||||||
otherwise_block: Option<BasicBlock>,
|
|
||||||
|
|
||||||
/// If the candidate matches, bindings and ascriptions must be established.
|
/// If the candidate matches, bindings and ascriptions must be established.
|
||||||
extra_data: PatternExtraData<'tcx>,
|
extra_data: PatternExtraData<'tcx>,
|
||||||
|
|
||||||
@ -1090,6 +1087,9 @@ struct Candidate<'pat, 'tcx> {
|
|||||||
/// The block before the `bindings` have been established.
|
/// The block before the `bindings` have been established.
|
||||||
pre_binding_block: Option<BasicBlock>,
|
pre_binding_block: Option<BasicBlock>,
|
||||||
|
|
||||||
|
/// The block to branch to if the guard or a nested candidate fails to match.
|
||||||
|
otherwise_block: Option<BasicBlock>,
|
||||||
|
|
||||||
/// The earliest block that has only candidates >= this one as descendents. Used for false
|
/// The earliest block that has only candidates >= this one as descendents. Used for false
|
||||||
/// edges, see the doc for [`Builder::match_expr`].
|
/// edges, see the doc for [`Builder::match_expr`].
|
||||||
false_edge_start_block: Option<BasicBlock>,
|
false_edge_start_block: Option<BasicBlock>,
|
||||||
@ -1500,11 +1500,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
candidate.pre_binding_block = Some(start_block);
|
candidate.pre_binding_block = Some(start_block);
|
||||||
let otherwise_block = self.cfg.start_new_block();
|
let otherwise_block = self.cfg.start_new_block();
|
||||||
if candidate.has_guard {
|
|
||||||
// Create the otherwise block for this candidate, which is the
|
// Create the otherwise block for this candidate, which is the
|
||||||
// pre-binding block for the next candidate.
|
// pre-binding block for the next candidate.
|
||||||
candidate.otherwise_block = Some(otherwise_block);
|
candidate.otherwise_block = Some(otherwise_block);
|
||||||
}
|
|
||||||
otherwise_block
|
otherwise_block
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1591,10 +1589,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
assert!(leaf_candidate.match_pairs.is_empty());
|
assert!(leaf_candidate.match_pairs.is_empty());
|
||||||
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
|
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
|
||||||
let or_start = leaf_candidate.pre_binding_block.unwrap();
|
let or_start = leaf_candidate.pre_binding_block.unwrap();
|
||||||
// In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b,
|
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
|
||||||
// c | d)` will fail too. If there is no guard, we skip testing of `b` by branching
|
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
|
||||||
// directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`.
|
// directly to `remainder_start`. If there is a guard, `or_otherwise` can be reached
|
||||||
let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start);
|
// by guard failure as well, so we can't skip `Q`.
|
||||||
|
let or_otherwise = if leaf_candidate.has_guard {
|
||||||
|
leaf_candidate.otherwise_block.unwrap()
|
||||||
|
} else {
|
||||||
|
remainder_start
|
||||||
|
};
|
||||||
self.test_candidates_with_or(
|
self.test_candidates_with_or(
|
||||||
span,
|
span,
|
||||||
scrutinee_span,
|
scrutinee_span,
|
||||||
@ -1669,6 +1672,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
|
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
|
||||||
});
|
});
|
||||||
if can_merge {
|
if can_merge {
|
||||||
|
let mut last_otherwise = None;
|
||||||
let any_matches = self.cfg.start_new_block();
|
let any_matches = self.cfg.start_new_block();
|
||||||
let or_span = candidate.or_span.take().unwrap();
|
let or_span = candidate.or_span.take().unwrap();
|
||||||
let source_info = self.source_info(or_span);
|
let source_info = self.source_info(or_span);
|
||||||
@ -1679,8 +1683,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
for subcandidate in mem::take(&mut candidate.subcandidates) {
|
for subcandidate in mem::take(&mut candidate.subcandidates) {
|
||||||
let or_block = subcandidate.pre_binding_block.unwrap();
|
let or_block = subcandidate.pre_binding_block.unwrap();
|
||||||
self.cfg.goto(or_block, source_info, any_matches);
|
self.cfg.goto(or_block, source_info, any_matches);
|
||||||
|
last_otherwise = subcandidate.otherwise_block;
|
||||||
}
|
}
|
||||||
candidate.pre_binding_block = Some(any_matches);
|
candidate.pre_binding_block = Some(any_matches);
|
||||||
|
assert!(last_otherwise.is_some());
|
||||||
|
candidate.otherwise_block = last_otherwise;
|
||||||
} else {
|
} else {
|
||||||
// Never subcandidates may have a set of bindings inconsistent with their siblings,
|
// Never subcandidates may have a set of bindings inconsistent with their siblings,
|
||||||
// which would break later code. So we filter them out. Note that we can't filter out
|
// which would break later code. So we filter them out. Note that we can't filter out
|
||||||
|
Loading…
Reference in New Issue
Block a user