Clean up MIR match lowering

* Adjust fake borrows to only be live over guards.
* Remove unused `slice_len_checked` field.
* Split the methods on builder into those for matches and those for all
  kinds of pattern bindings.
This commit is contained in:
Matthew Jasper 2019-02-02 10:56:55 +00:00
parent c15437c0c6
commit d51b5cdd82
7 changed files with 874 additions and 840 deletions

File diff suppressed because it is too large Load Diff

View File

@ -69,8 +69,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
PatternKind::Slice { ref prefix, ref slice, ref suffix }
if !match_pair.slice_len_checked => {
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
let len = prefix.len() + suffix.len();
let op = if slice.is_some() {
BinOp::Ge
@ -85,7 +84,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
PatternKind::AscribeUserType { .. } |
PatternKind::Array { .. } |
PatternKind::Slice { .. } |
PatternKind::Wild |
PatternKind::Binding { .. } |
PatternKind::Leaf { .. } |
@ -433,59 +431,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
target_block
}
/// Given that we are performing `test` against `test_place`,
/// this job sorts out what the status of `candidate` will be
/// after the test. The `resulting_candidates` vector stores, for
/// each possible outcome of `test`, a vector of the candidates
/// that will result. This fn should add a (possibly modified)
/// clone of candidate into `resulting_candidates` wherever
/// appropriate.
/// Given that we are performing `test` against `test_place`, this job
/// sorts out what the status of `candidate` will be after the test. See
/// `test_candidates` for the usage of this function. The returned index is
/// the index that this candiate should be placed in the
/// `target_candidates` vec. The candidate may be modified to update its
/// `match_pairs`.
///
/// So, for example, if this candidate is `x @ Some(P0)` and the
/// Tests is a variant test, then we would add `(x as Option).0 @
/// P0` to the `resulting_candidates` entry corresponding to the
/// variant `Some`.
/// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
/// a variant test, then we would modify the candidate to be `(x as
/// Option).0 @ P0` and return the index corresponding to the variant
/// `Some`.
///
/// However, in some cases, the test may just not be relevant to
/// candidate. For example, suppose we are testing whether `foo.x == 22`,
/// but in one match arm we have `Foo { x: _, ... }`... in that case,
/// the test for what value `x` has has no particular relevance
/// to this candidate. In such cases, this function just returns false
/// without doing anything. This is used by the overall `match_candidates`
/// algorithm to structure the match as a whole. See `match_candidates` for
/// more details.
/// However, in some cases, the test may just not be relevant to candidate.
/// For example, suppose we are testing whether `foo.x == 22`, but in one
/// match arm we have `Foo { x: _, ... }`... in that case, the test for
/// what value `x` has has no particular relevance to this candidate. In
/// such cases, this function just returns None without doing anything.
/// This is used by the overall `match_candidates` algorithm to structure
/// the match as a whole. See `match_candidates` for more details.
///
/// FIXME(#29623). In some cases, we have some tricky choices to
/// make. for example, if we are testing that `x == 22`, but the
/// candidate is `x @ 13..55`, what should we do? In the event
/// that the test is true, we know that the candidate applies, but
/// in the event of false, we don't know that it *doesn't*
/// apply. For now, we return false, indicate that the test does
/// not apply to this candidate, but it might be we can get
/// FIXME(#29623). In some cases, we have some tricky choices to make. for
/// example, if we are testing that `x == 22`, but the candidate is `x @
/// 13..55`, what should we do? In the event that the test is true, we know
/// that the candidate applies, but in the event of false, we don't know
/// that it *doesn't* apply. For now, we return false, indicate that the
/// test does not apply to this candidate, but it might be we can get
/// tighter match code if we do something a bit different.
pub fn sort_candidate<'pat>(&mut self,
test_place: &Place<'tcx>,
test: &Test<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>])
-> bool {
pub fn sort_candidate<'pat, 'cand>(
&mut self,
test_place: &Place<'tcx>,
test: &Test<'tcx>,
candidate: &mut Candidate<'pat, 'tcx>,
) -> Option<usize> {
// Find the match_pair for this place (if any). At present,
// afaik, there can be at most one. (In the future, if we
// adopted a more general `@` operator, there might be more
// than one, but it'd be very unusual to have two sides that
// both require tests; you'd expect one side to be simplified
// away.)
let tested_match_pair = candidate.match_pairs.iter()
.enumerate()
.find(|&(_, mp)| mp.place == *test_place);
let (match_pair_index, match_pair) = match tested_match_pair {
Some(pair) => pair,
None => {
// We are not testing this place. Therefore, this
// candidate applies to ALL outcomes.
return false;
}
};
let (match_pair_index, match_pair) = candidate.match_pairs
.iter()
.enumerate()
.find(|&(_, mp)| mp.place == *test_place)?;
match (&test.kind, &*match_pair.pattern.kind) {
// If we are performing a variant switch, then this
@ -493,17 +481,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(&TestKind::Switch { adt_def: tested_adt_def, .. },
&PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
assert_eq!(adt_def, tested_adt_def);
let new_candidate =
self.candidate_after_variant_switch(match_pair_index,
adt_def,
variant_index,
subpatterns,
candidate);
resulting_candidates[variant_index.as_usize()].push(new_candidate);
true
self.candidate_after_variant_switch(match_pair_index,
adt_def,
variant_index,
subpatterns,
candidate);
Some(variant_index.as_usize())
}
(&TestKind::Switch { .. }, _) => false,
(&TestKind::Switch { .. }, _) => None,
// If we are performing a switch over integers, then this informs integer
// equality, but nothing else.
@ -514,10 +500,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
&PatternKind::Constant { ref value })
if is_switch_ty(match_pair.pattern.ty) => {
let index = indices[value];
let new_candidate = self.candidate_without_match_pair(match_pair_index,
candidate);
resulting_candidates[index].push(new_candidate);
true
self.candidate_without_match_pair(match_pair_index, candidate);
Some(index)
}
(&TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
@ -530,14 +514,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// No switch values are contained in the pattern range,
// so the pattern can be matched only if this test fails.
let otherwise = options.len();
resulting_candidates[otherwise].push(candidate.clone());
true
Some(otherwise)
} else {
false
None
}
}
(&TestKind::SwitchInt { .. }, _) => false,
(&TestKind::SwitchInt { .. }, _) => None,
(&TestKind::Len { len: test_len, op: BinOp::Eq },
&PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
@ -546,32 +529,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(Ordering::Equal, &None) => {
// on true, min_len = len = $actual_length,
// on false, len != $actual_length
resulting_candidates[0].push(
self.candidate_after_slice_test(match_pair_index,
candidate,
prefix,
slice.as_ref(),
suffix)
);
true
self.candidate_after_slice_test(match_pair_index,
candidate,
prefix,
slice.as_ref(),
suffix);
Some(0)
}
(Ordering::Less, _) => {
// test_len < pat_len. If $actual_len = test_len,
// then $actual_len < pat_len and we don't have
// enough elements.
resulting_candidates[1].push(candidate.clone());
true
Some(1)
}
(Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
// This can match both if $actual_len = test_len >= pat_len,
// and if $actual_len > test_len. We can't advance.
false
None
}
(Ordering::Greater, &None) => {
// test_len != pat_len, so if $actual_len = test_len, then
// $actual_len != pat_len.
resulting_candidates[1].push(candidate.clone());
true
Some(1)
}
}
}
@ -584,32 +563,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(Ordering::Equal, &Some(_)) => {
// $actual_len >= test_len = pat_len,
// so we can match.
resulting_candidates[0].push(
self.candidate_after_slice_test(match_pair_index,
candidate,
prefix,
slice.as_ref(),
suffix)
);
true
self.candidate_after_slice_test(match_pair_index,
candidate,
prefix,
slice.as_ref(),
suffix);
Some(0)
}
(Ordering::Less, _) | (Ordering::Equal, &None) => {
// test_len <= pat_len. If $actual_len < test_len,
// then it is also < pat_len, so the test passing is
// necessary (but insufficient).
resulting_candidates[0].push(candidate.clone());
true
Some(0)
}
(Ordering::Greater, &None) => {
// test_len > pat_len. If $actual_len >= test_len > pat_len,
// then we know we won't have a match.
resulting_candidates[1].push(candidate.clone());
true
Some(1)
}
(Ordering::Greater, &Some(_)) => {
// test_len < pat_len, and is therefore less
// strict. This can still go both ways.
false
None
}
}
}
@ -617,12 +592,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(&TestKind::Range(test),
&PatternKind::Range(pat)) => {
if test == pat {
resulting_candidates[0]
.push(self.candidate_without_match_pair(
match_pair_index,
candidate,
));
return true;
self.candidate_without_match_pair(
match_pair_index,
candidate,
);
return Some(0);
}
let no_overlap = (|| {
@ -649,10 +623,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if no_overlap == Some(true) {
// Testing range does not overlap with pattern range,
// so the pattern can be matched only if this test fails.
resulting_candidates[1].push(candidate.clone());
true
Some(1)
} else {
false
None
}
}
@ -660,15 +633,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if self.const_range_contains(range, value) == Some(false) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
resulting_candidates[1].push(candidate.clone());
true
Some(1)
} else {
false
None
}
}
(&TestKind::Range { .. }, _) => false,
(&TestKind::Range { .. }, _) => None,
(&TestKind::Eq { .. }, _) |
(&TestKind::Len { .. }, _) => {
@ -677,73 +648,53 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// FIXME(#29623) we can be more clever here
let pattern_test = self.test(&match_pair);
if pattern_test.kind == test.kind {
let new_candidate = self.candidate_without_match_pair(match_pair_index,
candidate);
resulting_candidates[0].push(new_candidate);
true
self.candidate_without_match_pair(match_pair_index, candidate);
Some(0)
} else {
false
None
}
}
}
}
fn candidate_without_match_pair<'pat>(&mut self,
match_pair_index: usize,
candidate: &Candidate<'pat, 'tcx>)
-> Candidate<'pat, 'tcx> {
let other_match_pairs =
candidate.match_pairs.iter()
.enumerate()
.filter(|&(index, _)| index != match_pair_index)
.map(|(_, mp)| mp.clone())
.collect();
Candidate {
span: candidate.span,
match_pairs: other_match_pairs,
bindings: candidate.bindings.clone(),
ascriptions: candidate.ascriptions.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
pat_index: candidate.pat_index,
pre_binding_block: candidate.pre_binding_block,
next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
}
fn candidate_without_match_pair(
&mut self,
match_pair_index: usize,
candidate: &mut Candidate<'_, 'tcx>,
) {
candidate.match_pairs.remove(match_pair_index);
}
fn candidate_after_slice_test<'pat>(&mut self,
match_pair_index: usize,
candidate: &Candidate<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>,
prefix: &'pat [Pattern<'tcx>],
opt_slice: Option<&'pat Pattern<'tcx>>,
suffix: &'pat [Pattern<'tcx>])
-> Candidate<'pat, 'tcx> {
let mut new_candidate =
self.candidate_without_match_pair(match_pair_index, candidate);
suffix: &'pat [Pattern<'tcx>]) {
let removed_place = candidate.match_pairs.remove(match_pair_index).place;
self.prefix_slice_suffix(
&mut new_candidate.match_pairs,
&candidate.match_pairs[match_pair_index].place,
&mut candidate.match_pairs,
&removed_place,
prefix,
opt_slice,
suffix);
new_candidate
}
fn candidate_after_variant_switch<'pat>(&mut self,
match_pair_index: usize,
adt_def: &'tcx ty::AdtDef,
variant_index: VariantIdx,
subpatterns: &'pat [FieldPattern<'tcx>],
candidate: &Candidate<'pat, 'tcx>)
-> Candidate<'pat, 'tcx> {
let match_pair = &candidate.match_pairs[match_pair_index];
fn candidate_after_variant_switch<'pat>(
&mut self,
match_pair_index: usize,
adt_def: &'tcx ty::AdtDef,
variant_index: VariantIdx,
subpatterns: &'pat [FieldPattern<'tcx>],
candidate: &mut Candidate<'pat, 'tcx>,
) {
let match_pair = candidate.match_pairs.remove(match_pair_index);
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
let elem = ProjectionElem::Downcast(adt_def, variant_index);
let downcast_place = match_pair.place.clone().elem(elem); // `(x as Variant)`
let downcast_place = match_pair.place.elem(elem); // `(x as Variant)`
let consequent_match_pairs =
subpatterns.iter()
.map(|subpattern| {
@ -754,26 +705,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
MatchPair::new(place, &subpattern.pattern)
});
// In addition, we need all the other match pairs from the old candidate.
let other_match_pairs =
candidate.match_pairs.iter()
.enumerate()
.filter(|&(index, _)| index != match_pair_index)
.map(|(_, mp)| mp.clone());
let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect();
Candidate {
span: candidate.span,
match_pairs: all_match_pairs,
bindings: candidate.bindings.clone(),
ascriptions: candidate.ascriptions.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
pat_index: candidate.pat_index,
pre_binding_block: candidate.pre_binding_block,
next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
}
candidate.match_pairs.extend(consequent_match_pairs);
}
fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {

View File

@ -72,7 +72,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
MatchPair {
place,
pattern,
slice_len_checked: false,
}
}
}

