]> git.lizzy.rs Git - rust.git/commitdiff
Clean up MIR match lowering
authorMatthew Jasper <mjjasper1@gmail.com>
Sat, 2 Feb 2019 10:56:55 +0000 (10:56 +0000)
committerMatthew Jasper <mjjasper1@gmail.com>
Thu, 21 Feb 2019 19:03:34 +0000 (19:03 +0000)
* 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.

src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/matches/util.rs
src/test/mir-opt/issue-49232.rs
src/test/mir-opt/match_false_edges.rs
src/test/mir-opt/match_test.rs
src/test/mir-opt/remove_fake_borrows.rs

index 96d2c90345933d7487bb101f5e95286dec6fdd35..a287659ec8e60b1e8da44288620e631390e2b007 100644 (file)
@@ -1,7 +1,9 @@
-//! Code related to match expressions. These are sufficiently complex
-//! to warrant their own module and submodules. :) This main module
-//! includes the high-level algorithm, the submodules contain the
-//! details.
+//! Code related to match expressions. These are sufficiently complex to
+//! warrant their own module and submodules. :) This main module includes the
+//! high-level algorithm, the submodules contain the details.
+//!
+//! This also includes code for pattern bindings in `let` statements and
+//! function parameters.
 
 use crate::build::scope::{CachedBlock, DropKind};
 use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
 
 use std::convert::TryFrom;
 
-/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
-/// a match arm has a guard expression attached to it.
-#[derive(Copy, Clone, Debug)]
-pub(crate) struct ArmHasGuard(pub bool);
-
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
+    /// Generates MIR for a `match` expression.
+    ///
+    /// The MIR that we generate for a match looks like this.
+    ///
+    /// ```text
+    /// [ 0. Pre-match ]
+    ///        |
+    /// [ 1. Evaluate Scrutinee]
+    /// [ (fake read of scrutinee) ]
+    ///        |
+    /// [ 2. Decision tree -- check discriminants ] <--------+
+    ///        |                                             |
+    ///        | (once a specific arm is chosen)             |
+    ///        |                                             |
+    /// [pre_binding_block]                           [otherwise_block]
+    ///        |                                             |
+    /// [ 3. Create "guard bindings" for arm ]               |
+    /// [ (create fake borrows) ]                            |
+    ///        |                                             |
+    /// [ 4. Execute guard code ]                            |
+    /// [ (read fake borrows) ] --(guard is false)-----------+
+    ///        |
+    ///        | (guard results in true)
+    ///        |
+    /// [ 5. Create real bindings and execute arm ]
+    ///        |
+    /// [ Exit match ]
+    /// ```
+    ///
+    /// All of the different arms have been stacked on top of each other to
+    /// simplify the diagram. For an arm with no guard the blocks marked 3 and
+    /// 4 and the fake borrows are omitted.
+    ///
+    /// We generate MIR in the following steps:
+    ///
+    /// 1. Evaluate the scrutinee and add the fake read of it.
+    /// 2. Create the prebinding and otherwise blocks.
+    /// 3. Create the decision tree and record the places that we bind or test.
+    /// 4. Determine the fake borrows that are needed from the above places.
+    ///    Create the required temporaries for them.
+    /// 5. Create everything else: Create everything else: the guards and the
+    ///    arms.
+    ///
+    /// ## Fake Reads and borrows
+    ///
+    /// Match exhaustiveness checking is no able to handle the case where the
+    /// place being matched on is mutated in the guards. There is an AST check
+    /// that tries to stop this but it is buggy and overly restrictive. Instead
+    /// we add "fake borrows" to the guards that prevent any mutation of the
+    /// place being matched. There are a some subtleties:
+    ///
+    /// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared
+    ///    refence, the borrow isn't even tracked. As such we have to add fake
+    ///    borrows of any prefixes of a place
+    /// 2. We don't want `match x { _ => (), }` to conflict with mutable
+    ///    borrows of `x`, so we only add fake borrows for places which are
+    ///    bound or tested by the match.
+    /// 3. We don't want the fake borrows to conflict with `ref mut` bindings,
+    ///    so we lower `ref mut` bindings as two-phase borrows for the guard.
+    /// 4. The fake borrows may be of places in inactive variants, so it would
+    ///    be UB to generate code for them. They therefore have to be removed
+    ///    by a MIR pass run after borrow checking.
+    ///
+    /// ## False edges
+    ///
+    /// We don't want to have the exact structure of the decision tree be
+    /// visible through borrow checking. False edges ensure that the CFG as
+    /// seen by borrow checking doesn't encode this. False edges are added:
+    ///
+    /// * From each prebinding block to the next prebinding block.
+    /// * From each otherwise block to the next prebinding block.
     pub fn match_expr(
         &mut self,
         destination: &Place<'tcx>,
@@ -38,6 +106,9 @@ pub fn match_expr(
         arms: Vec<Arm<'tcx>>,
     ) -> BlockAnd<()> {
         let tcx = self.hir.tcx();
+
+        // Step 1. Evaluate the scrutinee and add the fake read of it.
+
         let discriminant_span = discriminant.span();
         let discriminant_place = unpack!(block = self.as_place(block, discriminant));
 
@@ -66,26 +137,7 @@ pub fn match_expr(
             ),
         });
 
-        let mut arm_blocks = ArmBlocks {
-            blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(),
-        };
-
-        // Get the arm bodies and their scopes, while declaring bindings.
-        let arm_bodies: Vec<_> = arms.iter()
-            .map(|arm| {
-                // BUG: use arm lint level
-                let body = self.hir.mirror(arm.body.clone());
-                let scope = self.declare_bindings(
-                    None,
-                    body.span,
-                    LintLevel::Inherited,
-                    &arm.patterns[..],
-                    ArmHasGuard(arm.guard.is_some()),
-                    Some((Some(&discriminant_place), discriminant_span)),
-                );
-                (body, scope.unwrap_or(self.source_scope))
-            })
-            .collect();
+        // Step 2. Create the otherwise and prebinding blocks.
 
         // create binding start block for link them by false edges
         let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::<usize>();
@@ -93,70 +145,8 @@ pub fn match_expr(
             .map(|_| self.cfg.start_new_block())
             .collect();
 
-        let mut has_guard = false;
-
-        // assemble a list of candidates: there is one candidate per
-        // pattern, which means there may be more than one candidate
-        // *per arm*. These candidates are kept sorted such that the
-        // highest priority candidate comes first in the list.
-        // (i.e., same order as in source)
-
-        let candidates: Vec<_> = arms.iter()
-            .enumerate()
-            .flat_map(|(arm_index, arm)| {
-                arm.patterns
-                    .iter()
-                    .enumerate()
-                    .map(move |(pat_index, pat)| (arm_index, pat_index, pat, arm.guard.clone()))
-            })
-            .zip(
-                pre_binding_blocks
-                    .iter()
-                    .zip(pre_binding_blocks.iter().skip(1)),
-            )
-            .map(
-                |(
-                    (arm_index, pat_index, pattern, guard),
-                    (pre_binding_block, next_candidate_pre_binding_block)
-                )| {
-                    has_guard |= guard.is_some();
-
-                    // One might ask: why not build up the match pair such that it
-                    // matches via `borrowed_input_temp.deref()` instead of
-                    // using the `discriminant_place` directly, as it is doing here?
-                    //
-                    // The basic answer is that if you do that, then you end up with
-                    // accceses to a shared borrow of the input and that conflicts with
-                    // any arms that look like e.g.
-                    //
-                    // match Some(&4) {
-                    //     ref mut foo => {
-                    //         ... /* mutate `foo` in arm body */ ...
-                    //     }
-                    // }
-                    //
-                    // (Perhaps we could further revise the MIR
-                    //  construction here so that it only does a
-                    //  shared borrow at the outset and delays doing
-                    //  the mutable borrow until after the pattern is
-                    //  matched *and* the guard (if any) for the arm
-                    //  has been run.)
-
-                    Candidate {
-                        span: pattern.span,
-                        match_pairs: vec![MatchPair::new(discriminant_place.clone(), pattern)],
-                        bindings: vec![],
-                        ascriptions: vec![],
-                        guard,
-                        arm_index,
-                        pat_index,
-                        pre_binding_block: *pre_binding_block,
-                        next_candidate_pre_binding_block: *next_candidate_pre_binding_block,
-                    }
-                },
-            )
-            .collect();
-
+        // There's one move pre_binding block that there are candidates so that
+        // every candidate has a next prebinding_block.
         let outer_source_info = self.source_info(span);
         self.cfg.terminate(
             *pre_binding_blocks.last().unwrap(),
@@ -164,27 +154,72 @@ pub fn match_expr(
             TerminatorKind::Unreachable,
         );
 
+        let mut match_has_guard = false;
+
+        let mut candidate_pre_binding_blocks = pre_binding_blocks.iter();
+        let mut next_candidate_pre_binding_blocks = pre_binding_blocks.iter().skip(1);
+
+        // Assemble a list of candidates: there is one candidate per pattern,
+        // which means there may be more than one candidate *per arm*.
+        let mut arm_candidates: Vec<_> = arms
+            .iter()
+            .map(|arm| {
+                let arm_has_guard = arm.guard.is_some();
+                match_has_guard |= arm_has_guard;
+                let arm_candidates: Vec<_> = arm.patterns
+                    .iter()
+                    .zip(candidate_pre_binding_blocks.by_ref())
+                    .zip(next_candidate_pre_binding_blocks.by_ref())
+                    .map(
+                        |((pattern, pre_binding_block), next_candidate_pre_binding_block)| {
+                            Candidate {
+                                span: pattern.span,
+                                match_pairs: vec![
+                                    MatchPair::new(discriminant_place.clone(), pattern),
+                                ],
+                                bindings: vec![],
+                                ascriptions: vec![],
+                                otherwise_block: if arm_has_guard {
+                                    Some(self.cfg.start_new_block())
+                                } else {
+                                    None
+                                },
+                                pre_binding_block: *pre_binding_block,
+                                next_candidate_pre_binding_block:
+                                    *next_candidate_pre_binding_block,
+                            }
+                        },
+                    )
+                    .collect();
+                (arm, arm_candidates)
+            })
+            .collect();
+
+        // Step 3. Create the decision tree and record the places that we bind or test.
+
         // Maps a place to the kind of Fake borrow that we want to perform on
         // it: either Shallow or Shared, depending on whether the place is
         // bound in the match, or just switched on.
         // If there are no match guards then we don't need any fake borrows,
         // so don't track them.
-        let mut fake_borrows = if has_guard && tcx.generate_borrow_of_any_match_input() {
+        let mut fake_borrows = if match_has_guard && tcx.generate_borrow_of_any_match_input() {
             Some(FxHashMap::default())
         } else {
             None
         };
 
-        let pre_binding_blocks: Vec<_> = candidates
-            .iter()
-            .map(|cand| (cand.pre_binding_block, cand.span))
-            .collect();
+        // These candidates are kept sorted such that the highest priority
+        // candidate comes first in the list. (i.e., same order as in source)
+        // As we gnerate the decision tree,
+        let candidates = &mut arm_candidates
+            .iter_mut()
+            .flat_map(|(_, candidates)| candidates)
+            .collect::<Vec<_>>();
 
         // this will generate code to test discriminant_place and
         // branch to the appropriate arm block
         let otherwise = self.match_candidates(
             discriminant_span,
-            &mut arm_blocks,
             candidates,
             block,
             &mut fake_borrows,
@@ -197,29 +232,59 @@ pub fn match_expr(
             //
             // In that case, the inexhaustive tips of the decision tree
             // can't be reached - terminate them with an `unreachable`.
-            let source_info = self.source_info(span);
-
             let mut otherwise = otherwise;
             otherwise.sort();
             otherwise.dedup(); // variant switches can introduce duplicate target blocks
             for block in otherwise {
                 self.cfg
-                    .terminate(block, source_info, TerminatorKind::Unreachable);
+                    .terminate(block, outer_source_info, TerminatorKind::Unreachable);
             }
         }
 
-        if let Some(fake_borrows) = fake_borrows {
-            self.add_fake_borrows(&pre_binding_blocks, fake_borrows, source_info, block);
-        }
+        // Step 4. Determine the fake borrows that are needed from the above
+        // places. Create the required temporaries for them.
+
+        let fake_borrow_temps = if let Some(ref borrows) = fake_borrows {
+            self.calculate_fake_borrows(borrows, discriminant_span)
+        } else {
+            Vec::new()
+        };
+
+        // Step 5. Create everything else: the guards and the arms.
 
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
         let outer_source_info = self.source_info(span);
-        for (arm_index, (body, source_scope)) in arm_bodies.into_iter().enumerate() {
-            let mut arm_block = arm_blocks.blocks[arm_index];
-            // Re-enter the source scope we created the bindings in.
-            self.source_scope = source_scope;
+
+        for (arm, candidates) in arm_candidates {
+            let mut arm_block = self.cfg.start_new_block();
+
+            let body = self.hir.mirror(arm.body.clone());
+            let scope = self.declare_bindings(
+                None,
+                body.span,
+                LintLevel::Inherited,
+                &arm.patterns[..],
+                ArmHasGuard(arm.guard.is_some()),
+                Some((Some(&discriminant_place), discriminant_span)),
+            );
+
+            for (pat_index, candidate) in candidates.into_iter().enumerate() {
+                self.bind_and_guard_matched_candidate(
+                    candidate,
+                    arm.guard.clone(),
+                    arm_block,
+                    &fake_borrow_temps,
+                    discriminant_span,
+                    pat_index,
+                );
+            }
+
+            if let Some(source_scope) = scope {
+                self.source_scope = source_scope;
+            }
+
             unpack!(arm_block = self.into(destination, arm_block, body));
             self.cfg.terminate(
                 arm_block,
@@ -227,6 +292,7 @@ pub fn match_expr(
                 TerminatorKind::Goto { target: end_block },
             );
         }
+
         self.source_scope = outer_source_info.scope;
 
         end_block.unit()
@@ -359,11 +425,9 @@ pub fn place_into_pattern(
             match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
             bindings: vec![],
             ascriptions: vec![],
-            guard: None,
 
-            // since we don't call `match_candidates`, next fields is unused
-            arm_index: 0,
-            pat_index: 0,
+            // since we don't call `match_candidates`, next fields are unused
+            otherwise_block: None,
             pre_binding_block: block,
             next_candidate_pre_binding_block: block,
         };
@@ -613,13 +677,7 @@ pub(super) fn visit_bindings(
     }
 }
 
-/// List of blocks for each arm (and potentially other metadata in the
-/// future).
-struct ArmBlocks {
-    blocks: Vec<BasicBlock>,
-}
-
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 pub struct Candidate<'pat, 'tcx: 'pat> {
     // span of the original pattern that gave rise to this candidate
     span: Span,
@@ -630,21 +688,15 @@ pub struct Candidate<'pat, 'tcx: 'pat> {
     // ...these bindings established...
     bindings: Vec<Binding<'tcx>>,
 
-    // ...these types asserted...
+    // ...and these types asserted...
     ascriptions: Vec<Ascription<'tcx>>,
 
-    // ...and the guard must be evaluated...
-    guard: Option<Guard<'tcx>>,
-
-    // ...and then we branch to arm with this index.
-    arm_index: usize,
+    // ...and the guard must be evaluated, if false branch to Block...
+    otherwise_block: Option<BasicBlock>,
 
     // ...and the blocks for add false edges between candidates
     pre_binding_block: BasicBlock,
     next_candidate_pre_binding_block: BasicBlock,
-
-    // This uniquely identifies this candidate *within* the arm.
-    pat_index: usize,
 }
 
 #[derive(Clone, Debug)]
@@ -676,13 +728,6 @@ pub struct MatchPair<'pat, 'tcx: 'pat> {
 
     // ... must match this pattern.
     pattern: &'pat Pattern<'tcx>,
-
-    // HACK(eddyb) This is used to toggle whether a Slice pattern
-    // has had its length checked. This is only necessary because
-    // the "rest" part of the pattern right now has type &[T] and
-    // as such, it requires an Rvalue::Slice to be generated.
-    // See RFC 495 / issue #23121 for the eventual (proper) solution.
-    slice_len_checked: bool,
 }
 
 #[derive(Clone, Debug, PartialEq)]
@@ -722,6 +767,11 @@ pub struct Test<'tcx> {
     kind: TestKind<'tcx>,
 }
 
+/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
+/// a match arm has a guard expression attached to it.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct ArmHasGuard(pub bool);
+
 ///////////////////////////////////////////////////////////////////////////
 // Main matching algorithm
 
@@ -732,7 +782,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// candidates are sorted such that the first item in the list
     /// has the highest priority. When a candidate is found to match
     /// the value, we will generate a branch to the appropriate
-    /// block found in `arm_blocks`.
+    /// prebinding block.
     ///
     /// The return value is a list of "otherwise" blocks. These are
     /// points in execution where we found that *NONE* of the
@@ -747,13 +797,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// list. This is important to keep the size of the generated code
     /// under control. See `test_candidates` for more details.
     ///
-    /// If `add_fake_borrows` is true, then places which need fake borrows
+    /// If `fake_borrows` is Some, then places which need fake borrows
     /// will be added to it.
     fn match_candidates<'pat>(
         &mut self,
         span: Span,
-        arm_blocks: &mut ArmBlocks,
-        mut candidates: Vec<Candidate<'pat, 'tcx>>,
+        candidates: &mut [&mut Candidate<'pat, 'tcx>],
         mut block: BasicBlock,
         fake_borrows: &mut Option<FxHashMap<Place<'tcx>, BorrowKind>>,
     ) -> Vec<BasicBlock> {
@@ -762,17 +811,16 @@ fn match_candidates<'pat>(
             span, block, candidates
         );
 
-        // Start by simplifying candidates. Once this process is
-        // complete, all the match pairs which remain require some
-        // form of test, whether it be a switch or pattern comparison.
-        for candidate in &mut candidates {
+        // Start by simplifying candidates. Once this process is complete, all
+        // the match pairs which remain require some form of test, whether it
+        // be a switch or pattern comparison.
+        for candidate in &mut *candidates {
             self.simplify_candidate(candidate);
         }
 
-        // The candidates are sorted by priority. Check to see
-        // whether the higher priority candidates (and hence at
-        // the front of the vec) have satisfied all their match
-        // pairs.
+        // The candidates are sorted by priority. Check to see whether the
+        // higher priority candidates (and hence at the front of the slice)
+        // have satisfied all their match pairs.
         let fully_matched = candidates
             .iter()
             .take_while(|c| c.match_pairs.is_empty())
@@ -781,87 +829,172 @@ fn match_candidates<'pat>(
             "match_candidates: {:?} candidates fully matched",
             fully_matched
         );
-        let mut unmatched_candidates = candidates.split_off(fully_matched);
+        let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched);
+
+        if !matched_candidates.is_empty() {
+            block = if let Some(last_otherwise_block) = self.select_matched_candidates(
+                matched_candidates,
+                block,
+                fake_borrows,
+            ) {
+                last_otherwise_block
+            } else {
+                // Any remaining candidates are unreachable.
+                if unmatched_candidates.is_empty() {
+                    return Vec::new();
+                } else {
+                    self.cfg.start_new_block()
+                }
+            };
+        }
+
+        // If there are no candidates that still need testing, we're
+        // done. Since all matches are exhaustive, execution should
+        // never reach this point.
+        if unmatched_candidates.is_empty() {
+            return vec![block];
+        }
+
+        // Test candidates where possible.
+        let (otherwise, untested_candidates) = self.test_candidates(
+            span,
+            unmatched_candidates,
+            block,
+            fake_borrows,
+        );
+
+        // If the target candidates were exhaustive, then we are done.
+        // But for borrowck continue build decision tree.
+        if untested_candidates.is_empty() {
+            return otherwise;
+        }
+
+        // Otherwise, let's process those remaining candidates.
+        let join_block = self.join_otherwise_blocks(span, otherwise);
+        self.match_candidates(
+            span,
+            untested_candidates,
+            join_block,
+            &mut None,
+        )
+    }
+
+    /// Link up matched candidates. For example, if we have something like
+    /// this:
+    ///
+    /// ...
+    /// Some(x) if cond => ...
+    /// Some(x) => ...
+    /// Some(x) if cond => ...
+    /// ...
+    ///
+    /// We generate real edges from:
+    /// * `block` to the prebinding_block of the first pattern,
+    /// * the otherwise block of the first pattern to the second pattern,
+    /// * the otherwise block of the third pattern to the a block with an
+    ///   Unreachable terminator.
+    ///
+    /// As well as that we add fake edges from the otherwise blocks to the
+    /// prebinding block of the next candidate in the original set of
+    /// candidates.
+    fn select_matched_candidates(
+        &mut self,
+        matched_candidates: &mut [&mut Candidate<'_, 'tcx>],
+        block: BasicBlock,
+        fake_borrows: &mut Option<FxHashMap<Place<'tcx>, BorrowKind>>,
+    ) -> Option<BasicBlock> {
+        debug_assert!(
+            !matched_candidates.is_empty(),
+            "select_matched_candidates called with no candidates",
+        );
 
         // Insert a *Shared* borrow of any places that are bound.
         if let Some(fake_borrows) = fake_borrows {
             for Binding { source, .. }
-                in candidates.iter().flat_map(|candidate| &candidate.bindings)
+                in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
             {
                 fake_borrows.insert(source.clone(), BorrowKind::Shared);
             }
         }
 
-        let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count();
+        let fully_matched_with_guard = matched_candidates
+            .iter()
+            .position(|c| c.otherwise_block.is_none())
+            .unwrap_or(matched_candidates.len() - 1);
 
-        let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() {
-            candidates.split_off(fully_matched_with_guard + 1)
-        } else {
-            vec![]
-        };
+        let (reachable_candidates, unreachable_candidates)
+            = matched_candidates.split_at_mut(fully_matched_with_guard + 1);
 
-        for candidate in candidates {
-            // If so, apply any bindings, test the guard (if any), and
-            // branch to the arm.
-            if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
-                block = b;
-            } else {
-                // if None is returned, then any remaining candidates
-                // are unreachable (at least not through this path).
-                // Link them with false edges.
-                debug!(
-                    "match_candidates: add false edges for unreachable {:?} and unmatched {:?}",
-                    unreachable_candidates, unmatched_candidates
-                );
-                for candidate in unreachable_candidates {
-                    let source_info = self.source_info(candidate.span);
-                    let target = self.cfg.start_new_block();
-                    if let Some(otherwise) =
-                        self.bind_and_guard_matched_candidate(target, arm_blocks, candidate)
-                    {
-                        self.cfg
-                            .terminate(otherwise, source_info, TerminatorKind::Unreachable);
-                    }
-                }
+        let first_candidate = &reachable_candidates[0];
 
-                if unmatched_candidates.is_empty() {
-                    return vec![];
+        let candidate_source_info = self.source_info(first_candidate.span);
+
+        self.cfg.terminate(
+            block,
+            candidate_source_info,
+            TerminatorKind::Goto {
+                target: first_candidate.pre_binding_block,
+            },
+        );
+
+        for window in reachable_candidates.windows(2) {
+            if let [first_candidate, second_candidate] = window {
+                let source_info = self.source_info(first_candidate.span);
+                if let Some(otherwise_block) = first_candidate.otherwise_block {
+                    self.cfg.terminate(
+                        otherwise_block,
+                        source_info,
+                        TerminatorKind::FalseEdges {
+                            real_target: second_candidate.pre_binding_block,
+                            imaginary_targets: vec![
+                                first_candidate.next_candidate_pre_binding_block
+                            ],
+                        }
+                    )
                 } else {
-                    let target = self.cfg.start_new_block();
-                    return self.match_candidates(
-                        span,
-                        arm_blocks,
-                        unmatched_candidates,
-                        target,
-                        &mut None,
-                    );
+                    bug!("candidate other than the last has no guard");
                 }
+            } else {
+                bug!("<[_]>::windows returned incorrectly sized window");
             }
         }
 
-        // If there are no candidates that still need testing, we're done.
-        // Since all matches are exhaustive, execution should never reach this point.
-        if unmatched_candidates.is_empty() {
-            return vec![block];
-        }
 
-        // Test candidates where possible.
-        let (otherwise, tested_candidates) =
-            self.test_candidates(span, arm_blocks, &unmatched_candidates, block, fake_borrows);
+        // if None is returned, then
+        debug!("match_candidates: add false edges for unreachable {:?}", unreachable_candidates);
+        for candidate in unreachable_candidates {
+            if let Some(otherwise) = candidate.otherwise_block {
+                let source_info = self.source_info(candidate.span);
+                let unreachable = self.cfg.start_new_block();
+                self.cfg.terminate(
+                    otherwise,
+                    source_info,
+                    TerminatorKind::FalseEdges {
+                        real_target: unreachable,
+                        imaginary_targets: vec![candidate.next_candidate_pre_binding_block],
+                    }
+                );
+                self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
+            }
+        }
 
-        // If the target candidates were exhaustive, then we are done.
-        // But for borrowck continue build decision tree.
+        let last_candidate = reachable_candidates.last().unwrap();
 
-        // If all candidates were sorted into `target_candidates` somewhere, then
-        // the initial set was inexhaustive.
-        let untested_candidates = unmatched_candidates.split_off(tested_candidates);
-        if untested_candidates.len() == 0 {
-            return otherwise;
+        if let Some(otherwise) = last_candidate.otherwise_block {
+            let source_info = self.source_info(last_candidate.span);
+            let block = self.cfg.start_new_block();
+            self.cfg.terminate(
+                otherwise,
+                source_info,
+                TerminatorKind::FalseEdges {
+                    real_target: block,
+                    imaginary_targets: vec![last_candidate.next_candidate_pre_binding_block]
+                }
+            );
+            Some(block)
+        } else {
+            None
         }
-
-        // Otherwise, let's process those remaining candidates.
-        let join_block = self.join_otherwise_blocks(span, otherwise);
-        self.match_candidates(span, arm_blocks, untested_candidates, join_block, &mut None)
     }
 
     fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>) -> BasicBlock {
@@ -995,17 +1128,17 @@ fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>)
     /// In addition to avoiding exponential-time blowups, this algorithm
     /// also has nice property that each guard and arm is only generated
     /// once.
-    fn test_candidates<'pat>(
+    fn test_candidates<'pat, 'b, 'c>(
         &mut self,
         span: Span,
-        arm_blocks: &mut ArmBlocks,
-        candidates: &[Candidate<'pat, 'tcx>],
+        mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
         block: BasicBlock,
         fake_borrows: &mut Option<FxHashMap<Place<'tcx>, BorrowKind>>,
-    ) -> (Vec<BasicBlock>, usize) {
+    ) -> (Vec<BasicBlock>, &'b mut [&'c mut Candidate<'pat, 'tcx>]) {
         // extract the match-pair from the highest priority candidate
         let match_pair = &candidates.first().unwrap().match_pairs[0];
         let mut test = self.test(match_pair);
+        let match_place = match_pair.place.clone();
 
         // most of the time, the test to perform is simply a function
         // of the main candidate; but for a test like SwitchInt, we
@@ -1019,7 +1152,7 @@ fn test_candidates<'pat>(
             } => {
                 for candidate in candidates.iter() {
                     if !self.add_cases_to_switch(
-                        &match_pair.place,
+                        &match_place,
                         candidate,
                         switch_ty,
                         options,
@@ -1034,7 +1167,7 @@ fn test_candidates<'pat>(
                 ref mut variants,
             } => {
                 for candidate in candidates.iter() {
-                    if !self.add_variants_to_switch(&match_pair.place, candidate, variants) {
+                    if !self.add_variants_to_switch(&match_place, candidate, variants) {
                         break;
                     }
                 }
@@ -1044,7 +1177,7 @@ fn test_candidates<'pat>(
 
         // Insert a Shallow borrow of any places that is switched on.
         fake_borrows.as_mut().map(|fb| {
-            fb.entry(match_pair.place.clone()).or_insert(BorrowKind::Shallow)
+            fb.entry(match_place.clone()).or_insert(BorrowKind::Shallow)
         });
 
         // perform the test, branching to one of N blocks. For each of
@@ -1055,25 +1188,29 @@ fn test_candidates<'pat>(
             "match_candidates: test={:?} match_pair={:?}",
             test, match_pair
         );
-        let target_blocks = self.perform_test(block, &match_pair.place, &test);
-        let mut target_candidates = vec![vec![]; target_blocks.len()];
+        let target_blocks = self.perform_test(block, &match_place, &test);
+        let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
+        target_candidates.resize_with(target_blocks.len(), Default::default);
+
+        let total_candidate_count = candidates.len();
 
         // Sort the candidates into the appropriate vector in
         // `target_candidates`. Note that at some point we may
         // encounter a candidate where the test is not relevant; at
         // that point, we stop sorting.
-        let tested_candidates = candidates
-            .iter()
-            .take_while(|c| {
-                self.sort_candidate(&match_pair.place, &test, c, &mut target_candidates)
-            })
-            .count();
-        assert!(tested_candidates > 0); // at least the last candidate ought to be tested
-        debug!("tested_candidates: {}", tested_candidates);
-        debug!(
-            "untested_candidates: {}",
-            candidates.len() - tested_candidates
-        );
+        while let Some(candidate) = candidates.first_mut() {
+            if let Some(idx) = self.sort_candidate(&match_place, &test, candidate) {
+                let (candidate, rest) = candidates.split_first_mut().unwrap();
+                target_candidates[idx].push(candidate);
+                candidates = rest;
+            } else {
+                break;
+            }
+        }
+        // at least the first candidate ought to be tested
+        assert!(total_candidate_count > candidates.len());
+        debug!("tested_candidates: {}", total_candidate_count - candidates.len());
+        debug!("untested_candidates: {}", candidates.len());
 
         // For each outcome of test, process the candidates that still
         // apply. Collect a list of blocks where control flow will
@@ -1082,59 +1219,99 @@ fn test_candidates<'pat>(
         let otherwise: Vec<_> = target_blocks
             .into_iter()
             .zip(target_candidates)
-            .flat_map(|(target_block, target_candidates)| {
+            .flat_map(|(target_block, mut target_candidates)| {
                 self.match_candidates(
                     span,
-                    arm_blocks,
-                    target_candidates,
+                    &mut *target_candidates,
                     target_block,
                     fake_borrows,
                 )
             })
             .collect();
 
-        (otherwise, tested_candidates)
+        (otherwise, candidates)
+    }
+
+    // Determine the fake borrows that are needed to ensure that the place
+    // will evaluate to the same thing until an arm has been chosen.
+    fn calculate_fake_borrows<'b>(
+        &mut self,
+        fake_borrows: &'b FxHashMap<Place<'tcx>, BorrowKind>,
+        temp_span: Span,
+    ) -> Vec<(&'b Place<'tcx>, BorrowKind, Local)> {
+        let tcx = self.hir.tcx();
+
+        debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
+
+        let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
+
+        // Insert a Shallow borrow of the prefixes of any fake borrows.
+        for (place, borrow_kind) in fake_borrows
+        {
+            let mut prefix_cursor = place;
+            while let Place::Projection(box Projection { base, elem }) = prefix_cursor {
+                if let ProjectionElem::Deref = elem {
+                    // Insert a shallow borrow after a deref. For other
+                    // projections the borrow of prefix_cursor will
+                    // conflict with any mutation of base.
+                    all_fake_borrows.push((base, BorrowKind::Shallow));
+                }
+                prefix_cursor = base;
+            }
+
+            all_fake_borrows.push((place, *borrow_kind));
+        }
+
+        // Deduplicate and ensure a deterministic order.
+        all_fake_borrows.sort();
+        all_fake_borrows.dedup();
+
+        debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
+
+        all_fake_borrows.into_iter().map(|(matched_place, borrow_kind)| {
+            let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).to_ty(tcx);
+            let fake_borrow_ty = tcx.mk_imm_ref(tcx.types.re_erased, fake_borrow_deref_ty);
+            let fake_borrow_temp = self.local_decls.push(
+                LocalDecl::new_temp(fake_borrow_ty, temp_span)
+            );
+
+            (matched_place, borrow_kind, fake_borrow_temp)
+        }).collect()
     }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Pattern binding - used for `let` and function parameters as well.
 
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Initializes each of the bindings from the candidate by
-    /// moving/copying/ref'ing the source as appropriate. Tests the
-    /// guard, if any, and then branches to the arm. Returns the block
-    /// for the case where the guard fails.
+    /// moving/copying/ref'ing the source as appropriate. Tests the guard, if
+    /// any, and then branches to the arm. Returns the block for the case where
+    /// the guard fails.
     ///
-    /// Note: we check earlier that if there is a guard, there cannot
-    /// be move bindings. This isn't really important for the
-    /// self-consistency of this fn, but the reason for it should be
-    /// clear: after we've done the assignments, if there were move
-    /// bindings, further tests would be a use-after-move (which would
-    /// in turn be detected by the borrowck code that runs on the
-    /// MIR).
+    /// Note: we check earlier that if there is a guard, there cannot be move
+    /// bindings (unless feature(bind_by_move_pattern_guards) is used). This
+    /// isn't really important for the self-consistency of this fn, but the
+    /// reason for it should be clear: after we've done the assignments, if
+    /// there were move bindings, further tests would be a use-after-move.
+    /// bind_by_move_pattern_guards avoids this by only moving the binding once
+    /// the guard has evaluated to true (see below).
     fn bind_and_guard_matched_candidate<'pat>(
         &mut self,
-        mut block: BasicBlock,
-        arm_blocks: &mut ArmBlocks,
         candidate: Candidate<'pat, 'tcx>,
-    ) -> Option<BasicBlock> {
-        debug!(
-            "bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
-            block, candidate
-        );
+        guard: Option<Guard<'tcx>>,
+        arm_block: BasicBlock,
+        fake_borrows: &Vec<(&Place<'tcx>, BorrowKind, Local)>,
+        discriminant_span: Span,
+        pat_index: usize,
+    ) {
+        debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
 
         debug_assert!(candidate.match_pairs.is_empty());
 
-        self.ascribe_types(block, &candidate.ascriptions);
-
-        let arm_block = arm_blocks.blocks[candidate.arm_index];
         let candidate_source_info = self.source_info(candidate.span);
 
-        self.cfg.terminate(
-            block,
-            candidate_source_info,
-            TerminatorKind::Goto {
-                target: candidate.pre_binding_block,
-            },
-        );
-
-        block = self.cfg.start_new_block();
+        let mut block = self.cfg.start_new_block();
         self.cfg.terminate(
             candidate.pre_binding_block,
             candidate_source_info,
@@ -1143,6 +1320,7 @@ fn bind_and_guard_matched_candidate<'pat>(
                 imaginary_targets: vec![candidate.next_candidate_pre_binding_block],
             },
         );
+        self.ascribe_types(block, &candidate.ascriptions);
 
         // rust-lang/rust#27282: The `autoref` business deserves some
         // explanation here.
@@ -1226,14 +1404,13 @@ fn bind_and_guard_matched_candidate<'pat>(
         //      match input itself; it is up to us to create a place
         //      holding a `&` or `&mut` that we can then borrow).
 
-        let autoref = self.hir
-            .tcx()
-            .all_pat_vars_are_implicit_refs_within_guards();
-        if let Some(guard) = candidate.guard {
+        let tcx = self.hir.tcx();
+        let autoref = tcx.all_pat_vars_are_implicit_refs_within_guards();
+        if let Some(guard) = guard {
             if autoref {
                 self.bind_matched_candidate_for_guard(
                     block,
-                    candidate.pat_index,
+                    pat_index,
                     &candidate.bindings,
                 );
                 let guard_frame = GuardFrame {
@@ -1249,12 +1426,29 @@ fn bind_and_guard_matched_candidate<'pat>(
                 self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
             }
 
+            let re_erased = tcx.types.re_erased;
+            let discriminant_source_info = self.source_info(discriminant_span);
+            for &(place, borrow_kind, temp) in fake_borrows {
+                let borrow = Rvalue::Ref(
+                    re_erased,
+                    borrow_kind,
+                    place.clone(),
+                );
+                self.cfg.push_assign(
+                    block,
+                    discriminant_source_info,
+                    &Place::Local(temp),
+                    borrow,
+                );
+            }
+
             // the block to branch to if the guard fails; if there is no
             // guard, this block is simply unreachable
             let guard = match guard {
                 Guard::If(e) => self.hir.mirror(e),
             };
             let source_info = self.source_info(guard.span);
+            let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span));
             let cond = unpack!(block = self.as_local_operand(block, guard));
             if autoref {
                 let guard_frame = self.guard_context.pop().unwrap();
@@ -1264,7 +1458,15 @@ fn bind_and_guard_matched_candidate<'pat>(
                 );
             }
 
-            let false_edge_block = self.cfg.start_new_block();
+            for &(_, _, temp) in fake_borrows {
+                self.cfg.push(block, Statement {
+                    source_info: guard_end,
+                    kind: StatementKind::FakeRead(
+                        FakeReadCause::ForMatchGuard,
+                        Place::Local(temp),
+                    ),
+                });
+            }
 
             // We want to ensure that the matched candidates are bound
             // after we have confirmed this candidate *and* any
@@ -1296,7 +1498,12 @@ fn bind_and_guard_matched_candidate<'pat>(
             self.cfg.terminate(
                 block,
                 source_info,
-                TerminatorKind::if_(self.hir.tcx(), cond, post_guard_block, false_edge_block),
+                TerminatorKind::if_(
+                    self.hir.tcx(),
+                    cond,
+                    post_guard_block,
+                    candidate.otherwise_block.unwrap()
+                ),
             );
 
             if autoref {
@@ -1308,19 +1515,8 @@ fn bind_and_guard_matched_candidate<'pat>(
                 source_info,
                 TerminatorKind::Goto { target: arm_block },
             );
-
-            let otherwise = self.cfg.start_new_block();
-
-            self.cfg.terminate(
-                false_edge_block,
-                source_info,
-                TerminatorKind::FalseEdges {
-                    real_target: otherwise,
-                    imaginary_targets: vec![candidate.next_candidate_pre_binding_block],
-                },
-            );
-            Some(otherwise)
         } else {
+            assert!(candidate.otherwise_block.is_none());
             // (Here, it is not too early to bind the matched
             // candidate on `block`, because there is no guard result
             // that we have to inspect before we bind them.)
@@ -1330,7 +1526,6 @@ fn bind_and_guard_matched_candidate<'pat>(
                 candidate_source_info,
                 TerminatorKind::Goto { target: arm_block },
             );
-            None
         }
     }
 
@@ -1397,8 +1592,9 @@ fn bind_matched_candidate_for_guard(
             let ref_for_guard =
                 self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard);
             // Question: Why schedule drops if bindings are all
-            // shared-&'s?  Answer: Because schedule_drop_for_binding
-            // also emits StorageDead's for those locals.
+            // shared-&'s?
+            // Answer: Because schedule_drop_for_binding also emits
+            // StorageDead's for those locals.
             self.schedule_drop_for_binding(binding.var_id, binding.span, RefWithinGuard);
             match binding.binding_mode {
                 BindingMode::ByValue => {
@@ -1585,86 +1781,4 @@ fn declare_binding(
         debug!("declare_binding: vars={:?}", locals);
         self.var_indices.insert(var_id, locals);
     }
-
-    // Determine the fake borrows that are needed to ensure that the place
-    // will evaluate to the same thing until an arm has been chosen.
-    fn add_fake_borrows<'pat>(
-        &mut self,
-        pre_binding_blocks: &[(BasicBlock, Span)],
-        fake_borrows: FxHashMap<Place<'tcx>, BorrowKind>,
-        source_info: SourceInfo,
-        start_block: BasicBlock,
-    ) {
-        let tcx = self.hir.tcx();
-
-        debug!("add_fake_borrows pre_binding_blocks = {:?}, fake_borrows = {:?}",
-               pre_binding_blocks, fake_borrows);
-
-        let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
-
-        // Insert a Shallow borrow of the prefixes of any fake borrows.
-        for (place, borrow_kind) in fake_borrows
-        {
-            {
-                let mut prefix_cursor = &place;
-                while let Place::Projection(box Projection { base, elem }) = prefix_cursor {
-                    if let ProjectionElem::Deref = elem {
-                        // Insert a shallow borrow after a deref. For other
-                        // projections the borrow of prefix_cursor will
-                        // conflict with any mutation of base.
-                        all_fake_borrows.push((base.clone(), BorrowKind::Shallow));
-                    }
-                    prefix_cursor = base;
-                }
-            }
-
-            all_fake_borrows.push((place, borrow_kind));
-        }
-
-        // Deduplicate and ensure a deterministic order.
-        all_fake_borrows.sort();
-        all_fake_borrows.dedup();
-
-        debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
-
-        // Add fake borrows to the start of the match and reads of them before
-        // the start of each arm.
-        let mut borrowed_input_temps = Vec::with_capacity(all_fake_borrows.len());
-
-        for (matched_place, borrow_kind) in all_fake_borrows {
-            let borrowed_input =
-                Rvalue::Ref(tcx.types.re_erased, borrow_kind, matched_place.clone());
-            let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx);
-            let borrowed_input_temp = self.temp(borrowed_input_ty, source_info.span);
-            self.cfg.push_assign(
-                start_block,
-                source_info,
-                &borrowed_input_temp,
-                borrowed_input
-            );
-            borrowed_input_temps.push(borrowed_input_temp);
-        }
-
-        // FIXME: This could be a lot of reads (#fake borrows * #patterns).
-        // The false edges that we currently generate would allow us to only do
-        // this on the last Candidate, but it's possible that there might not be
-        // so many false edges in the future, so we read for all Candidates for
-        // now.
-        // Another option would be to make our own block and add our own false
-        // edges to it.
-        if tcx.emit_read_for_match() {
-            for &(pre_binding_block, span) in pre_binding_blocks {
-                let pattern_source_info = self.source_info(span);
-                for temp in &borrowed_input_temps {
-                    self.cfg.push(pre_binding_block, Statement {
-                        source_info: pattern_source_info,
-                        kind: StatementKind::FakeRead(
-                            FakeReadCause::ForMatchGuard,
-                            temp.clone(),
-                        ),
-                    });
-                }
-            }
-        }
-    }
 }
index a41d3895d6d3cfcace3d167745f430ca6461f159..72b92444dece9be37883af5998213616f8d597b5 100644 (file)
@@ -69,8 +69,7 @@ pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'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 @@ pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
 
             PatternKind::AscribeUserType { .. } |
             PatternKind::Array { .. } |
-            PatternKind::Slice { .. } |
             PatternKind::Wild |
             PatternKind::Binding { .. } |
             PatternKind::Leaf { .. } |
@@ -433,59 +431,49 @@ fn compare(&mut self,
         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 @@ pub fn sort_candidate<'pat>(&mut self,
             (&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 @@ pub fn sort_candidate<'pat>(&mut self,
              &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 @@ pub fn sort_candidate<'pat>(&mut self,
                     // 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 @@ pub fn sort_candidate<'pat>(&mut self,
                     (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 @@ pub fn sort_candidate<'pat>(&mut self,
                     (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 @@ pub fn sort_candidate<'pat>(&mut self,
             (&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 @@ pub fn sort_candidate<'pat>(&mut self,
                 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 @@ pub fn sort_candidate<'pat>(&mut self,
                 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 @@ pub fn sort_candidate<'pat>(&mut self,
                 // 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 @@ fn candidate_after_variant_switch<'pat>(&mut self,
                            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>) -> ! {
index b583b184a4103146286e5d81a7e53d5cf9d55a5f..3b90ff7884f012a70341494a317d7148dcca54a1 100644 (file)
@@ -72,7 +72,6 @@ pub fn new(place: Place<'tcx>, pattern: &'pat Pattern<'tcx>) -> MatchPair<'pat,
         MatchPair {
             place,
             pattern,
-            slice_len_checked: false,
         }
     }
 }
index 8417c2cfd137dd7ca744654887d30d2ec96e3670..5b4ec483277ac0f6ccdc67a0b32abc5016a6ce08 100644 (file)
@@ -41,46 +41,46 @@ 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];
+//         unreachable;
 //     }
 //     bb8: {
-//         falseEdges -> [real: bb13, imaginary: bb9];
+//         goto -> bb6;
 //     }
 //     bb9: {
-//         unreachable;
+//         goto -> bb5;
 //     }
 //     bb10: {
-//         goto -> bb8;
+//         FakeRead(ForLet, _2);
+//         StorageDead(_3);
+//         StorageLive(_6);
+//         _6 = &_2;
+//         _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4];
 //     }
 //     bb11: {
-//         goto -> bb7;
+//         _2 = const 4i32;
+//         goto -> bb10;
 //     }
 //     bb12: {
-//         goto -> bb5;
+//         goto -> bb11;
 //     }
 //     bb13: {
-//         goto -> bb6;
+//         _0 = ();
+//         goto -> bb15;
 //     }
 //     bb14: {
-//         FakeRead(ForLet, _2);
-//         StorageDead(_3);
-//         StorageLive(_6);
-//         _6 = &_2;
-//         _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4];
+//         goto -> bb13;
 //     }
 //     bb15: {
 //         StorageDead(_3);
@@ -96,7 +96,7 @@ fn main() {
 //     }
 //     bb18: {
 //         StorageDead(_4);
-//         goto -> bb14;
+//         goto -> bb10;
 //     }
 //     bb19: {
 //         StorageDead(_6);
index b512172de64eea9cd28c0da445d7516e77886654..9faecf5b7af46952328e2a0158c807d8fc29c967 100644 (file)
@@ -44,72 +44,68 @@ 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];
+//  bb8: {
+//      ...
+//      return;
 //  }
-//  bb10: { // to pre_binding2
-//      falseEdges -> [real: bb4, imaginary: bb4];
+//  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];
 //  }
-//  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;
+//  bb10: {
+//      FakeRead(ForMatchGuard, _4);
+//      FakeRead(ForMatchGuard, _5);
+//      switchInt(move _9) -> [false: bb6, otherwise: bb11];
 //  }
-//  bb12: {
+//  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 = _6;
-//      _1 = (const 2i32, move_12);
+//      _12 = _11;
+//      _1 = (const 2i32, move _12);
 //      StorageDead(_12);
-//      goto -> bb13;
+//      goto -> bb8;
 //  }
 //  bb13: {
-//      ...
-//      return;
+//      _1 = (const 3i32, const 3i32);
+//      goto -> bb8;
 //  }
 // END rustc.full_tested_match.QualifyAndPromoteConstants.after.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];
+//  bb8: {
+//      ...
+//      return;
 //  }
-//  bb9: { // end of guard
-//      switchInt(move _8) -> [false: bb10, otherwise: bb11];
+//  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: { // to pre_binding3 (can skip 2 since this is `Some`)
-//      falseEdges -> [real: bb5, imaginary: bb4];
+//  bb10: { // end of guard
+//      FakeRead(ForMatchGuard, _4);
+//      FakeRead(ForMatchGuard, _5);
+//      switchInt(move _9) -> [false: bb6, otherwise: bb11];
 //  }
 //  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(_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 = _6;
+//      _12 = _11;
 //      _1 = (const 2i32, move _12);
 //      StorageDead(_12);
-//      goto -> bb13;
-//  }
-//  bb13: {
-//      ...
-//      return;
+//      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
index 9bfb728e1346152de7ce5ceb408453dea7d110ac..835a5ce1200b9b30e240b4a4d7faaa6c8f9eafbc 100644 (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];
+//        unreachable;
 //    }
 //    bb6: {
-//        falseEdges -> [real: bb2, imaginary: bb7];
+//        falseEdges -> [real: bb4, imaginary: bb2];
 //    }
 //    bb7: {
-//        falseEdges -> [real: bb3, imaginary: bb8];
+//        _6 = Le(const 10i32, _1);
+//        switchInt(move _6) -> [false: bb9, otherwise: bb10];
 //    }
 //    bb8: {
-//        falseEdges -> [real: bb4, imaginary: bb9];
+//        _5 = Lt(_1, const 10i32);
+//        switchInt(move _5) -> [false: bb7, otherwise: bb1];
 //    }
 //    bb9: {
-//        unreachable;
+//        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];
+//        StorageDead(_8);
+//        _0 = ();
+//        StorageDead(_2);
+//        StorageDead(_1);
+//        return;
 //    }
 //    bb12: {
-//        StorageLive(_6);
-//        _6 = _2;
-//        switchInt(move _6) -> [false: bb13, otherwise: bb1];
+//        _3 = const 0i32;
+//        goto -> bb11;
 //    }
 //    bb13: {
-//        falseEdges -> [real: bb8, imaginary: bb6];
+//        StorageLive(_8);
+//        _8 = _2;
+//        switchInt(move _8) -> [false: bb6, otherwise: bb12];
 //    }
 //    bb14: {
-//        switchInt(_1) -> [-1i32: bb7, otherwise: bb8];
+//        _3 = const 1i32;
+//        goto -> bb11;
 //    }
 //    bb15: {
-//        _8 = Le(_1, const 20i32);
-//        switchInt(move _8) -> [false: bb14, otherwise: bb6];
+//        _3 = const 2i32;
+//        goto -> bb11;
 //    }
 //    bb16: {
-//        StorageDead(_6);
-//        ...
-//        return;
+//        _3 = const 3i32;
+//        goto -> bb11;
 //    }
 // END rustc.main.SimplifyCfg-initial.after.mir
index 8411fba02e97766244669818182bd50866855617..fab4d28a936cac558c32fc6872829090a27aecae 100644 (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