about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-05-09 23:01:39 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2019-06-13 21:05:21 +0100
commitda22793a35b725e2fe2f7e2ac1d808404c39c4aa (patch)
treec48a0a97a0308968e92ebfcc68b5e314c8d3e758
parent32c337724dd3a1b651cb7ba9769e60262f9f52f8 (diff)
downloadrust-da22793a35b725e2fe2f7e2ac1d808404c39c4aa.tar.gz
rust-da22793a35b725e2fe2f7e2ac1d808404c39c4aa.zip
Create fewer basic blocks in match MIR lowering
-rw-r--r--src/librustc_mir/build/matches/mod.rs229
-rw-r--r--src/librustc_mir/build/matches/test.rs478
-rw-r--r--src/librustc_mir/build/mod.rs11
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs3
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs4
-rw-r--r--src/test/codegen/match.rs4
-rw-r--r--src/test/compile-fail/const-fn-error.rs1
-rw-r--r--src/test/compile-fail/issue-52443.rs1
-rw-r--r--src/test/mir-opt/const_prop/switch_int.rs8
-rw-r--r--src/test/mir-opt/deaggregator_test_enum_2.rs26
-rw-r--r--src/test/mir-opt/issue-38669.rs14
-rw-r--r--src/test/mir-opt/issue-49232.rs48
-rw-r--r--src/test/mir-opt/loop_test.rs13
-rw-r--r--src/test/mir-opt/match-arm-scopes.rs150
-rw-r--r--src/test/mir-opt/match_false_edges.rs134
-rw-r--r--src/test/mir-opt/match_test.rs48
-rw-r--r--src/test/mir-opt/nll/region-subtyping-basic.rs6
-rw-r--r--src/test/mir-opt/remove_fake_borrows.rs56
-rw-r--r--src/test/mir-opt/simplify_if.rs4
-rw-r--r--src/test/mir-opt/simplify_match.rs4
-rw-r--r--src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr14
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.rs1
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.stderr12
-rw-r--r--src/test/ui/consts/const-match-pattern-arm.rs2
-rw-r--r--src/test/ui/consts/const-match-pattern-arm.stderr18
-rw-r--r--src/test/ui/consts/single_variant_match_ice.rs11
-rw-r--r--src/test/ui/consts/single_variant_match_ice.stderr18
-rw-r--r--src/test/ui/issues/issue-46843.rs4
-rw-r--r--src/test/ui/issues/issue-46843.stderr10
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr6
30 files changed, 685 insertions, 653 deletions
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 38c9a177c38..521aca56108 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -206,33 +206,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             .flat_map(|(_, candidates)| candidates)
             .collect::<Vec<_>>();
 
+        let outer_source_info = self.source_info(span);
+
         // this will generate code to test scrutinee_place and
         // branch to the appropriate arm block
-        let otherwise = self.match_candidates(
+        self.match_candidates(
             scrutinee_span,
+            &mut Some(block),
+            None,
             candidates,
-            block,
             &mut fake_borrows,
         );
 
-        let outer_source_info = self.source_info(span);
-
-        if !otherwise.is_empty() {
-            // All matches are exhaustive. However, because some matches
-            // only have exponentially-large exhaustive decision trees, we
-            // sometimes generate an inexhaustive decision tree.
-            //
-            // In that case, the inexhaustive tips of the decision tree
-            // can't be reached - terminate them with an `unreachable`.
-            let mut otherwise = otherwise;
-            otherwise.sort();
-            otherwise.dedup(); // variant switches can introduce duplicate target blocks
-            for block in otherwise {
-                self.cfg
-                    .terminate(block, outer_source_info, TerminatorKind::Unreachable);
-            }
-        }
-
         // Step 4. Determine the fake borrows that are needed from the above
         // places. Create the required temporaries for them.
 
@@ -247,8 +232,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let arm_source_info = self.source_info(arm.span);
             let region_scope = (arm.scope, arm_source_info);
             self.in_scope(region_scope, arm.lint_level, |this| {
-                let mut arm_block = this.cfg.start_new_block();
-
                 let body = this.hir.mirror(arm.body.clone());
                 let scope = this.declare_bindings(
                     None,
@@ -258,23 +241,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some((Some(&scrutinee_place), scrutinee_span)),
                 );
 
+                let arm_block;
                 if candidates.len() == 1 {
-                    arm_block = self.bind_and_guard_matched_candidate(
+                    arm_block = this.bind_and_guard_matched_candidate(
                         candidates.pop().unwrap(),
                         arm.guard.clone(),
                         &fake_borrow_temps,
                         scrutinee_span,
+                        region_scope,
                     );
                 } else {
-                    arm_block = self.cfg.start_new_block();
+                    arm_block = this.cfg.start_new_block();
                     for candidate in candidates {
-                        let binding_end = self.bind_and_guard_matched_candidate(
+                        this.clear_top_scope(arm.scope);
+                        let binding_end = this.bind_and_guard_matched_candidate(
                             candidate,
                             arm.guard.clone(),
                             &fake_borrow_temps,
                             scrutinee_span,
+                            region_scope,
                         );
-                        self.cfg.terminate(
+                        this.cfg.terminate(
                             binding_end,
                             source_info,
                             TerminatorKind::Goto { target: arm_block },
@@ -286,18 +273,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     this.source_scope = source_scope;
                 }
 
-                for candidate in candidates {
-                    this.clear_top_scope(arm.scope);
-                    this.bind_and_guard_matched_candidate(
-                        candidate,
-                        arm.guard.clone(),
-                        arm_block,
-                        &fake_borrow_temps,
-                        scrutinee_span,
-                        region_scope,
-                    );
-                }
-
                 this.into(destination, arm_block, body)
             })
         }).collect();
@@ -792,11 +767,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// the value, we will generate a branch to the appropriate
     /// prebinding block.
     ///
-    /// The return value is a list of "otherwise" blocks. These are
-    /// points in execution where we found that *NONE* of the
-    /// candidates apply. In principle, this means that the input
-    /// list was not exhaustive, though at present we sometimes are
-    /// not smart enough to recognize all exhaustive inputs.
+    /// If we find that *NONE* of the candidates apply, we branch to the
+    /// `otherwise_block`. In principle, this means that the input list was not
+    /// exhaustive, though at present we sometimes are not smart enough to
+    /// recognize all exhaustive inputs.
     ///
     /// It might be surprising that the input can be inexhaustive.
     /// Indeed, initially, it is not, because all matches are
@@ -810,13 +784,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn match_candidates<'pat>(
         &mut self,
         span: Span,
+        start_block: &mut Option<BasicBlock>,
+        otherwise_block: Option<BasicBlock>,
         candidates: &mut [&mut Candidate<'pat, 'tcx>],
-        mut block: BasicBlock,
         fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
-    ) -> Vec<BasicBlock> {
+    ) {
         debug!(
-            "matched_candidate(span={:?}, block={:?}, candidates={:?})",
-            span, block, candidates
+            "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
+            span,
+            candidates,
+            start_block,
+            otherwise_block,
         );
 
         // Start by simplifying candidates. Once this process is complete, all
@@ -839,52 +817,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         );
         let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched);
 
+        let block: BasicBlock;
+
         if !matched_candidates.is_empty() {
-            block = if let Some(last_otherwise_block) = self.select_matched_candidates(
+            let otherwise_block = self.select_matched_candidates(
                 matched_candidates,
-                block,
+                start_block,
                 fake_borrows,
-            ) {
-                last_otherwise_block
+            );
+
+            if let Some(last_otherwise_block) = otherwise_block {
+                block = last_otherwise_block
             } else {
                 // Any remaining candidates are unreachable.
                 if unmatched_candidates.is_empty() {
-                    return Vec::new();
-                } else {
-                    self.cfg.start_new_block()
+                    return;
                 }
+                block = self.cfg.start_new_block();
             };
+        } else {
+            block = *start_block.get_or_insert_with(|| 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];
+            let source_info = self.source_info(span);
+            if let Some(otherwise) = otherwise_block {
+                self.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Goto { target: otherwise },
+                );
+            } else {
+                self.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Unreachable,
+                )
+            }
+            return;
         }
 
-        // Test candidates where possible.
-        let (otherwise, untested_candidates) = self.test_candidates(
+        // Test for the remaining candidates.
+        self.test_candidates(
             span,
             unmatched_candidates,
             block,
+            otherwise_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,
-            fake_borrows,
-        )
     }
 
     /// Link up matched candidates. For example, if we have something like
@@ -908,7 +891,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn select_matched_candidates(
         &mut self,
         matched_candidates: &mut [&mut Candidate<'_, 'tcx>],
-        block: BasicBlock,
+        start_block: &mut Option<BasicBlock>,
         fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
     ) -> Option<BasicBlock> {
         debug_assert!(
@@ -956,16 +939,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             = matched_candidates.split_at_mut(fully_matched_with_guard + 1);
 
         let first_candidate = &reachable_candidates[0];
+        let first_prebinding_block = first_candidate.pre_binding_block;
 
-        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,
-            },
-        );
+        if let Some(start_block) = *start_block {
+            let source_info = self.source_info(first_candidate.span);
+            self.cfg.terminate(
+                start_block,
+                source_info,
+                TerminatorKind::Goto { target: first_prebinding_block },
+            );
+        } else {
+            *start_block = Some(first_prebinding_block);
+        }
 
         for window in reachable_candidates.windows(2) {
             if let [first_candidate, second_candidate] = window {
@@ -1017,25 +1002,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>) -> BasicBlock {
-        let source_info = self.source_info(span);
-        otherwise.sort();
-        otherwise.dedup(); // variant switches can introduce duplicate target blocks
-        if otherwise.len() == 1 {
-            otherwise[0]
-        } else {
-            let join_block = self.cfg.start_new_block();
-            for block in otherwise {
-                self.cfg.terminate(
-                    block,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-            }
-            join_block
-        }
-    }
-
     /// This is the most subtle part of the matching algorithm. At
     /// this point, the input candidates have been fully simplified,
     /// and so we know that all remaining match-pairs require some
@@ -1153,8 +1119,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         span: Span,
         mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
         block: BasicBlock,
+        mut otherwise_block: Option<BasicBlock>,
         fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
-    ) -> (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);
@@ -1208,9 +1175,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             "match_candidates: test={:?} match_pair={:?}",
             test, match_pair
         );
-        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);
+        target_candidates.resize_with(test.targets(), Default::default);
 
         let total_candidate_count = candidates.len();
 
@@ -1236,20 +1202,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // apply. Collect a list of blocks where control flow will
         // branch if one of the `target_candidate` sets is not
         // exhaustive.
-        let otherwise: Vec<_> = target_blocks
-            .into_iter()
-            .zip(target_candidates)
-            .flat_map(|(target_block, mut target_candidates)| {
+        if !candidates.is_empty() {
+            let remainder_start = &mut None;
+            self.match_candidates(
+                span,
+                remainder_start,
+                otherwise_block,
+                candidates,
+                fake_borrows,
+            );
+            otherwise_block = Some(remainder_start.unwrap());
+        };
+        let target_blocks: Vec<_> = target_candidates.into_iter().map(|mut candidates| {
+            if candidates.len() != 0 {
+                let candidate_start = &mut None;
                 self.match_candidates(
                     span,
-                    &mut *target_candidates,
-                    target_block,
+                    candidate_start,
+                    otherwise_block,
+                    &mut *candidates,
                     fake_borrows,
-                )
-            })
-            .collect();
+                );
+                candidate_start.unwrap()
+            } else {
+                *otherwise_block.get_or_insert_with(|| {
+                    let unreachable = self.cfg.start_new_block();
+                    let source_info = self.source_info(span);
+                    self.cfg.terminate(
+                        unreachable,
+                        source_info,
+                        TerminatorKind::Unreachable,
+                    );
+                    unreachable
+                })
+            }
+        }).collect();
 
-        (otherwise, candidates)
+        self.perform_test(
+            block,
+            &match_place,
+            &test,
+            target_blocks,
+        );
     }
 
     // Determine the fake borrows that are needed to ensure that the place
@@ -1323,7 +1317,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         fake_borrows: &Vec<(&Place<'tcx>, Local)>,
         scrutinee_span: Span,
         region_scope: (region::Scope, SourceInfo),
-    ) {
     ) -> BasicBlock {
         debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
 
@@ -1345,10 +1338,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block,
                 fresh_block,
                 candidate.next_candidate_pre_binding_block,
-            candidate_source_info,
-        );
+                candidate_source_info,
+            );
             block = fresh_block;
-        self.ascribe_types(block, &candidate.ascriptions);
+            self.ascribe_types(block, &candidate.ascriptions);
         } else {
             return block;
         }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index c767fff9253..bbaf92bf9f5 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -16,7 +16,6 @@ use rustc::ty::util::IntTypeExt;
 use rustc::ty::layout::VariantIdx;
 use rustc::mir::*;
 use rustc::hir::{RangeEnd, Mutability};
-use syntax_pos::Span;
 use std::cmp::Ordering;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -162,43 +161,50 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Generates the code to perform a test.
-    pub fn perform_test(&mut self,
-                        block: BasicBlock,
-                        place: &Place<'tcx>,
-                        test: &Test<'tcx>)
-                        -> Vec<BasicBlock> {
+    pub fn perform_test(
+        &mut self,
+        block: BasicBlock,
+        place: &Place<'tcx>,
+        test: &Test<'tcx>,
+        target_blocks: Vec<BasicBlock>,
+    ) {
         debug!("perform_test({:?}, {:?}: {:?}, {:?})",
                block,
                place,
                place.ty(&self.local_decls, self.hir.tcx()),
                test);
+
         let source_info = self.source_info(test.span);
         match test.kind {
             TestKind::Switch { adt_def, ref variants } => {
                 // Variants is a BitVec of indexes into adt_def.variants.
                 let num_enum_variants = adt_def.variants.len();
                 let used_variants = variants.count();
-                let mut otherwise_block = None;
-                let mut target_blocks = Vec::with_capacity(num_enum_variants);
+                debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
+                let otherwise_block = *target_blocks.last().unwrap();
                 let mut targets = Vec::with_capacity(used_variants + 1);
                 let mut values = Vec::with_capacity(used_variants);
                 let tcx = self.hir.tcx();
                 for (idx, discr) in adt_def.discriminants(tcx) {
-                    target_blocks.push(if variants.contains(idx) {
+                    if variants.contains(idx) {
+                        debug_assert_ne!(
+                            target_blocks[idx.index()],
+                            otherwise_block,
+                            "no canididates for tested discriminant: {:?}",
+                            discr,
+                        );
                         values.push(discr.val);
-                        let block = self.cfg.start_new_block();
-                        targets.push(block);
-                        block
+                        targets.push(target_blocks[idx.index()]);
                     } else {
-                        *otherwise_block
-                            .get_or_insert_with(|| self.cfg.start_new_block())
-                    });
+                        debug_assert_eq!(
+                            target_blocks[idx.index()],
+                            otherwise_block,
+                            "found canididates for untested discriminant: {:?}",
+                            discr,
+                        );
+                    }
                 }
-                targets.push(
-                    otherwise_block
-                        .unwrap_or_else(|| self.unreachable_block()),
-                );
+                targets.push(otherwise_block);
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
@@ -212,160 +218,61 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     values: From::from(values),
                     targets,
                 });
-                target_blocks
             }
 
             TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
-                let (ret, terminator) = if switch_ty.sty == ty::Bool {
+                let terminator = if switch_ty.sty == ty::Bool {
                     assert!(options.len() > 0 && options.len() <= 2);
-                    let (true_bb, false_bb) = (self.cfg.start_new_block(),
-                                               self.cfg.start_new_block());
-                    let ret = match options[0] {
-                        1 => vec![true_bb, false_bb],
-                        0 => vec![false_bb, true_bb],
-                        v => span_bug!(test.span, "expected boolean value but got {:?}", v)
-                    };
-                    (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
-                                              true_bb, false_bb))
+                    if let [first_bb, second_bb] = *target_blocks {
+                        let (true_bb, false_bb) = match options[0] {
+                            1 => (first_bb, second_bb),
+                            0 => (second_bb, first_bb),
+                            v => span_bug!(test.span, "expected boolean value but got {:?}", v)
+                        };
+                        TerminatorKind::if_(
+                            self.hir.tcx(),
+                            Operand::Copy(place.clone()),
+                            true_bb,
+                            false_bb,
+                        )
+                    } else {
+                        bug!("`TestKind::SwitchInt` on `bool` should have two targets")
+                    }
                 } else {
-                    // The switch may be inexhaustive so we
-                    // add a catch all block
-                    let otherwise = self.cfg.start_new_block();
-                    let targets: Vec<_> =
-                        options.iter()
-                               .map(|_| self.cfg.start_new_block())
-                               .chain(Some(otherwise))
-                               .collect();
-                    (targets.clone(), TerminatorKind::SwitchInt {
+                    // The switch may be inexhaustive so we have a catch all block
+                    debug_assert_eq!(options.len() + 1, target_blocks.len());
+                    TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place.clone()),
                         switch_ty,
                         values: options.clone().into(),
-                        targets,
-                    })
+                        targets: target_blocks,
+                    }
                 };
                 self.cfg.terminate(block, source_info, terminator);
-                ret
             }
 
-            TestKind::Eq { value, mut ty } => {
-                let val = Operand::Copy(place.clone());
-                let mut expect = self.literal_operand(test.span, ty, value);
+            TestKind::Eq { value, ty } => {
                 // Use `PartialEq::eq` instead of `BinOp::Eq`
                 // (the binop can only handle primitives)
-                let fail = self.cfg.start_new_block();
-                if !ty.is_scalar() {
-                    // If we're using `b"..."` as a pattern, we need to insert an
-                    // unsizing coercion, as the byte string has the type `&[u8; N]`.
-                    //
-                    // We want to do this even when the scrutinee is a reference to an
-                    // array, so we can call `<[u8]>::eq` rather than having to find an
-                    // `<[u8; N]>::eq`.
-                    let unsize = |ty: Ty<'tcx>| match ty.sty {
-                        ty::Ref(region, rty, _) => match rty.sty {
-                            ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
-                            _ => None,
-                        },
-                        _ => None,
-                    };
-                    let opt_ref_ty = unsize(ty);
-                    let opt_ref_test_ty = unsize(value.ty);
-                    let mut place = place.clone();
-                    match (opt_ref_ty, opt_ref_test_ty) {
-                        // nothing to do, neither is an array
-                        (None, None) => {},
-                        (Some((region, elem_ty, _)), _) |
-                        (None, Some((region, elem_ty, _))) => {
-                            let tcx = self.hir.tcx();
-                            // make both a slice
-                            ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
-                            if opt_ref_ty.is_some() {
-                                place = self.temp(ty, test.span);
-                                self.cfg.push_assign(
-                                    block, source_info, &place, Rvalue::Cast(
-                                        CastKind::Pointer(PointerCast::Unsize), val, ty
-                                    )
-                                );
-                            }
-                            if opt_ref_test_ty.is_some() {
-                                let array = self.literal_operand(
-                                    test.span,
-                                    value.ty,
-                                    value,
-                                );
-
-                                let slice = self.temp(ty, test.span);
-                                self.cfg.push_assign(
-                                    block, source_info, &slice, Rvalue::Cast(
-                                        CastKind::Pointer(PointerCast::Unsize), array, ty
-                                    )
-                                );
-                                expect = Operand::Move(slice);
-                            }
-                        },
+                if let [success, fail] = *target_blocks {
+                    if !ty.is_scalar() {
+                        self.non_scalar_compare(
+                            block,
+                            success,
+                            fail,
+                            source_info,
+                            value,
+                            place,
+                            ty,
+                        );
+                    } else {
+                        let val = Operand::Copy(place.clone());
+                        let expect = self.literal_operand(test.span, ty, value);
+                        self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
                     }
-                    let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
-                    let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
-
-                    let re_erased = self.hir.tcx().lifetimes.re_erased;
-                    // take the argument by reference
-                    let tam = ty::TypeAndMut {
-                        ty,
-                        mutbl: Mutability::MutImmutable,
-                    };
-                    let ref_ty = self.hir.tcx().mk_ref(re_erased, tam);
-
-                    // let lhs_ref_place = &lhs;
-                    let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place);
-                    let lhs_ref_place = self.temp(ref_ty, test.span);
-                    self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
-                    let val = Operand::Move(lhs_ref_place);
-
-                    // let rhs_place = rhs;
-                    let rhs_place = self.temp(ty, test.span);
-                    self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
-
-                    // let rhs_ref_place = &rhs_place;
-                    let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place);
-                    let rhs_ref_place = self.temp(ref_ty, test.span);
-                    self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
-                    let expect = Operand::Move(rhs_ref_place);
-
-                    let bool_ty = self.hir.bool_ty();
-                    let eq_result = self.temp(bool_ty, test.span);
-                    let eq_block = self.cfg.start_new_block();
-                    let cleanup = self.diverge_cleanup();
-                    self.cfg.terminate(block, source_info, TerminatorKind::Call {
-                        func: Operand::Constant(box Constant {
-                            span: test.span,
-                            ty: mty,
-
-                            // FIXME(#54571): This constant comes from user
-                            // input (a constant in a pattern).  Are
-                            // there forms where users can add type
-                            // annotations here?  For example, an
-                            // associated constant? Need to
-                            // experiment.
-                            user_ty: None,
-
-                            literal: method,
-                        }),
-                        args: vec![val, expect],
-                        destination: Some((eq_result.clone(), eq_block)),
-                        cleanup: Some(cleanup),
-                        from_hir_call: false,
-                    });
-
-                    // check the result
-                    let block = self.cfg.start_new_block();
-                    self.cfg.terminate(eq_block, source_info,
-                                       TerminatorKind::if_(self.hir.tcx(),
-                                                           Operand::Move(eq_result),
-                                                           block, fail));
-                    vec![block, fail]
                 } else {
-                    let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
-                    vec![block, fail]
-                }
+                    bug!("`TestKind::Eq` should have two target blocks")
+                };
             }
 
             TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
@@ -374,20 +281,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let hi = self.literal_operand(test.span, ty, hi);
                 let val = Operand::Copy(place.clone());
 
-                let fail = self.cfg.start_new_block();
-                let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
-                let block = match *end {
-                    RangeEnd::Included => self.compare(block, fail, test.span, BinOp::Le, val, hi),
-                    RangeEnd::Excluded => self.compare(block, fail, test.span, BinOp::Lt, val, hi),
-                };
-
-                vec![block, fail]
+                if let [success, fail] = *target_blocks {
+                    let lower_bound_success = self.cfg.start_new_block();
+
+                    self.compare(
+                        block,
+                        lower_bound_success,
+                        fail,
+                        source_info,
+                        BinOp::Le,
+                        lo,
+                        val.clone(),
+                    );
+                    let op = match *end {
+                        RangeEnd::Included => BinOp::Le,
+                        RangeEnd::Excluded => BinOp::Lt,
+                    };
+                    self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
+                } else {
+                    bug!("`TestKind::Range` should have two target blocks");
+                }
             }
 
             TestKind::Len { len, op } => {
-                let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
-                let (actual, result) = (self.temp(usize_ty, test.span),
-                                        self.temp(bool_ty, test.span));
+                let usize_ty = self.hir.usize_ty();
+                let actual = self.temp(usize_ty, test.span);
 
                 // actual = len(place)
                 self.cfg.push_assign(block, source_info,
@@ -396,44 +314,188 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // expected = <N>
                 let expected = self.push_usize(block, source_info, len);
 
-                // result = actual == expected OR result = actual < expected
-                self.cfg.push_assign(block, source_info, &result,
-                                     Rvalue::BinaryOp(op,
-                                                      Operand::Move(actual),
-                                                      Operand::Move(expected)));
-
-                // branch based on result
-                let (false_bb, true_bb) = (self.cfg.start_new_block(),
-                                           self.cfg.start_new_block());
-                self.cfg.terminate(block, source_info,
-                                   TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
-                                                       true_bb, false_bb));
-                vec![true_bb, false_bb]
+                if let [true_bb, false_bb] = *target_blocks {
+                    // result = actual == expected OR result = actual < expected
+                    // branch based on result
+                    self.compare(
+                        block,
+                        true_bb,
+                        false_bb,
+                        source_info,
+                        op,
+                        Operand::Move(actual),
+                        Operand::Move(expected),
+                    );
+                } else {
+                    bug!("`TestKind::Len` should have two target blocks");
+                }
             }
         }
     }
 
-    fn compare(&mut self,
-               block: BasicBlock,
-               fail_block: BasicBlock,
-               span: Span,
-               op: BinOp,
-               left: Operand<'tcx>,
-               right: Operand<'tcx>) -> BasicBlock {
+    /// Compare using the provided built-in comparison operator
+    fn compare(
+        &mut self,
+        block: BasicBlock,
+        success_block: BasicBlock,
+        fail_block: BasicBlock,
+        source_info: SourceInfo,
+        op: BinOp,
+        left: Operand<'tcx>,
+        right: Operand<'tcx>,
+    ) {
         let bool_ty = self.hir.bool_ty();
-        let result = self.temp(bool_ty, span);
+        let result = self.temp(bool_ty, source_info.span);
 
         // result = op(left, right)
-        let source_info = self.source_info(span);
-        self.cfg.push_assign(block, source_info, &result,
-                             Rvalue::BinaryOp(op, left, right));
+        self.cfg.push_assign(
+            block,
+            source_info,
+            &result,
+            Rvalue::BinaryOp(op, left, right),
+        );
 
         // branch based on result
-        let target_block = self.cfg.start_new_block();
-        self.cfg.terminate(block, source_info,
-                           TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
-                                               target_block, fail_block));
-        target_block
+        self.cfg.terminate(
+            block,
+            source_info,
+            TerminatorKind::if_(
+                self.hir.tcx(),
+                Operand::Move(result),
+                success_block,
+                fail_block,
+            ),
+        );
+    }
+
+    /// Compare using `std::compare::PartialEq::eq`
+    fn non_scalar_compare(
+        &mut self,
+        block: BasicBlock,
+        success_block: BasicBlock,
+        fail_block: BasicBlock,
+        source_info: SourceInfo,
+        value: &'tcx ty::Const<'tcx>,
+        place: &Place<'tcx>,
+        mut ty: Ty<'tcx>,
+    ) {
+        use rustc::middle::lang_items::EqTraitLangItem;
+
+        let mut expect = self.literal_operand(source_info.span, ty, value);
+        let val = Operand::Copy(place.clone());
+
+        // If we're using `b"..."` as a pattern, we need to insert an
+        // unsizing coercion, as the byte string has the type `&[u8; N]`.
+        //
+        // We want to do this even when the scrutinee is a reference to an
+        // array, so we can call `<[u8]>::eq` rather than having to find an
+        // `<[u8; N]>::eq`.
+        let unsize = |ty: Ty<'tcx>| match ty.sty {
+            ty::Ref(region, rty, _) => match rty.sty {
+                ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
+                _ => None,
+            },
+            _ => None,
+        };
+        let opt_ref_ty = unsize(ty);
+        let opt_ref_test_ty = unsize(value.ty);
+        let mut place = place.clone();
+        match (opt_ref_ty, opt_ref_test_ty) {
+            // nothing to do, neither is an array
+            (None, None) => {},
+            (Some((region, elem_ty, _)), _) |
+            (None, Some((region, elem_ty, _))) => {
+                let tcx = self.hir.tcx();
+                // make both a slice
+                ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
+                if opt_ref_ty.is_some() {
+                    place = self.temp(ty, source_info.span);
+                    self.cfg.push_assign(
+                        block, source_info, &place, Rvalue::Cast(
+                            CastKind::Pointer(PointerCast::Unsize), val, ty
+                        )
+                    );
+                }
+                if opt_ref_test_ty.is_some() {
+                    let array = self.literal_operand(
+                        source_info.span,
+                        value.ty,
+                        value,
+                    );
+
+                    let slice = self.temp(ty, source_info.span);
+                    self.cfg.push_assign(
+                        block, source_info, &slice, Rvalue::Cast(
+                            CastKind::Pointer(PointerCast::Unsize), array, ty
+                        )
+                    );
+                    expect = Operand::Move(slice);
+                }
+            },
+        }
+        let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem);
+        let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
+
+        let re_erased = self.hir.tcx().lifetimes.re_erased;
+        // take the argument by reference
+        let tam = ty::TypeAndMut {
+            ty,
+            mutbl: Mutability::MutImmutable,
+        };
+        let ref_ty = self.hir.tcx().mk_ref(re_erased, tam);
+
+        // let lhs_ref_place = &lhs;
+        let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place);
+        let lhs_ref_place = self.temp(ref_ty, source_info.span);
+        self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
+        let val = Operand::Move(lhs_ref_place);
+
+        // let rhs_place = rhs;
+        let rhs_place = self.temp(ty, source_info.span);
+        self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
+
+        // let rhs_ref_place = &rhs_place;
+        let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place);
+        let rhs_ref_place = self.temp(ref_ty, source_info.span);
+        self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
+        let expect = Operand::Move(rhs_ref_place);
+
+        let bool_ty = self.hir.bool_ty();
+        let eq_result = self.temp(bool_ty, source_info.span);
+        let eq_block = self.cfg.start_new_block();
+        let cleanup = self.diverge_cleanup();
+        self.cfg.terminate(block, source_info, TerminatorKind::Call {
+            func: Operand::Constant(box Constant {
+                span: source_info.span,
+                ty: mty,
+
+                // FIXME(#54571): This constant comes from user
+                // input (a constant in a pattern).  Are
+                // there forms where users can add type
+                // annotations here?  For example, an
+                // associated constant? Need to
+                // experiment.
+                user_ty: None,
+
+                literal: method,
+            }),
+            args: vec![val, expect],
+            destination: Some((eq_result.clone(), eq_block)),
+            cleanup: Some(cleanup),
+            from_hir_call: false,
+        });
+
+        // check the result
+        self.cfg.terminate(
+            eq_block,
+            source_info,
+            TerminatorKind::if_(
+                self.hir.tcx(),
+                Operand::Move(eq_result),
+                success_block,
+                fail_block,
+            ),
+        );
     }
 
     /// Given that we are performing `test` against `test_place`, this job
@@ -755,6 +817,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     }
 }
 
+impl Test<'_> {
+    pub(super) fn targets(&self) -> usize {
+        match self.kind {
+            TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => {
+                2
+            }
+            TestKind::Switch { adt_def, .. } => {
+                adt_def.variants.len() + 1
+            }
+            TestKind::SwitchInt { switch_ty, ref options, .. } => {
+                if switch_ty.is_bool() {
+                    2
+                } else {
+                    options.len() + 1
+                }
+            }
+        }
+    }
+}
+
 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
     ty.is_integral() || ty.is_char() || ty.is_bool()
 }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 579a403f3ac..fdab73eb3ca 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -952,17 +952,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }
     }
-
-    fn unreachable_block(&mut self) -> BasicBlock {
-        match self.cached_unreachable_block {
-            Some(ub) => ub,
-            None => {
-                let ub = self.cfg.start_new_block();
-                self.cached_unreachable_block = Some(ub);
-                ub
-            }
-        }
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 125411a717d..2fc52969a3c 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1448,6 +1448,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
             StatementKind::Assign(..) => {
                 self.super_statement(statement, location);
             }
+            StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
+                self.not_const();
+            }
             // FIXME(eddyb) should these really do nothing?
             StatementKind::FakeRead(..) |
             StatementKind::SetDiscriminant { .. } |
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 7f5afb2394a..418a88859ac 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -211,6 +211,10 @@ fn check_statement(
             check_rvalue(tcx, body, rval, span)
         }
 
+        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
+            Err((span, "loops and conditional expressions are not stable in const fn".into()))
+        }
+
         StatementKind::FakeRead(_, place) => check_place(place, span),
 
         // just an assignment
diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs
index 1b46bb3b25f..145d4ba6b4c 100644
--- a/src/test/codegen/match.rs
+++ b/src/test/codegen/match.rs
@@ -14,12 +14,12 @@ pub fn exhaustive_match(e: E, unit: ()) {
 // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
 // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
 // CHECK-NEXT: ]
+// CHECK: [[B]]:
+// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
 // CHECK: [[OTHERWISE]]:
 // CHECK-NEXT: unreachable
 // CHECK: [[A]]:
 // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
-// CHECK: [[B]]:
-// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
     match e {
         E::A => unit,
         E::B => unit,
diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs
index da6036a04a5..87a9cf9490d 100644
--- a/src/test/compile-fail/const-fn-error.rs
+++ b/src/test/compile-fail/const-fn-error.rs
@@ -7,6 +7,7 @@ const fn f(x: usize) -> usize {
     for i in 0..x {
         //~^ ERROR E0015
         //~| ERROR E0019
+        //~| ERROR E0019
         //~| ERROR E0080
         sum += i;
     }
diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs
index e1f07ff96be..0d6906086e9 100644
--- a/src/test/compile-fail/issue-52443.rs
+++ b/src/test/compile-fail/issue-52443.rs
@@ -4,5 +4,6 @@ fn main() {
     [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
     [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
     //~^ ERROR constant contains unimplemented expression type
+    //~| ERROR constant contains unimplemented expression type
     //~| ERROR evaluation of constant value failed
 }
diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs
index 0df1112ec3e..904d303d87e 100644
--- a/src/test/mir-opt/const_prop/switch_int.rs
+++ b/src/test/mir-opt/const_prop/switch_int.rs
@@ -13,26 +13,26 @@ fn main() {
 //  bb0: {
 //      ...
 //      _1 = const 1i32;
-//      switchInt(_1) -> [1i32: bb1, otherwise: bb2];
+//      switchInt(_1) -> [1i32: bb2, otherwise: bb1];
 //  }
 // END rustc.main.ConstProp.before.mir
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+//      switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1];
 //  }
 // END rustc.main.ConstProp.after.mir
 // START rustc.main.SimplifyBranches-after-const-prop.before.mir
 //  bb0: {
 //      ...
 //      _1 = const 1i32;
-//      switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+//      switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1];
 //  }
 // END rustc.main.SimplifyBranches-after-const-prop.before.mir
 // START rustc.main.SimplifyBranches-after-const-prop.after.mir
 //  bb0: {
 //      ...
 //      _1 = const 1i32;
-//      goto -> bb1;
+//      goto -> bb2;
 //  }
 // END rustc.main.SimplifyBranches-after-const-prop.after.mir
diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs
index 59c75739d81..b39ad1bef8e 100644
--- a/src/test/mir-opt/deaggregator_test_enum_2.rs
+++ b/src/test/mir-opt/deaggregator_test_enum_2.rs
@@ -21,30 +21,22 @@ fn main() {
 // END RUST SOURCE
 // START rustc.test1.Deaggregator.before.mir
 //  bb1: {
-//      StorageLive(_4);
-//      _4 = _2;
-//      _0 = Foo::A(move _4,);
-//      StorageDead(_4);
-//      goto -> bb3;
-//  }
-//  bb2: {
 //      StorageLive(_5);
 //      _5 = _2;
 //      _0 = Foo::B(move _5,);
 //      StorageDead(_5);
 //      goto -> bb3;
 //  }
-// END rustc.test1.Deaggregator.before.mir
-// START rustc.test1.Deaggregator.after.mir
-//  bb1: {
+//  bb2: {
 //      StorageLive(_4);
 //      _4 = _2;
-//      ((_0 as A).0: i32) = move _4;
-//      discriminant(_0) = 0;
+//      _0 = Foo::A(move _4,);
 //      StorageDead(_4);
 //      goto -> bb3;
 //  }
-//  bb2: {
+// END rustc.test1.Deaggregator.before.mir
+// START rustc.test1.Deaggregator.after.mir
+//  bb1: {
 //      StorageLive(_5);
 //      _5 = _2;
 //      ((_0 as B).0: i32) = move _5;
@@ -52,5 +44,13 @@ fn main() {
 //      StorageDead(_5);
 //      goto -> bb3;
 //  }
+//  bb2: {
+//      StorageLive(_4);
+//      _4 = _2;
+//      ((_0 as A).0: i32) = move _4;
+//      discriminant(_0) = 0;
+//      StorageDead(_4);
+//      goto -> bb3;
+//  }
 // END rustc.test1.Deaggregator.after.mir
 //
diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs
index e8ab690bb46..909f9b7b6b7 100644
--- a/src/test/mir-opt/issue-38669.rs
+++ b/src/test/mir-opt/issue-38669.rs
@@ -31,17 +31,17 @@ fn main() {
 //         switchInt(_4) -> [false: bb5, otherwise: bb4];
 //     }
 //     ...
-//     bb7: {
-//         _0 = ();
-//         StorageDead(_4);
-//         StorageDead(_1);
-//         return;
-//     }
-//     bb8: {
+//     bb5: {
 //         _3 = ();
 //         StorageDead(_4);
 //         _1 = const true;
 //         _2 = ();
 //         goto -> bb2;
 //     }
+//     bb6: {
+//         _0 = ();
+//         StorageDead(_4);
+//         StorageDead(_1);
+//         return;
+//     }
 // END rustc.main.SimplifyCfg-initial.after.mir
diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs
index 447f3a07a6a..9dde6d821f2 100644
--- a/src/test/mir-opt/issue-49232.rs
+++ b/src/test/mir-opt/issue-49232.rs
@@ -32,76 +32,58 @@ fn main() {
 //         falseUnwind -> [real: bb3, cleanup: bb4];
 //     }
 //     bb2: {
-//         goto -> bb20;
+//         goto -> bb14;
 //     }
 //     bb3: {
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         _3 = const true;
 //         FakeRead(ForMatchedPlace, _3);
-//         switchInt(_3) -> [false: bb9, otherwise: bb8];
+//         switchInt(_3) -> [false: bb5, otherwise: bb6];
 //     }
 //     bb4 (cleanup): {
 //         resume;
 //     }
 //     bb5: {
-//         falseEdges -> [real: bb11, imaginary: bb6];
+//         falseEdges -> [real: bb7, imaginary: bb6];
 //     }
 //     bb6: {
-//         falseEdges -> [real: bb13, imaginary: bb7];
+//         _0 = ();
+//         goto -> bb8;
 //     }
 //     bb7: {
-//         unreachable;
-//     }
-//     bb8: {
-//         goto -> bb6;
-//     }
-//     bb9: {
-//         goto -> bb5;
-//     }
-//     bb10: {
 //         _2 = const 4i32;
-//         goto -> bb18;
-//     }
-//     bb11: {
-//         goto -> bb10;
-//     }
-//     bb12: {
-//         _0 = ();
-//         goto -> bb14;
-//     }
-//     bb13: {
 //         goto -> bb12;
 //     }
-//     bb14: {
+//     bb8: {
 //         StorageDead(_3);
-//         goto -> bb15;
+//         goto -> bb9;
 //     }
-//     bb15: {
+//     bb9: {
 //         StorageDead(_2);
 //         goto -> bb2;
 //     }
-//     bb16: {
+//     bb10: {
 //         _4 = ();
 //         unreachable;
 //     }
-//     bb17: {
-//         goto -> bb18;
+//     bb11: {
+//         goto -> bb12;
 //     }
-//     bb18: {
+//     bb12: {
 //         FakeRead(ForLet, _2);
 //         StorageDead(_3);
 //         StorageLive(_6);
 //         _6 = &_2;
-//         _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb19, unwind: bb4];
+//         _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4];
 //     }
-//     bb19: {
+//     bb13: {
 //         StorageDead(_6);
 //         _1 = ();
 //         StorageDead(_2);
 //         goto -> bb1;
 //     }
-//     bb20: {
+//     bb14: {
 //         return;
 //     }
 // }
diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs
index e75955b9b24..68ea60d9278 100644
--- a/src/test/mir-opt/loop_test.rs
+++ b/src/test/mir-opt/loop_test.rs
@@ -22,20 +22,21 @@ fn main() {
 //        resume;
 //    }
 //    ...
-//    bb6: { // Entry into the loop
+//    bb3: { // Entry into the loop
 //        _1 = ();
 //        StorageDead(_2);
-//        goto -> bb7;
+//        goto -> bb5;
 //    }
-//    bb7: { // The loop_block
-//        falseUnwind -> [real: bb8, cleanup: bb1];
+//    ...
+//    bb5: { // The loop_block
+//        falseUnwind -> [real: bb6, cleanup: bb1];
 //    }
-//    bb8: { // The loop body (body_block)
+//    bb6: { // The loop body (body_block)
 //        StorageLive(_6);
 //        _6 = const 1i32;
 //        FakeRead(ForLet, _6);
 //        StorageDead(_6);
-//        goto -> bb7;
+//        goto -> bb5;
 //    }
 //    ...
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs
index 0f026b8a08d..a2bc238c68a 100644
--- a/src/test/mir-opt/match-arm-scopes.rs
+++ b/src/test/mir-opt/match-arm-scopes.rs
@@ -42,55 +42,49 @@ fn main() {
 // let mut _0: i32;
 // let mut _3: &bool;                   // Temp for fake borrow of `items.0`
 // let mut _4: &bool;                   // Temp for fake borrow of `items.1`
-// let _5: bool;                    // `a` in arm
-// let _6: &bool;                   // `a` in guard
-// let _7: std::string::String;     // `s` in arm
-// let _8: &std::string::String;    // `s` in guard
+// let _5: bool;                        // `a` in arm
+// let _6: &bool;                       // `a` in guard
+// let _7: std::string::String;         // `s` in arm
+// let _8: &std::string::String;        // `s` in guard
 // let mut _9: bool;                    // `if cond { return 3 } else { a }`
 // let mut _10: bool;                   // `cond`
 // let mut _11: !;                      // `return 3`
 // let mut _12: bool;                   // `if cond { return 3 } else { a }`
 // let mut _13: bool;                   // `cond`
 // let mut _14: !;                      // `return 3`
-// let _15: bool;                   // `b`
-// let _16: std::string::String;    // `t`
+// let _15: bool;                       // `b`
+// let _16: std::string::String;        // `t`
 // scope 1 {
 // }
 // scope 2 {
 // }
 // bb0: {
 //     FakeRead(ForMatchedPlace, _2);
-//     switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb7];
+//     switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb5];
 // }
 // bb1 (cleanup): {
 //     resume;
 // }
 // bb2: {
-//     falseEdges -> [real: bb10, imaginary: bb3];
+//     falseEdges -> [real: bb8, imaginary: bb3];
 // }
 // bb3: {
-//     falseEdges -> [real: bb21, imaginary: bb4];
+//     falseEdges -> [real: bb17, imaginary: bb4];
 // }
 // bb4: {
-//     falseEdges -> [real: bb31, imaginary: bb5];
+//     falseEdges -> [real: bb25, imaginary: bb26];
 // }
 // bb5: {
-//     falseEdges -> [real: bb32, imaginary: bb6];
+//     switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb6];
 // }
 // bb6: {
-//     unreachable;
+//     switchInt((_2.0: bool)) -> [false: bb26, otherwise: bb4];
 // }
-// bb7: {
-//     switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb8];
-// }
-// bb8: {
-//     switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb4];
-// }
-// bb9: {                               // arm 1
+// bb7: {                               // arm 1
 //     _0 = const 1i32;
-//     drop(_7) -> [return: bb29, unwind: bb16];
+//     drop(_7) -> [return: bb23, unwind: bb13];
 // }
-// bb10: {                              // guard - first time
+// bb8: {                               // guard - first time
 //     StorageLive(_6);
 //     _6 = &(_2.1: bool);
 //     StorageLive(_8);
@@ -101,58 +95,52 @@ fn main() {
 //     StorageLive(_10);
 //     _10 = _1;
 //     FakeRead(ForMatchedPlace, _10);
-//     switchInt(_10) -> [false: bb12, otherwise: bb11];
+//     switchInt(_10) -> [false: bb10, otherwise: bb9];
 // }
-// bb11: {
-//     falseEdges -> [real: bb14, imaginary: bb12];
+// bb9: {
+//     falseEdges -> [real: bb11, imaginary: bb10];
 // }
-// bb12: {
-//     falseEdges -> [real: bb18, imaginary: bb13];
-// }
-// bb13: {
-//     unreachable;
+// bb10: {                              // `else` block - first time
+//     _9 = (*_6);
+//     StorageDead(_10);
+//     FakeRead(ForMatchGuard, _3);
+//     FakeRead(ForMatchGuard, _4);
+//     FakeRead(ForGuardBinding, _6);
+//     FakeRead(ForGuardBinding, _8);
+//     switchInt(move _9) -> [false: bb16, otherwise: bb15];
 // }
-// bb14: {                              // `return 3` - first time
+// bb11: {                              // `return 3` - first time
 //     _0 = const 3i32;
 //     StorageDead(_10);
 //     StorageDead(_9);
 //     StorageDead(_8);
 //     StorageDead(_6);
-//     goto -> bb17;
+//     goto -> bb14;
 // }
-// bb15: {
+// bb12: {
 //     return;
 // }
-// bb16 (cleanup): {
+// bb13 (cleanup): {
 //     drop(_2) -> bb1;
 // }
-// bb17: {
-//     drop(_2) -> [return: bb15, unwind: bb1];
-// }
-// bb18: {                              // `else` block - first time
-//     _9 = (*_6);
-//     StorageDead(_10);
-//     FakeRead(ForMatchGuard, _3);
-//     FakeRead(ForMatchGuard, _4);
-//     FakeRead(ForGuardBinding, _6);
-//     FakeRead(ForGuardBinding, _8);
-//     switchInt(move _9) -> [false: bb20, otherwise: bb19];
+// bb14: {
+//     drop(_2) -> [return: bb12, unwind: bb1];
 // }
-// bb19: {
+// bb15: {
 //     StorageDead(_9);
 //     StorageLive(_5);
 //     _5 = (_2.1: bool);
 //     StorageLive(_7);
 //     _7 = move (_2.2: std::string::String);
-//     goto -> bb9;
+//     goto -> bb7;
 // }
-// bb20: {                              // guard otherwise case - first time
+// bb16: {                              // guard otherwise case - first time
 //     StorageDead(_9);
 //     StorageDead(_8);
 //     StorageDead(_6);
-//     falseEdges -> [real: bb7, imaginary: bb3];
+//     falseEdges -> [real: bb5, imaginary: bb3];
 // }
-// bb21: {                              // guard - second time
+// bb17: {                              // guard - second time
 //     StorageLive(_6);
 //     _6 = &(_2.0: bool);
 //     StorageLive(_8);
@@ -163,80 +151,74 @@ fn main() {
 //     StorageLive(_13);
 //     _13 = _1;
 //     FakeRead(ForMatchedPlace, _13);
-//     switchInt(_13) -> [false: bb23, otherwise: bb22];
-// }
-// bb22: {
-//     falseEdges -> [real: bb25, imaginary: bb23];
-// }
-// bb23: {
-//     falseEdges -> [real: bb26, imaginary: bb24];
+//     switchInt(_13) -> [false: bb19, otherwise: bb18];
 // }
-// bb24: {
-//     unreachable;
+// bb18: {
+//     falseEdges -> [real: bb20, imaginary: bb19];
 // }
-// bb25: {                              // `return 3` - second time
-//     _0 = const 3i32;
-//     StorageDead(_13);
-//     StorageDead(_12);
-//     StorageDead(_8);
-//     StorageDead(_6);
-//     goto -> bb17;
-// }
-// bb26: {                              // `else` block - second time
+// bb19: {                              // `else` block - second time
 //     _12 = (*_6);
 //     StorageDead(_13);
 //     FakeRead(ForMatchGuard, _3);
 //     FakeRead(ForMatchGuard, _4);
 //     FakeRead(ForGuardBinding, _6);
 //     FakeRead(ForGuardBinding, _8);
-//     switchInt(move _12) -> [false: bb28, otherwise: bb27];
+//     switchInt(move _12) -> [false: bb22, otherwise: bb21];
+// }
+// bb20: {
+//     _0 = const 3i32;
+//     StorageDead(_13);
+//     StorageDead(_12);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     goto -> bb14;
 // }
-// bb27: {                              // Guard otherwise case - second time
+// bb21: {                              // bindings for arm 1
 //     StorageDead(_12);
 //     StorageLive(_5);
 //     _5 = (_2.0: bool);
 //     StorageLive(_7);
 //     _7 = move (_2.2: std::string::String);
-//     goto -> bb9;
+//     goto -> bb7;
 // }
-// bb28: {                              // rest of arm 1
+// bb22: {                              // Guard otherwise case - second time
 //     StorageDead(_12);
 //     StorageDead(_8);
 //     StorageDead(_6);
-//     falseEdges -> [real: bb8, imaginary: bb4];
+//     falseEdges -> [real: bb6, imaginary: bb4];
 // }
-// bb29: {
+// bb23: {                              // rest of arm 1
 //     StorageDead(_7);
 //     StorageDead(_5);
 //     StorageDead(_8);
 //     StorageDead(_6);
-//     goto -> bb34;
+//     goto -> bb28;
 // }
-// bb30: {                              // arm 2
+// bb24: {                              // arm 2
 //     _0 = const 2i32;
-//     drop(_16) -> [return: bb33, unwind: bb16];
+//     drop(_16) -> [return: bb27, unwind: bb13];
 // }
-// bb31: {                              // bindings for arm 2 - first pattern
+// bb25: {                              // bindings for arm 2 - first pattern
 //     StorageLive(_15);
 //     _15 = (_2.1: bool);
 //     StorageLive(_16);
 //     _16 = move (_2.2: std::string::String);
-//     goto -> bb30;
+//     goto -> bb24;
 // }
-// bb32: {                              // bindings for arm 2 - first pattern
+// bb26: {                              // bindings for arm 2 - second pattern
 //     StorageLive(_15);
 //     _15 = (_2.1: bool);
 //     StorageLive(_16);
 //     _16 = move (_2.2: std::string::String);
-//     goto -> bb30;
+//     goto -> bb24;
 // }
-// bb33: {                              // rest of arm 2
+// bb27: {                              // rest of arm 2
 //     StorageDead(_16);
 //     StorageDead(_15);
-//     goto -> bb34;
+//     goto -> bb28;
 // }
-// bb34: {                              // end of match
-//     drop(_2) -> [return: bb15, unwind: bb1];
+// bb28: {
+//     drop(_2) -> [return: bb12, unwind: bb1];
 // }
 // END rustc.complicated_match.SimplifyCfg-initial.after.mir
 // START rustc.complicated_match.ElaborateDrops.after.mir
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 6979924c8cd..a62e1b21dd1 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -45,39 +45,37 @@ fn main() {
 //      _2 = std::option::Option::<i32>::Some(const 42i32,);
 //      FakeRead(ForMatchedPlace, _2);
 //      _3 = discriminant(_2);
-//      switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb6];
+//      switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb5];
 //  }
 //  bb1 (cleanup): {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
+//      falseEdges -> [real: bb6, imaginary: bb3]; //pre_binding1
 //  }
 //  bb3: {
-//      falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
+//      falseEdges -> [real: bb10, imaginary: bb4]; //pre_binding2
 //  }
-//  bb4: {
-//      falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3
+//  bb4: { //pre_binding3 and arm3
+//      _1 = (const 3i32, const 3i32);
+//      goto -> bb11;
 //  }
 //  bb5: {
 //      unreachable;
 //  }
-//  bb6: {
-//      unreachable;
-//  }
-//  bb7: { // binding1 and guard
+//  bb6: { // binding1 and guard
 //      StorageLive(_6);
 //      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
-//      _7 = const guard() -> [return: bb8, unwind: bb1];
+//      _7 = const guard() -> [return: bb7, unwind: bb1];
 //  }
-//  bb8: { // end of guard
+//  bb7: { // end of guard
 //      FakeRead(ForMatchGuard, _4);
 //      FakeRead(ForGuardBinding, _6);
-//      switchInt(move _7) -> [false: bb10, otherwise: bb9];
+//      switchInt(move _7) -> [false: bb9, otherwise: bb8];
 //  }
-//  bb9: { // arm1
+//  bb8: { // arm1
 //      StorageDead(_7);
 //      StorageLive(_5);
 //      _5 = ((_2 as Some).0: i32);
@@ -87,14 +85,14 @@ fn main() {
 //      StorageDead(_8);
 //      StorageDead(_5);
 //      StorageDead(_6);
-//      goto -> bb13;
+//      goto -> bb11;
 //  }
-//  bb10: { // to pre_binding2
+//  bb9: { // to pre_binding2
 //      StorageDead(_7);
 //      StorageDead(_6);
-//      falseEdges -> [real: bb3, imaginary: bb3];
+//      goto -> bb3;
 //  }
-//  bb11: { // arm2
+//  bb10: { // arm2
 //      StorageLive(_9);
 //      _9 = ((_2 as Some).0: i32);
 //      StorageLive(_10);
@@ -102,13 +100,9 @@ fn main() {
 //      _1 = (const 2i32, move _10);
 //      StorageDead(_10);
 //      StorageDead(_9);
-//      goto -> bb13;
+//      goto -> bb11;
 //  }
-//  bb12: { // arm3
-//      _1 = (const 3i32, const 3i32);
-//      goto -> bb13;
-//  }
-//  bb13: {
+//  bb11: { // arm3
 //      StorageDead(_2);
 //      StorageDead(_1);
 //      _0 = ();
@@ -122,39 +116,33 @@ fn main() {
 //      _2 = std::option::Option::<i32>::Some(const 42i32,);
 //      FakeRead(ForMatchedPlace, _2);
 //      _3 = discriminant(_2);
-//      switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb6];
+//      switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb4];
 //  }
 //  bb1 (cleanup): {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb7, imaginary: bb3];
+//      falseEdges -> [real: bb5, imaginary: bb3];
 //  }
 //  bb3: {
-//      falseEdges -> [real: bb11, imaginary: bb4];
+//      falseEdges -> [real: bb9, imaginary: bb10];
 //  }
-//  bb4: {
-//      falseEdges -> [real: bb12, imaginary: bb5];
-//  }
-//  bb5: {
+//  bb4: { // to arm3 (can skip 2 since this is `Some`)
 //      unreachable;
 //  }
-//  bb6: {
-//      unreachable;
-//  }
-//  bb7: { // binding1 and guard
+//  bb5: { // binding1 and guard
 //      StorageLive(_6);
 //      _6 = &((_2 as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
-//      _7 = const guard() -> [return: bb8, unwind: bb1];
+//      _7 = const guard() -> [return: bb6, unwind: bb1];
 //  }
-//  bb8: { // end of guard
+//  bb6: { // end of guard
 //      FakeRead(ForMatchGuard, _4);
 //      FakeRead(ForGuardBinding, _6);
-//      switchInt(move _7) -> [false: bb10, otherwise: bb9];
+//      switchInt(move _7) -> [false: bb8, otherwise: bb7];
 //  }
-//  bb9: { // arm1
+//  bb7: {
 //      StorageDead(_7);
 //      StorageLive(_5);
 //      _5 = ((_2 as Some).0: i32);
@@ -164,18 +152,18 @@ fn main() {
 //      StorageDead(_8);
 //      StorageDead(_5);
 //      StorageDead(_6);
-//      goto -> bb13;
+//      goto -> bb11;
 //  }
-//  bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
+//  bb8: { // to pre_binding3 (can skip 2 since this is `Some`)
 //      StorageDead(_7);
 //      StorageDead(_6);
-//      falseEdges -> [real: bb4, imaginary: bb3];
+//      falseEdges -> [real: bb10, imaginary: bb3];
 //  }
-//  bb11: { // arm2
+//  bb9: { // arm2
 //      _1 = (const 3i32, const 3i32);
-//      goto -> bb13;
+//      goto -> bb11;
 //  }
-//  bb12: { // binding3 and arm3
+//  bb10: { // binding3 and arm3
 //      StorageLive(_9);
 //      _9 = ((_2 as Some).0: i32);
 //      StorageLive(_10);
@@ -183,9 +171,9 @@ fn main() {
 //      _1 = (const 2i32, move _10);
 //      StorageDead(_10);
 //      StorageDead(_9);
-//      goto -> bb13;
+//      goto -> bb11;
 //  }
-//  bb13: {
+//  bb11: {
 //      StorageDead(_2);
 //      StorageDead(_1);
 //      _0 = ();
@@ -198,97 +186,91 @@ fn main() {
 //     ...
 //      _2 = std::option::Option::<i32>::Some(const 1i32,);
 //      FakeRead(ForMatchedPlace, _2);
-//      _3 = discriminant(_2);
-//      switchInt(move _3) -> [1isize: bb2, otherwise: bb3];
+//      _4 = discriminant(_2);
+//      switchInt(move _4) -> [1isize: bb2, otherwise: bb3];
 //  }
 //  bb1 (cleanup): {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb7, imaginary: bb3];
+//      falseEdges -> [real: bb5, imaginary: bb3];
 //  }
 //  bb3: {
-//      falseEdges -> [real: bb11, imaginary: bb4];
+//      falseEdges -> [real: bb9, imaginary: bb4];
 //  }
 //  bb4: {
-//      falseEdges -> [real: bb12, imaginary: bb5];
+//      falseEdges -> [real: bb10, imaginary: bb14];
 //  }
 //  bb5: {
-//      falseEdges -> [real: bb16, imaginary: bb6];
-//  }
-//  bb6: {
-//      unreachable;
-//  }
-//  bb7: { // binding1: Some(w) if guard()
 //      StorageLive(_7);
 //      _7 = &((_2 as Some).0: i32);
 //      _5 = &shallow _2;
 //      StorageLive(_8);
-//      _8 = const guard() -> [return: bb8, unwind: bb1];
+//      _8 = const guard() -> [return: bb6, unwind: bb1];
 //  }
-//  bb8: { //end of guard1
+//  bb6: { //end of guard1
 //      FakeRead(ForMatchGuard, _5);
 //      FakeRead(ForGuardBinding, _7);
-//      switchInt(move _8) -> [false: bb10, otherwise: bb9];
+//      switchInt(move _8) -> [false: bb8, otherwise: bb7];
 //  }
-//  bb9: {
+//  bb7: {
 //      StorageDead(_8);
 //      StorageLive(_6);
 //      _6 = ((_2 as Some).0: i32);
 //      _1 = const 1i32;
 //      StorageDead(_6);
 //      StorageDead(_7);
-//      goto -> bb17;
+//      goto -> bb15;
 //  }
-//  bb10: {
+//  bb8: {
 //      StorageDead(_8);
 //      StorageDead(_7);
 //      falseEdges -> [real: bb3, imaginary: bb3];
 //  }
-//  bb11: { // binding2 & arm2
+//  bb9: { // binding2 & arm2
 //      StorageLive(_9);
 //      _9 = _2;
 //      _1 = const 2i32;
 //      StorageDead(_9);
-//      goto -> bb17;
+//      goto -> bb15;
 //  }
-//  bb12: { // binding3: Some(y) if guard2(y)
+//  bb10: { // binding3: Some(y) if guard2(y)
 //      StorageLive(_11);
 //      _11 = &((_2 as Some).0: i32);
 //      _5 = &shallow _2;
 //      StorageLive(_12);
 //      StorageLive(_13);
 //      _13 = (*_11);
-//      _12 = const guard2(move _13) -> [return: bb13, unwind: bb1];
+//      _12 = const guard2(move _13) -> [return: bb11, unwind: bb1];
 //  }
-//  bb13: { // end of guard2
+//  bb11: { // end of guard2
 //      StorageDead(_13);
 //      FakeRead(ForMatchGuard, _5);
 //      FakeRead(ForGuardBinding, _11);
-//      switchInt(move _12) -> [false: bb15, otherwise: bb14];
+//      switchInt(move _12) -> [false: bb13, otherwise: bb12];
 //  }
-//  bb14: { // binding4 & arm4
+//  bb12: { // binding4 & arm4
 //      StorageDead(_12);
 //      StorageLive(_10);
 //      _10 = ((_2 as Some).0: i32);
 //      _1 = const 3i32;
 //      StorageDead(_10);
 //      StorageDead(_11);
-//      goto -> bb17;
+//      goto -> bb15;
 //  }
-//  bb15: {
+//  bb13: {
 //      StorageDead(_12);
 //      StorageDead(_11);
-//      falseEdges -> [real: bb5, imaginary: bb5];
+//      falseEdges -> [real: bb14, imaginary: bb14];
 //  }
-//  bb16: {
+//  bb14: {
 //      StorageLive(_14);
 //      _14 = _2;
 //      _1 = const 4i32;
 //      StorageDead(_14);
-//      goto -> bb17;
+//      goto -> bb15;
 //  }
-//  bb17: {
+//  bb15: {
 //      StorageDead(_2);
 //      StorageDead(_1);
 //      _0 = ();
diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs
index 2ef9520c12c..ef60a04d1bd 100644
--- a/src/test/mir-opt/match_test.rs
+++ b/src/test/mir-opt/match_test.rs
@@ -20,67 +20,61 @@ fn main() {
 // START rustc.main.SimplifyCfg-initial.after.mir
 //    bb0: {
 //        ...
-//        switchInt(move _4) -> [false: bb6, otherwise: bb7];
+//        switchInt(move _6) -> [false: bb6, otherwise: bb5];
 //    }
 //    bb1: {
-//        falseEdges -> [real: bb10, imaginary: bb2];
+//        falseEdges -> [real: bb9, imaginary: bb2];
 //    }
 //    bb2: {
-//        falseEdges -> [real: bb13, imaginary: bb3];
+//        falseEdges -> [real: bb12, imaginary: bb3];
 //    }
 //    bb3: {
-//        falseEdges -> [real: bb14, imaginary: bb4];
+//        falseEdges -> [real: bb13, imaginary: bb4];
 //    }
 //    bb4: {
-//        falseEdges -> [real: bb15, imaginary: bb5];
+//        _3 = const 3i32;
+//        goto -> bb14;
 //    }
 //    bb5: {
-//        unreachable;
+//        _7 = Lt(_1, const 10i32);
+//        switchInt(move _7) -> [false: bb6, otherwise: bb1];
 //    }
 //    bb6: {
-//        _6 = Le(const 10i32, _1);
-//        switchInt(move _6) -> [false: bb8, otherwise: bb9];
+//        _4 = Le(const 10i32, _1);
+//        switchInt(move _4) -> [false: bb8, otherwise: bb7];
 //    }
 //    bb7: {
-//        _5 = Lt(_1, const 10i32);
-//        switchInt(move _5) -> [false: bb6, otherwise: bb1];
+//        _5 = Le(_1, const 20i32);
+//        switchInt(move _5) -> [false: bb8, otherwise: bb2];
 //    }
 //    bb8: {
 //        switchInt(_1) -> [-1i32: bb3, otherwise: bb4];
 //    }
 //    bb9: {
-//        _7 = Le(_1, const 20i32);
-//        switchInt(move _7) -> [false: bb8, otherwise: bb2];
-//    }
-//    bb10: {
 //        _8 = &shallow _1;
 //        StorageLive(_9);
 //        _9 = _2;
 //        FakeRead(ForMatchGuard, _8);
-//        switchInt(move _9) -> [false: bb12, otherwise: bb11];
+//        switchInt(move _9) -> [false: bb11, otherwise: bb10];
 //    }
-//    bb11: {
+//    bb10: {
 //        StorageDead(_9);
 //        _3 = const 0i32;
-//        goto -> bb16;
+//        goto -> bb14;
 //    }
-//    bb12: {
+//    bb11: {
 //        StorageDead(_9);
 //        falseEdges -> [real: bb4, imaginary: bb2];
 //    }
-//    bb13: {
+//    bb12: {
 //        _3 = const 1i32;
-//        goto -> bb16;
+//        goto -> bb14;
 //    }
-//    bb14: {
+//    bb13: {
 //        _3 = const 2i32;
-//        goto -> bb16;
+//        goto -> bb14;
 //    }
-//    bb15: {
-//        _3 = const 3i32;
-//        goto -> bb16;
-//    }
-//    bb16: {
+//    bb14: {
 //        _0 = ();
 //        StorageDead(_2);
 //        StorageDead(_1);
diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs
index 622cc999830..fa0dbe51c5d 100644
--- a/src/test/mir-opt/nll/region-subtyping-basic.rs
+++ b/src/test/mir-opt/nll/region-subtyping-basic.rs
@@ -22,9 +22,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#2r | U0 | {bb2[0..=8], bb3[0], bb6[0..=1]}
-// | '_#3r | U0 | {bb2[1..=8], bb3[0], bb6[0..=1]}
-// | '_#4r | U0 | {bb2[4..=8], bb3[0], bb6[0..=1]}
+// | '_#2r | U0 | {bb2[0..=8], bb3[0], bb5[0..=1]}
+// | '_#3r | U0 | {bb2[1..=8], bb3[0], bb5[0..=1]}
+// | '_#4r | U0 | {bb2[4..=8], bb3[0], bb5[0..=1]}
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
 // let _2: &'_#3r usize;
diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs
index 6ac9cee79f5..0f9c6f62c2b 100644
--- a/src/test/mir-opt/remove_fake_borrows.rs
+++ b/src/test/mir-opt/remove_fake_borrows.rs
@@ -19,21 +19,19 @@ fn main() {
 // bb0: {
 //     FakeRead(ForMatchedPlace, _1);
 //     _3 = discriminant(_1);
-//     switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
+//     switchInt(move _3) -> [1isize: bb3, otherwise: bb2];
 // }
 // bb1: {
-//     goto -> bb5;
+//     goto -> bb4;
 // }
 // bb2: {
-//     goto -> bb8;
+//     _0 = const 1i32;
+//     goto -> bb7;
 // }
 // bb3: {
-//     unreachable;
-// }
-// bb4: {
 //     switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
 // }
-// bb5: {
+// bb4: {
 //     _4 = &shallow _1;
 //     _5 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
 //     _6 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
@@ -44,25 +42,21 @@ fn main() {
 //     FakeRead(ForMatchGuard, _5);
 //     FakeRead(ForMatchGuard, _6);
 //     FakeRead(ForMatchGuard, _7);
-//     switchInt(move _8) -> [false: bb7, otherwise: bb6];
+//     switchInt(move _8) -> [false: bb6, otherwise: bb5];
 // }
-// bb6: {
+// bb5: {
 //     StorageDead(_8);
 //     _0 = const 0i32;
-//     goto -> bb9;
+//     goto -> bb7;
 // }
-// bb7: {
+// bb6: {
 //     StorageDead(_8);
 //     goto -> bb2;
 // }
-// bb8: {
-//     _0 = const 1i32;
-//     goto -> bb9;
-// }
-// bb9: {
+// bb7: {
 //     return;
 // }
-// bb10 (cleanup): {
+// bb8 (cleanup): {
 //     resume;
 // }
 // END rustc.match_guard.CleanupNonCodegenStatements.before.mir
@@ -71,21 +65,19 @@ fn main() {
 // bb0: {
 //     nop;
 //     _3 = discriminant(_1);
-//     switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
+//     switchInt(move _3) -> [1isize: bb3, otherwise: bb2];
 // }
 // bb1: {
-//     goto -> bb5;
+//     goto -> bb4;
 // }
 // bb2: {
-//     goto -> bb8;
+//     _0 = const 1i32;
+//     goto -> bb7;
 // }
 // bb3: {
-//     unreachable;
-// }
-// bb4: {
 //     switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
 // }
-// bb5: {
+// bb4: {
 //     nop;
 //     nop;
 //     nop;
@@ -96,25 +88,21 @@ fn main() {
 //     nop;
 //     nop;
 //     nop;
-//     switchInt(move _8) -> [false: bb7, otherwise: bb6];
+//     switchInt(move _8) -> [false: bb6, otherwise: bb5];
 // }
-// bb6: {
+// bb5: {
 //     StorageDead(_8);
 //     _0 = const 0i32;
-//     goto -> bb9;
+//     goto -> bb7;
 // }
-// bb7: {
+// bb6: {
 //     StorageDead(_8);
 //     goto -> bb2;
 // }
-// bb8: {
-//     _0 = const 1i32;
-//     goto -> bb9;
-// }
-// bb9: {
+// bb7: {
 //     return;
 // }
-// bb10 (cleanup): {
+// bb8 (cleanup): {
 //     resume;
 // }
 // END rustc.match_guard.CleanupNonCodegenStatements.after.mir
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 35512b94c0c..471c1df3300 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -8,12 +8,12 @@ fn main() {
 // START rustc.main.SimplifyBranches-after-const-prop.before.mir
 // bb0: {
 //     ...
-//     switchInt(const false) -> [false: bb3, otherwise: bb1];
+//     switchInt(const false) -> [false: bb1, otherwise: bb2];
 // }
 // END rustc.main.SimplifyBranches-after-const-prop.before.mir
 // START rustc.main.SimplifyBranches-after-const-prop.after.mir
 // bb0: {
 //     ...
-//     goto -> bb3;
+//     goto -> bb1;
 // }
 // END rustc.main.SimplifyBranches-after-const-prop.after.mir
diff --git a/src/test/mir-opt/simplify_match.rs b/src/test/mir-opt/simplify_match.rs
index 0192aa01d01..8624899a0ab 100644
--- a/src/test/mir-opt/simplify_match.rs
+++ b/src/test/mir-opt/simplify_match.rs
@@ -9,14 +9,14 @@ fn main() {
 // START rustc.main.SimplifyBranches-after-copy-prop.before.mir
 // bb0: {
 //     ...
-//     switchInt(const false) -> [false: bb3, otherwise: bb1];
+//     switchInt(const false) -> [false: bb1, otherwise: bb2];
 // }
 // bb1: {
 // END rustc.main.SimplifyBranches-after-copy-prop.before.mir
 // START rustc.main.SimplifyBranches-after-copy-prop.after.mir
 // bb0: {
 //     ...
-//     goto -> bb3;
+//     goto -> bb1;
 // }
 // bb1: {
 // END rustc.main.SimplifyBranches-after-copy-prop.after.mir
diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
index a8d00d15234..ca1496a6c8d 100644
--- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
+++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
@@ -2,22 +2,22 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-mut-borrow-linear-errors.rs:10:30
    |
 LL |             1 => { addr.push(&mut x); }
-   |                    ----      ^^^^^^ second mutable borrow occurs here
-   |                    |
-   |                    first borrow later used here
+   |                              ^^^^^^ second mutable borrow occurs here
 LL |             2 => { addr.push(&mut x); }
 LL |             _ => { addr.push(&mut x); }
-   |                              ------ first mutable borrow occurs here
+   |                    ----      ------ first mutable borrow occurs here
+   |                    |
+   |                    first borrow later used here
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-mut-borrow-linear-errors.rs:11:30
    |
-LL |             1 => { addr.push(&mut x); }
-   |                    ---- first borrow later used here
 LL |             2 => { addr.push(&mut x); }
    |                              ^^^^^^ second mutable borrow occurs here
 LL |             _ => { addr.push(&mut x); }
-   |                              ------ first mutable borrow occurs here
+   |                    ----      ------ first mutable borrow occurs here
+   |                    |
+   |                    first borrow later used here
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
index e0af01aeef4..50757afaf56 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
@@ -6,6 +6,7 @@ fn main() {
         match &1 as *const i32 as usize {
             //~^ ERROR casting pointers to integers in constants
             //~| NOTE for more information, see
+            //~| ERROR constant contains unimplemented expression type
             0 => 42, //~ ERROR constant contains unimplemented expression type
             //~^ NOTE "pointer arithmetic or comparison" needs an rfc before being allowed
             //~| ERROR evaluation of constant value failed
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
index d005e09b28a..167d5ad8d61 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
@@ -8,18 +8,24 @@ LL |         match &1 as *const i32 as usize {
    = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/match-test-ptr-null.rs:9:13
+  --> $DIR/match-test-ptr-null.rs:6:15
+   |
+LL |         match &1 as *const i32 as usize {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/match-test-ptr-null.rs:10:13
    |
 LL |             0 => 42,
    |             ^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/match-test-ptr-null.rs:9:13
+  --> $DIR/match-test-ptr-null.rs:10:13
    |
 LL |             0 => 42,
    |             ^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0019, E0080, E0658.
 For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/const-match-pattern-arm.rs b/src/test/ui/consts/const-match-pattern-arm.rs
index 3b985269a56..6ed3ac23562 100644
--- a/src/test/ui/consts/const-match-pattern-arm.rs
+++ b/src/test/ui/consts/const-match-pattern-arm.rs
@@ -1,6 +1,7 @@
 #![allow(warnings)]
 
 const x: bool = match Some(true) {
+    //~^ ERROR: constant contains unimplemented expression type [E0019]
     Some(value) => true,
     //~^ ERROR: constant contains unimplemented expression type [E0019]
     _ => false
@@ -8,6 +9,7 @@ const x: bool = match Some(true) {
 
 const y: bool = {
     match Some(true) {
+    //~^ ERROR: constant contains unimplemented expression type [E0019]
         Some(value) => true,
         //~^ ERROR: constant contains unimplemented expression type [E0019]
         _ => false
diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr
index c793cc0cd78..709b66b7bf0 100644
--- a/src/test/ui/consts/const-match-pattern-arm.stderr
+++ b/src/test/ui/consts/const-match-pattern-arm.stderr
@@ -1,15 +1,27 @@
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:4:5
+  --> $DIR/const-match-pattern-arm.rs:3:23
+   |
+LL | const x: bool = match Some(true) {
+   |                       ^^^^^^^^^^
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/const-match-pattern-arm.rs:5:5
    |
 LL |     Some(value) => true,
    |     ^^^^^^^^^^^
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:11:9
+  --> $DIR/const-match-pattern-arm.rs:11:11
+   |
+LL |     match Some(true) {
+   |           ^^^^^^^^^^
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/const-match-pattern-arm.rs:13:9
    |
 LL |         Some(value) => true,
    |         ^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs
index 6002506689e..75793c90483 100644
--- a/src/test/ui/consts/single_variant_match_ice.rs
+++ b/src/test/ui/consts/single_variant_match_ice.rs
@@ -2,12 +2,12 @@ enum Foo {
     Prob,
 }
 
-const FOO: u32 = match Foo::Prob {
-    Foo::Prob => 42, //~ ERROR unimplemented expression type
+const FOO: u32 = match Foo::Prob { //~ ERROR unimplemented expression type
+    Foo::Prob => 42,
 };
 
-const BAR: u32 = match Foo::Prob {
-    x => 42, //~ ERROR unimplemented expression type
+const BAR: u32 = match Foo::Prob { //~ ERROR unimplemented expression type
+    x => 42,
 };
 
 impl Foo {
@@ -15,7 +15,8 @@ impl Foo {
         use self::Foo::*;
 
         match *self {
-            Prob => 0x1, //~ ERROR loops and conditional expressions are not stable in const fn
+            //~^ ERROR loops and conditional expressions are not stable in const fn
+            Prob => 0x1,
         }
     }
 }
diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr
index 1e092c8af99..851733726ac 100644
--- a/src/test/ui/consts/single_variant_match_ice.stderr
+++ b/src/test/ui/consts/single_variant_match_ice.stderr
@@ -1,20 +1,20 @@
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/single_variant_match_ice.rs:6:5
+  --> $DIR/single_variant_match_ice.rs:5:24
    |
-LL |     Foo::Prob => 42,
-   |     ^^^^^^^^^
+LL | const FOO: u32 = match Foo::Prob {
+   |                        ^^^^^^^^^
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/single_variant_match_ice.rs:10:5
+  --> $DIR/single_variant_match_ice.rs:9:24
    |
-LL |     x => 42,
-   |     ^
+LL | const BAR: u32 = match Foo::Prob {
+   |                        ^^^^^^^^^
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/single_variant_match_ice.rs:18:13
+  --> $DIR/single_variant_match_ice.rs:17:15
    |
-LL |             Prob => 0x1,
-   |             ^^^^
+LL |         match *self {
+   |               ^^^^^
    |
    = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
    = help: add #![feature(const_fn)] to the crate attributes to enable
diff --git a/src/test/ui/issues/issue-46843.rs b/src/test/ui/issues/issue-46843.rs
index a310de624d2..aa252efea46 100644
--- a/src/test/ui/issues/issue-46843.rs
+++ b/src/test/ui/issues/issue-46843.rs
@@ -4,7 +4,9 @@ fn non_const() -> Thing {
     Thing::This
 }
 
-pub const Q: i32 = match non_const() { //~ ERROR E0015
+pub const Q: i32 = match non_const() {
+    //~^ ERROR E0015
+    //~^^ ERROR unimplemented expression type
     Thing::This => 1, //~ ERROR unimplemented expression type
     Thing::That => 0
 };
diff --git a/src/test/ui/issues/issue-46843.stderr b/src/test/ui/issues/issue-46843.stderr
index b7abf0213b0..92ee154552c 100644
--- a/src/test/ui/issues/issue-46843.stderr
+++ b/src/test/ui/issues/issue-46843.stderr
@@ -5,12 +5,18 @@ LL | pub const Q: i32 = match non_const() {
    |                          ^^^^^^^^^^^
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/issue-46843.rs:8:5
+  --> $DIR/issue-46843.rs:7:26
+   |
+LL | pub const Q: i32 = match non_const() {
+   |                          ^^^^^^^^^^^
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/issue-46843.rs:10:5
    |
 LL |     Thing::This => 1,
    |     ^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0015, E0019.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
index c646912d3b6..13b6a7bbef3 100644
--- a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
@@ -28,6 +28,9 @@ LL |     let x;
 ...
 LL |             x = 1;
    |             ^^^^^ cannot assign twice to immutable variable
+LL |         } else {
+LL |             x = 2;
+   |             ----- first assignment to `x`
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/liveness-assign-imm-local-notes.rs:32:13
@@ -35,9 +38,6 @@ error[E0384]: cannot assign twice to immutable variable `x`
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
 ...
-LL |             x = 1;
-   |             ----- first assignment to `x`
-LL |         } else {
 LL |             x = 2;
    |             ^^^^^ cannot assign twice to immutable variable