View File

@ -41,47 +41,47 @@ fn main() {
// StorageLive(_3);
// _3 = const true;
// FakeRead(ForMatchedPlace, _3);
// switchInt(_3) -> [false: bb11, otherwise: bb10];
// switchInt(_3) -> [false: bb9, otherwise: bb8];
// }
// bb4: {
// resume;
// }
// bb5: {
// _2 = const 4i32;
// goto -> bb14;
// falseEdges -> [real: bb12, imaginary: bb6];
// }
// bb6: {
// _0 = ();
// goto -> bb15;
// falseEdges -> [real: bb14, imaginary: bb7];
// }
// bb7: {
// falseEdges -> [real: bb12, imaginary: bb8];
// }
// bb8: {
// falseEdges -> [real: bb13, imaginary: bb9];
// }
// bb9: {
// unreachable;
// }
// bb10: {
// goto -> bb8;
// }
// bb11: {
// goto -> bb7;
// }
// bb12: {
// goto -> bb5;
// }
// bb13: {
// bb8: {
// goto -> bb6;
// }
// bb14: {
// bb9: {
// goto -> bb5;
// }
// bb10: {
// FakeRead(ForLet, _2);
// StorageDead(_3);
// StorageLive(_6);
// _6 = &_2;
// _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4];
// }
// bb11: {
// _2 = const 4i32;
// goto -> bb10;
// }
// bb12: {
// goto -> bb11;
// }
// bb13: {
// _0 = ();
// goto -> bb15;
// }
// bb14: {
// goto -> bb13;
// }
// bb15: {
// StorageDead(_3);
// goto -> bb16;
@ -96,7 +96,7 @@ fn main() {
// }
// bb18: {
// StorageDead(_4);
// goto -> bb14;
// goto -> bb10;
// }
// bb19: {
// StorageDead(_6);

View File

@ -44,73 +44,69 @@ fn main() {
// ...
// _2 = std::option::Option<i32>::Some(const 42i32,);
// FakeRead(ForMatchedPlace, _2);
// _7 = discriminant(_2);
// _9 = &shallow (promoted[2]: std::option::Option<i32>);
// _10 = &(((promoted[1]: std::option::Option<i32>) as Some).0: i32);
// switchInt(move _7) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
// _3 = discriminant(_2);
// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7];
// }
// bb1: {
// resume;
// }
// bb2: { // arm1
// _1 = (const 3i32, const 3i32);
// goto -> bb13;
// bb2: {
// falseEdges -> [real: bb9, imaginary: bb3]; //pre_binding1
// }
// bb3: { // binding3(empty) and arm3
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
// bb3: {
// falseEdges -> [real: bb12, imaginary: bb4]; //pre_binding2
// }
// bb4: {
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding2
// falseEdges -> [real: bb13, imaginary: bb5]; //pre_binding3
// }
// bb5: {
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
// }
// bb6: {
// unreachable;
// }
// bb6: { // to pre_binding2
// falseEdges -> [real: bb3, imaginary: bb3];
// }
// bb7: {
// unreachable;
// }
// bb8: { // binding1 and guard
// StorageLive(_5);
// _5 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
// StorageLive(_8);
// _8 = const guard() -> [return: bb9, unwind: bb1];
// }
// bb9: {
// switchInt(move _8) -> [false: bb10, otherwise: bb11];
// }
// bb10: { // to pre_binding2
// falseEdges -> [real: bb4, imaginary: bb4];
// }
// bb11: { // bindingNoLandingPads.before.mir2 and arm2
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// StorageLive(_11);
// _11 = _3;
// _1 = (const 1i32, move _11);
// StorageDead(_11);
// goto -> bb13;
// }
// bb12: {
// StorageLive(_6);
// _6 = ((_2 as Some).0: i32);
// StorageLive(_12);
// _12 = _6;
// _1 = (const 2i32, move_12);
// StorageDead(_12);
// goto -> bb13;
// }
// bb13: {
// bb8: {
// ...
// return;
// }
// bb9: { // binding1 and guard
// StorageLive(_8);
// _8 = &(((promoted[2]: std::option::Option<i32>) as Some).0: i32);
// _4 = &shallow (promoted[1]: std::option::Option<i32>);
// _5 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
// StorageLive(_9);
// _9 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: {
// FakeRead(ForMatchGuard, _4);
// FakeRead(ForMatchGuard, _5);
// switchInt(move _9) -> [false: bb6, otherwise: bb11];
// }
// bb11: {
// StorageLive(_6);
// _6 = ((_2 as Some).0: i32);
// StorageLive(_10);
// _10 = _6;
// _1 = (const 1i32, move _10);
// StorageDead(_10);
// goto -> bb8;
// }
// bb12: {
// StorageLive(_11);
// _11 = ((_2 as Some).0: i32);
// StorageLive(_12);
// _12 = _11;
// _1 = (const 2i32, move _12);
// StorageDead(_12);
// goto -> bb8;
// }
// bb13: {
// _1 = (const 3i32, const 3i32);
// goto -> bb8;
// }
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//
// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
@ -118,164 +114,158 @@ fn main() {
// ...
// _2 = std::option::Option<i32>::Some(const 42i32,);
// FakeRead(ForMatchedPlace, _2);
// _7 = discriminant(_2);
// _9 = &shallow _2;
// _10 = &((_2 as Some).0: i32);
// switchInt(move _7) -> [0isize: bb4, 1isize: bb3, otherwise: bb7];
// _3 = discriminant(_2);
// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7];
// }
// bb1: {
// resume;
// }
// bb2: { // arm2
// _1 = (const 3i32, const 3i32);
// goto -> bb13;
// bb2: {
// falseEdges -> [real: bb9, imaginary: bb3];
// }
// bb3: {
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
// falseEdges -> [real: bb12, imaginary: bb4];
// }
// bb4: {
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
// falseEdges -> [real: bb13, imaginary: bb5];
// }
// bb5: {
// FakeRead(ForMatchGuard, _9);
// FakeRead(ForMatchGuard, _10);
// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
// }
// bb6: {
// unreachable;
// }
// bb6: { // to pre_binding3 (can skip 2 since this is `Some`)
// falseEdges -> [real: bb4, imaginary: bb3];
// }
// bb7: {
// unreachable;
// }
// bb8: { // binding1 and guard
// StorageLive(_5);
// _5 = &((_2 as Some).0: i32);
// StorageLive(_8);
// _8 = const guard() -> [return: bb9, unwind: bb1];
// }
// bb9: { // end of guard
// switchInt(move _8) -> [false: bb10, otherwise: bb11];
// }
// bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
// falseEdges -> [real: bb5, imaginary: bb4];
// }
// bb11: { // arm1
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// StorageLive(_11);
// _11 = _3;
// _1 = (const 1i32, move _11);
// StorageDead(_11);
// goto -> bb13;
// }
// bb12: { // binding3 and arm3
// StorageLive(_6);
// _6 = ((_2 as Some).0: i32);
// StorageLive(_12);
// _12 = _6;
// _1 = (const 2i32, move _12);
// StorageDead(_12);
// goto -> bb13;
// }
// bb13: {
// bb8: {
// ...
// return;
// }
// bb9: { // binding1 and guard
// StorageLive(_8);
// _8 = &((_2 as Some).0: i32);
// _4 = &shallow _2;
// _5 = &((_2 as Some).0: i32);
// StorageLive(_9);
// _9 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { // end of guard
// FakeRead(ForMatchGuard, _4);
// FakeRead(ForMatchGuard, _5);
// switchInt(move _9) -> [false: bb6, otherwise: bb11];
// }
// bb11: { // arm1
// StorageLive(_6);
// _6 = ((_2 as Some).0: i32);
// StorageLive(_10);
// _10 = _6;
// _1 = (const 1i32, move _10);
// StorageDead(_10);
// goto -> bb8;
// }
// bb12: { // arm2
// _1 = (const 3i32, const 3i32);
// goto -> bb8;
// }
// bb13: { // binding3 and arm3
// StorageLive(_11);
// _11 = ((_2 as Some).0: i32);
// StorageLive(_12);
// _12 = _11;
// _1 = (const 2i32, move _12);
// StorageDead(_12);
// goto -> bb8;
// }
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//
// START rustc.main.QualifyAndPromoteConstants.before.mir
// bb0: {
// ...
// _2 = std::option::Option<i32>::Some(const 1i32,);
// FakeRead(ForMatchedPlace, _2);
// _11 = discriminant(_2);
// _16 = &shallow _2;
// _17 = &((_2 as Some).0: i32);
// switchInt(move _11) -> [1isize: bb2, otherwise: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// FakeRead(ForMatchGuard, _16);
// FakeRead(ForMatchGuard, _17);
// falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
// }
// bb3: {
// FakeRead(ForMatchGuard, _16);
// FakeRead(ForMatchGuard, _17);
// falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
// }
// bb4: {
// FakeRead(ForMatchGuard, _16);
// FakeRead(ForMatchGuard, _17);
// falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3
// }
// bb5: {
// FakeRead(ForMatchGuard, _16);
// FakeRead(ForMatchGuard, _17);
// falseEdges -> [real: bb16, imaginary: bb6]; //pre_binding4
// }
// bb6: {
// unreachable;
// }
// bb7: { // binding1: Some(w) if guard()
// StorageLive(_5);
// _5 = &((_2 as Some).0: i32);
// StorageLive(_12);
// _12 = const guard() -> [return: bb8, unwind: bb1];
// }
// bb8: { //end of guard
// switchInt(move _12) -> [false: bb9, otherwise: bb10];
// }
// bb9: { // to pre_binding2
// falseEdges -> [real: bb3, imaginary: bb3];
// }
// bb10: { // set up bindings for arm1
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// _1 = const 1i32;
// goto -> bb17;
// }
// bb11: { // binding2 & arm2
// StorageLive(_6);
// _6 = _2;
// _1 = const 2i32;
// goto -> bb17;
// }
// bb12: { // binding3: Some(y) if guard2(y)
// StorageLive(_9);
// _9 = &((_2 as Some).0: i32);
// StorageLive(_14);
// StorageLive(_15);
// _15 = (*_9);
// _14 = const guard2(move _15) -> [return: bb13, unwind: bb1];
// }
// bb13: { // end of guard2
// StorageDead(_15);
// switchInt(move _14) -> [false: bb14, otherwise: bb15];
// }
// bb14: { // to pre_binding4
// falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb15: { // set up bindings for arm3
// StorageLive(_7);
// _7 = ((_2 as Some).0: i32);
// _1 = const 3i32;
// goto -> bb17;
// }
// bb16: { // binding4 & arm4
// StorageLive(_10);
// _10 = _2;
// _1 = const 4i32;
// goto -> bb17;
// }
// bb17: {
// ...
// return;
// }
// _2 = std::option::Option<i32>::Some(const 1i32,);
// FakeRead(ForMatchedPlace, _2);
// _3 = discriminant(_2);
// switchInt(move _3) -> [1isize: bb2, otherwise: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// falseEdges -> [real: bb10, imaginary: bb3]; //pre_binding1
// }
// bb3: {
// falseEdges -> [real: bb13, imaginary: bb4]; //pre_binding2
// }
// bb4: {
// falseEdges -> [real: bb14, imaginary: bb5]; //pre_binding3
// }
// bb5: {
// falseEdges -> [real: bb17, imaginary: bb6]; //pre_binding4
// }
// bb6: {
// unreachable;
// }
// bb7: { // to pre_binding2
// falseEdges -> [real: bb3, imaginary: bb3];
// }
// bb8: { // to pre_binding4
// falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb9: {
// ...
// return;
// }
// bb10: { // binding1: Some(w) if guard()
// StorageLive(_9);
// _9 = &((_2 as Some).0: i32);
// _5 = &shallow _2;
// _6 = &((_2 as Some).0: i32);
// StorageLive(_10);
// _10 = const guard() -> [return: bb11, unwind: bb1];
// }
// bb11: { //end of guard
// FakeRead(ForMatchGuard, _5);
// FakeRead(ForMatchGuard, _6);
// switchInt(move _10) -> [false: bb7, otherwise: bb12];
// }
// bb12: { // set up bindings for arm1
// StorageLive(_7);
// _7 = ((_2 as Some).0: i32);
// _1 = const 1i32;
// goto -> bb9;
// }
// bb13: { // binding2 & arm2
// StorageLive(_11);
// _11 = _2;
// _1 = const 2i32;
// goto -> bb9;
// }
// bb14: { // binding3: Some(y) if guard2(y)
// StorageLive(_14);
// _14 = &((_2 as Some).0: i32);
// _5 = &shallow _2;
// _6 = &((_2 as Some).0: i32);
// StorageLive(_15);
// StorageLive(_16);
// _16 = (*_14);
// _15 = const guard2(move _16) -> [return: bb15, unwind: bb1];
// }
// bb15: { // end of guard2
// StorageDead(_16);
// FakeRead(ForMatchGuard, _5);
// FakeRead(ForMatchGuard, _6);
// switchInt(move _15) -> [false: bb8, otherwise: bb16];
// }
// bb16: { // binding4 & arm4
// StorageLive(_12);
// _12 = ((_2 as Some).0: i32);
// _1 = const 3i32;
// goto -> bb9;
// }
// bb17: {
// StorageLive(_17);
// _17 = _2;
// _1 = const 4i32;
// goto -> bb9;
// }
// END rustc.main.QualifyAndPromoteConstants.before.mir

View File

@ -20,66 +20,67 @@ fn main() {
// START rustc.main.SimplifyCfg-initial.after.mir
// bb0: {
// ...
// _4 = Le(const 0i32, _1);
// switchInt(move _4) -> [false: bb10, otherwise: bb11];
// switchInt(move _4) -> [false: bb7, otherwise: bb8];
// }
// bb1: {
// _3 = const 0i32;
// goto -> bb16;
// falseEdges -> [real: bb13, imaginary: bb2];
// }
// bb2: {
// _3 = const 1i32;
// goto -> bb16;
// falseEdges -> [real: bb14, imaginary: bb3];
// }
// bb3: {
// _3 = const 2i32;
// goto -> bb16;
// falseEdges -> [real: bb15, imaginary: bb4];
// }
// bb4: {
// _3 = const 3i32;
// goto -> bb16;
// falseEdges -> [real: bb16, imaginary: bb5];
// }
// bb5: {
// falseEdges -> [real: bb12, imaginary: bb6];
// }
// bb6: {
// falseEdges -> [real: bb2, imaginary: bb7];
// }
// bb7: {
// falseEdges -> [real: bb3, imaginary: bb8];
// }
// bb8: {
// falseEdges -> [real: bb4, imaginary: bb9];
// }
// bb9: {
// unreachable;
// }
// bb6: {
// falseEdges -> [real: bb4, imaginary: bb2];
// }
// bb7: {
// _6 = Le(const 10i32, _1);
// switchInt(move _6) -> [false: bb9, otherwise: bb10];
// }
// bb8: {
// _5 = Lt(_1, const 10i32);
// switchInt(move _5) -> [false: bb7, otherwise: bb1];
// }
// bb9: {
// switchInt(_1) -> [-1i32: bb3, otherwise: bb4];
// }
// bb10: {
// _7 = Le(const 10i32, _1);
// switchInt(move _7) -> [false: bb14, otherwise: bb15];
// _7 = Le(_1, const 20i32);
// switchInt(move _7) -> [false: bb9, otherwise: bb2];
// }
// bb11: {
// _5 = Lt(_1, const 10i32);
// switchInt(move _5) -> [false: bb10, otherwise: bb5];
// }
// bb12: {
// StorageLive(_6);
// _6 = _2;
// switchInt(move _6) -> [false: bb13, otherwise: bb1];
// }
// bb13: {
// falseEdges -> [real: bb8, imaginary: bb6];
// }
// bb14: {
// switchInt(_1) -> [-1i32: bb7, otherwise: bb8];
// }
// bb15: {
// _8 = Le(_1, const 20i32);
// switchInt(move _8) -> [false: bb14, otherwise: bb6];
// }
// bb16: {
// StorageDead(_6);
// ...
// StorageDead(_8);
// _0 = ();
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// bb12: {
// _3 = const 0i32;
// goto -> bb11;
// }
// bb13: {
// StorageLive(_8);
// _8 = _2;
// switchInt(move _8) -> [false: bb6, otherwise: bb12];
// }
// bb14: {
// _3 = const 1i32;
// goto -> bb11;
// }
// bb15: {
// _3 = const 2i32;
// goto -> bb11;
// }
// bb16: {
// _3 = const 3i32;
// goto -> bb11;
// }
// END rustc.main.SimplifyCfg-initial.after.mir

View File

@ -4,15 +4,15 @@
#![feature(nll)]
fn match_guard(x: Option<&&i32>) -> i32 {
fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
match x {
Some(0) if true => 0,
Some(0) if c => 0,
_ => 1,
}
}
fn main() {
match_guard(None);
match_guard(None, true);
}
// END RUST SOURCE
@ -20,49 +20,48 @@ fn main() {
// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir
// bb0: {
// FakeRead(ForMatchedPlace, _1);
// _2 = discriminant(_1);
// _3 = &shallow _1;
// _4 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
// _5 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
// _6 = &shallow (*(*((_1 as Some).0: &'<empty> &'<empty> i32)));
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
// _3 = discriminant(_1);
// switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
// }
// bb1: {
// _0 = const 0i32;
// goto -> bb9;
// goto -> bb8;
// }
// bb2: {
// _0 = const 1i32;
// goto -> bb9;
// }
// bb3: {
// FakeRead(ForMatchGuard, _3);
// FakeRead(ForMatchGuard, _4);
// FakeRead(ForMatchGuard, _5);
// FakeRead(ForMatchGuard, _6);
// goto -> bb7;
// unreachable;
// }
// bb4: {
// FakeRead(ForMatchGuard, _3);
// FakeRead(ForMatchGuard, _4);
// FakeRead(ForMatchGuard, _5);
// FakeRead(ForMatchGuard, _6);
// goto -> bb2;
// }
// bb5: {
// unreachable;
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
// }
// bb6: {
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
// StorageDead(_8);
// return;
// }
// bb7: {
// goto -> bb1;
// _0 = const 0i32;
// goto -> bb6;
// }
// bb8: {
// goto -> bb4;
// _4 = &shallow _1;
// _5 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
// _6 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
// _7 = &shallow (*(*((_1 as Some).0: &'<empty> &'<empty> i32)));
// StorageLive(_8);
// _8 = _2;
// FakeRead(ForMatchGuard, _4);
// FakeRead(ForMatchGuard, _5);
// FakeRead(ForMatchGuard, _6);
// FakeRead(ForMatchGuard, _7);
// switchInt(move _8) -> [false: bb4, otherwise: bb7];
// }
// bb9: {
// return;
// _0 = const 1i32;
// goto -> bb6;
// }
// bb10: {
// resume;
@ -72,51 +71,50 @@ fn main() {
// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir
// bb0: {
// nop;
// _2 = discriminant(_1);
// nop;
// nop;
// nop;
// nop;
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
// _3 = discriminant(_1);
// switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
// }
// bb1: {
// _0 = const 0i32;
// goto -> bb9;
// goto -> bb8;
// }
// bb2: {
// _0 = const 1i32;
// goto -> bb9;
// }
// bb3: {
// nop;
// nop;
// nop;
// nop;
// goto -> bb7;
// unreachable;
// }
// bb4: {
// nop;
// nop;
// nop;
// nop;
// goto -> bb2;
// }
// bb5: {
// unreachable;
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
// }
// bb6: {
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
// StorageDead(_8);
// return;
// }
// bb7: {
// goto -> bb1;
// _0 = const 0i32;
// goto -> bb6;
// }
// bb8: {
// goto -> bb4;
// nop;
// nop;
// nop;
// nop;
// StorageLive(_8);
// _8 = _2;
// nop;
// nop;
// nop;
// nop;
// switchInt(move _8) -> [false: bb4, otherwise: bb7];
// }
// bb9: {
// return;
// _0 = const 1i32;
// goto -> bb6;
// }
// bb10: {
// resume;
// }
// }
// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir