diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 4bda89690b7a9..05436201e7a6e 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -62,7 +62,8 @@ for mir::Terminator<'gcx> {
             mir::TerminatorKind::Drop { .. } |
             mir::TerminatorKind::DropAndReplace { .. } |
             mir::TerminatorKind::Yield { .. } |
-            mir::TerminatorKind::Call { .. } => false,
+            mir::TerminatorKind::Call { .. } |
+            mir::TerminatorKind::FalseEdges { .. } => false,
         };
 
         if hash_spans_unconditionally {
@@ -210,6 +211,12 @@ for mir::TerminatorKind<'gcx> {
                 target.hash_stable(hcx, hasher);
                 cleanup.hash_stable(hcx, hasher);
             }
+            mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => {
+                real_target.hash_stable(hcx, hasher);
+                for target in imaginary_targets {
+                    target.hash_stable(hcx, hasher);
+                }
+            }
         }
     }
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index c4a33bb07cdf2..8f86d1b9d78ee 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -682,6 +682,11 @@ pub enum TerminatorKind<'tcx> {
 
     /// Indicates the end of the dropping of a generator
     GeneratorDrop,
+
+    FalseEdges {
+        real_target: BasicBlock,
+        imaginary_targets: Vec<BasicBlock>
+    },
 }
 
 impl<'tcx> Terminator<'tcx> {
@@ -731,6 +736,11 @@ impl<'tcx> TerminatorKind<'tcx> {
             }
             Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
             Assert { ref target, .. } => slice::ref_slice(target).into_cow(),
+            FalseEdges { ref real_target, ref imaginary_targets } => {
+                let mut s = vec![*real_target];
+                s.extend_from_slice(imaginary_targets);
+                s.into_cow()
+            }
         }
     }
 
@@ -757,7 +767,12 @@ impl<'tcx> TerminatorKind<'tcx> {
                 vec![target]
             }
             Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind],
-            Assert { ref mut target, .. } => vec![target]
+            Assert { ref mut target, .. } => vec![target],
+            FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
+                let mut s = vec![real_target];
+                s.extend(imaginary_targets.iter_mut());
+                s
+            }
         }
     }
 }
@@ -874,7 +889,8 @@ impl<'tcx> TerminatorKind<'tcx> {
                 }
 
                 write!(fmt, ")")
-            }
+            },
+            FalseEdges { .. } => write!(fmt, "falseEdges")
         }
     }
 
@@ -910,7 +926,12 @@ impl<'tcx> TerminatorKind<'tcx> {
             }
             Assert { cleanup: None, .. } => vec!["".into()],
             Assert { .. } =>
-                vec!["success".into_cow(), "unwind".into_cow()]
+                vec!["success".into_cow(), "unwind".into_cow()],
+            FalseEdges { ref imaginary_targets, .. } => {
+                let mut l = vec!["real".into()];
+                l.resize(imaginary_targets.len() + 1, "imaginary".into());
+                l
+            }
         }
     }
 }
@@ -1878,6 +1899,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
             Resume => Resume,
             Return => Return,
             Unreachable => Unreachable,
+            FalseEdges { real_target, ref imaginary_targets } =>
+                FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
         };
         Terminator {
             source_info: self.source_info,
@@ -1917,7 +1940,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
             Resume |
             Return |
             GeneratorDrop |
-            Unreachable => false
+            Unreachable |
+            FalseEdges { .. } => false
         }
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 63652980f9b4b..47dbcee639425 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -486,8 +486,15 @@ macro_rules! make_mir_visitor {
                         self.visit_operand(value, source_location);
                         self.visit_branch(block, resume);
                         drop.map(|t| self.visit_branch(block, t));
+
                     }
 
+                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
+                        self.visit_branch(block, real_target);
+                        for target in imaginary_targets {
+                            self.visit_branch(block, *target);
+                        }
+                    }
                 }
             }
 
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 819f67a39e931..2cb1a23ef5a15 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -364,7 +364,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'tcx>
             TerminatorKind::Resume |
             TerminatorKind::Return |
             TerminatorKind::GeneratorDrop |
-            TerminatorKind::Unreachable => {
+            TerminatorKind::Unreachable |
+            TerminatorKind::FalseEdges { .. } => {
                 // no data used, thus irrelevant to borrowck
             }
         }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 56c926eaa6153..b65d859e7d756 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -21,7 +21,7 @@ use rustc::mir::*;
 use rustc::hir;
 use hair::*;
 use syntax::ast::{Name, NodeId};
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::Span;
 
 // helper functions, broken out by category:
 mod simplify;
@@ -54,11 +54,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             (body, scope.unwrap_or(self.visibility_scope))
         }).collect();
 
+        // create binding start block for link them by false edges
+        let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len());
+        let pre_binding_blocks: Vec<_> = (0..candidate_count + 1)
+            .map(|_| self.cfg.start_new_block()).collect();
+
         // 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()
@@ -66,17 +72,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     arm.patterns.iter()
                                 .map(move |pat| (arm_index, pat, arm.guard.clone()))
                 })
-                .map(|(arm_index, pattern, guard)| {
+                .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1)))
+                .map(|((arm_index, pattern, guard),
+                       (pre_binding_block, next_candidate_pre_binding_block))| {
                     Candidate {
                         span: pattern.span,
                         match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
                         bindings: vec![],
                         guard,
                         arm_index,
+                        pre_binding_block: *pre_binding_block,
+                        next_candidate_pre_binding_block: *next_candidate_pre_binding_block,
                     }
                 })
                 .collect();
 
+        let outer_source_info = self.source_info(span);
+        self.cfg.terminate(*pre_binding_blocks.last().unwrap(),
+                           outer_source_info, TerminatorKind::Unreachable);
+
         // this will generate code to test discriminant_lvalue and
         // branch to the appropriate arm block
         let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block);
@@ -148,7 +162,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
             bindings: vec![],
             guard: None,
-            arm_index: 0, // since we don't call `match_candidates`, this field is unused
+
+            // since we don't call `match_candidates`, next fields is unused
+            arm_index: 0,
+            pre_binding_block: block,
+            next_candidate_pre_binding_block: block
         };
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
@@ -278,6 +296,10 @@ pub struct Candidate<'pat, 'tcx:'pat> {
 
     // ...and then we branch to arm with this index.
     arm_index: usize,
+
+    // ...and the blocks for add false edges between candidates
+    pre_binding_block: BasicBlock,
+    next_candidate_pre_binding_block: BasicBlock,
 }
 
 #[derive(Clone, Debug)]
@@ -398,17 +420,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
         debug!("match_candidates: {:?} candidates fully matched", fully_matched);
         let mut unmatched_candidates = candidates.split_off(fully_matched);
-        for (index, candidate) in candidates.into_iter().enumerate() {
+
+        let fully_matched_with_guard =
+            candidates.iter().take_while(|c| c.guard.is_some()).count();
+
+        let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() {
+            candidates.split_off(fully_matched_with_guard + 1)
+        } else {
+            vec![]
+        };
+
+        for candidate in candidates {
             // If so, apply any bindings, test the guard (if any), and
             // branch to the arm.
-            let is_last = index == fully_matched - 1;
-            if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks,
-                                                                   candidate, is_last) {
+            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).
-                return vec![];
+                // 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);
+                    }
+                }
+
+                if unmatched_candidates.is_empty() {
+                    return vec![]
+                } else {
+                    let target = self.cfg.start_new_block();
+                    return self.match_candidates(span, arm_blocks, unmatched_candidates, target);
+                }
             }
         }
 
@@ -423,9 +471,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.test_candidates(span, arm_blocks, &unmatched_candidates, block);
 
         // If the target candidates were exhaustive, then we are done.
-        if otherwise.is_empty() {
-            return vec![];
-        }
+        // But for borrowck continue build decision tree.
 
         // If all candidates were sorted into `target_candidates` somewhere, then
         // the initial set was inexhaustive.
@@ -666,17 +712,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn bind_and_guard_matched_candidate<'pat>(&mut self,
                                               mut block: BasicBlock,
                                               arm_blocks: &mut ArmBlocks,
-                                              candidate: Candidate<'pat, 'tcx>,
-                                              is_last_arm: bool)
+                                              candidate: Candidate<'pat, 'tcx>)
                                               -> Option<BasicBlock> {
         debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
                block, candidate);
 
         debug_assert!(candidate.match_pairs.is_empty());
 
-        self.bind_matched_candidate(block, candidate.bindings);
-
         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();
+        self.cfg.terminate(candidate.pre_binding_block, candidate_source_info,
+                               TerminatorKind::FalseEdges {
+                                   real_target: block,
+                                   imaginary_targets:
+                                       vec![candidate.next_candidate_pre_binding_block]});
+
+        self.bind_matched_candidate(block, candidate.bindings);
 
         if let Some(guard) = candidate.guard {
             // the block to branch to if the guard fails; if there is no
@@ -684,30 +740,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let guard = self.hir.mirror(guard);
             let source_info = self.source_info(guard.span);
             let cond = unpack!(block = self.as_local_operand(block, guard));
-            let otherwise = self.cfg.start_new_block();
+
+            let false_edge_block = self.cfg.start_new_block();
             self.cfg.terminate(block, source_info,
-                               TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
-            Some(otherwise)
-        } else if !is_last_arm {
-            // Add always true guard in case of more than one arm
-            // it creates false edges and allow MIR borrowck detects errors
-            // FIXME(#45184) -- permit "false edges"
-            let source_info = self.source_info(candidate.span);
-            let true_expr = Expr {
-                temp_lifetime: None,
-                ty: self.hir.tcx().types.bool,
-                span: DUMMY_SP,
-                kind: ExprKind::Literal{literal: self.hir.true_literal()},
-            };
-            let cond = unpack!(block = self.as_local_operand(block, true_expr));
+                               TerminatorKind::if_(self.hir.tcx(), cond, arm_block,
+                                   false_edge_block));
+
             let otherwise = self.cfg.start_new_block();
-            self.cfg.terminate(block, source_info,
-                               TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
+            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 {
-            let source_info = self.source_info(candidate.span);
-            self.cfg.terminate(block, source_info,
-                               TerminatorKind::Goto { target: arm_block  });
+            self.cfg.terminate(block, candidate_source_info,
+                               TerminatorKind::Goto { target: arm_block });
             None
         }
     }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 7b91c43aa3722..4792bf2b213e6 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -598,6 +598,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             bindings: candidate.bindings.clone(),
             guard: candidate.guard.clone(),
             arm_index: candidate.arm_index,
+            pre_binding_block: candidate.pre_binding_block,
+            next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
         }
     }
 
@@ -659,6 +661,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             bindings: candidate.bindings.clone(),
             guard: candidate.guard.clone(),
             arm_index: candidate.arm_index,
+            pre_binding_block: candidate.pre_binding_block,
+            next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
         }
     }
 
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index d27a4e7e9d9c3..f5517096e3aba 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -721,6 +721,12 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
                     self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb);
                 }
             }
+            mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => {
+                self.propagate_bits_into_entry_set_for(in_out, changed, real_target);
+                for target in imaginary_targets {
+                    self.propagate_bits_into_entry_set_for(in_out, changed, target);
+                }
+            }
         }
     }
 
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 8f473d035ee1d..79ea745125c53 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -305,6 +305,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
             TerminatorKind::Goto { target: _ } |
             TerminatorKind::Resume |
             TerminatorKind::GeneratorDrop |
+            TerminatorKind::FalseEdges { .. } |
             TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 49ce36223994b..80c8f22c1029e 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -73,7 +73,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             TerminatorKind::GeneratorDrop |
             TerminatorKind::Resume |
             TerminatorKind::Return |
-            TerminatorKind::Unreachable => {
+            TerminatorKind::Unreachable |
+            TerminatorKind::FalseEdges { .. } => {
                                 // safe (at least as emitted during MIR construction)
             }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 9d32861aedade..f2453d3946172 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -720,6 +720,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 }
             }
             TerminatorKind::Unreachable => { }
+            TerminatorKind::FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
+                *real_target = self.update_target(*real_target);
+                for target in imaginary_targets {
+                    *target = self.update_target(*target);
+                }
+            }
         }
     }
 
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index fa6bb644871dc..7de8de3c96bd7 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -45,7 +45,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
             TerminatorKind::Unreachable |
             TerminatorKind::GeneratorDrop |
             TerminatorKind::Yield { .. } |
-            TerminatorKind::SwitchInt { .. } => {
+            TerminatorKind::SwitchInt { .. } |
+            TerminatorKind::FalseEdges { .. } => {
                 /* nothing to do */
             },
             TerminatorKind::Call { cleanup: ref mut unwind, .. } |
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 3f3b9d177d70c..583dfd9b616f1 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -317,7 +317,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 TerminatorKind::Resume |
                 TerminatorKind::GeneratorDrop |
                 TerminatorKind::Yield { .. } |
-                TerminatorKind::Unreachable => None,
+                TerminatorKind::Unreachable |
+                TerminatorKind::FalseEdges { .. } => None,
 
                 TerminatorKind::Return => {
                     // Check for unused values. This usually means
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 0dff145ecbce9..edbbe5305e959 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -61,6 +61,9 @@ impl MirPass for SimplifyBranches {
                 }), expected, .. } if cond == expected => {
                     TerminatorKind::Goto { target: target }
                 },
+                TerminatorKind::FalseEdges { real_target, .. } => {
+                    TerminatorKind::Goto { target: real_target }
+                },
                 _ => continue
             };
         }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index ab5998a34805b..d8dc7a8d5cc7d 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -441,7 +441,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             TerminatorKind::Return |
             TerminatorKind::GeneratorDrop |
             TerminatorKind::Unreachable |
-            TerminatorKind::Drop { .. } => {
+            TerminatorKind::Drop { .. } |
+            TerminatorKind::FalseEdges { .. } => {
                 // no checks needed for these
             }
 
@@ -685,6 +686,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     self.assert_iscleanup(mir, block, cleanup, true);
                 }
             }
+            TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
+                self.assert_iscleanup(mir, block, real_target, is_cleanup);
+                for target in imaginary_targets {
+                    self.assert_iscleanup(mir, block, *target, is_cleanup);
+                }
+            }
         }
     }
 
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 1fa49614580a3..30e2ba61dbda7 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -121,6 +121,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
             TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
             TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
             TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
+            TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
         }, kind);
         self.super_terminator_kind(block, kind, location);
     }
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index 00815be278ee0..73f60ff29a851 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -228,7 +228,8 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
                 TerminatorKind::GeneratorDrop |
                 TerminatorKind::Unreachable |
                 TerminatorKind::SwitchInt { .. } |
-                TerminatorKind::Yield { .. }  => {
+                TerminatorKind::Yield { .. } |
+                TerminatorKind::FalseEdges { .. } => {
                     /* nothing to do */
                 }
                 TerminatorKind::Call { cleanup: unwind, .. } |
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 591aa974666cc..11d992bd4cf0e 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -583,7 +583,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         cleanup);
             }
             mir::TerminatorKind::GeneratorDrop |
-            mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"),
+            mir::TerminatorKind::Yield { .. } |
+            mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"),
         }
     }
 
diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs
index cf9b80e5ed404..81c38dd3fe11d 100644
--- a/src/librustc_trans_utils/collector.rs
+++ b/src/librustc_trans_utils/collector.rs
@@ -623,7 +623,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             mir::TerminatorKind::Unreachable |
             mir::TerminatorKind::Assert { .. } => {}
             mir::TerminatorKind::GeneratorDrop |
-            mir::TerminatorKind::Yield { .. } => bug!(),
+            mir::TerminatorKind::Yield { .. } |
+            mir::TerminatorKind::FalseEdges { .. } => bug!(),
         }
 
         self.super_terminator_kind(block, kind, location);
diff --git a/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs b/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs
new file mode 100644
index 0000000000000..8bab6e8dfceac
--- /dev/null
+++ b/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs
@@ -0,0 +1,24 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+//compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn foo(_:String) {}
+
+fn main()
+{
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if { drop(my_str); false } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR (Mir) [E0381]
+    }
+}
diff --git a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs
index 1d21f40fccaef..5f236014457a7 100644
--- a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs
+++ b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs
@@ -11,6 +11,24 @@
 // revisions: ast mir
 //[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
 
+enum Foo {
+    A(i32),
+    B
+}
+
+fn match_enum() {
+    let mut foo = Foo::B;
+    let p = &mut foo;
+    let _ = match foo {
+        Foo::B => 1, //[mir]~ ERROR (Mir) [E0503]
+        _ => 2,
+        Foo::A(x) => x //[ast]~ ERROR [E0503]
+                       //[mir]~^ ERROR (Ast) [E0503]
+                       //[mir]~| ERROR (Mir) [E0503]
+    };
+}
+
+
 fn main() {
     let mut x = 1;
     let _x = &mut x;
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
new file mode 100644
index 0000000000000..78214dab53913
--- /dev/null
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -0,0 +1,236 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn guard() -> bool {
+    false
+}
+
+fn guard2(_:i32) -> bool {
+    true
+}
+
+fn full_tested_match() {
+    let _ = match Some(42) {
+        Some(x) if guard() => (1, x),
+        Some(y) => (2, y),
+        None => (3, 3),
+    };
+}
+
+fn full_tested_match2() {
+    let _ = match Some(42) {
+        Some(x) if guard() => (1, x),
+        None => (3, 3),
+        Some(y) => (2, y),
+    };
+}
+
+fn main() {
+    let _ = match Some(1) {
+        Some(_w) if guard() => 1,
+        _x => 2,
+        Some(y) if guard2(y) => 3,
+        _z => 4,
+    };
+}
+
+// END RUST SOURCE
+//
+// START rustc.node17.SimplifyBranches-initial.before.mir
+//  bb0: {
+//      ...
+//      _2 = std::option::Option<i32>::Some(const 42i32,);
+//      _5 = discriminant(_2);
+//      switchInt(_5) -> [0isize: bb5, otherwise: bb3];
+//  }
+//  bb1: { // arm1
+//      StorageLive(_7);
+//      _7 = _3;
+//      _1 = (const 1i32, _7);
+//      StorageDead(_7);
+//      goto -> bb11;
+//  }
+//  bb2: { // binding3(empty) and arm3
+//      _1 = (const 3i32, const 3i32);
+//      goto -> bb11;
+//  }
+//  bb3: {
+//      falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
+//  }
+//  bb4: {
+//      falseEdges -> [real: bb10, imaginary: bb5]; //pre_binding2
+//  }
+//  bb5: {
+//      falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
+//  }
+//  bb6: {
+//      unreachable;
+//  }
+//  bb7: { // binding1 and guard
+//      StorageLive(_3);
+//      _3 = ((_2 as Some).0: i32);
+//      StorageLive(_6);
+//      _6 = const guard() -> bb8;
+//  }
+//  bb8: { // end of guard
+//      switchInt(_6) -> [0u8: bb9, otherwise: bb1];
+//  }
+//  bb9: { // to pre_binding2
+//      falseEdges -> [real: bb4, imaginary: bb4];
+//  }
+//  bb10: { // bindingNoLandingPads.before.mir2 and arm2
+//      StorageLive(_4);
+//      _4 = ((_2 as Some).0: i32);
+//      StorageLive(_8);
+//      _8 = _4;
+//      _1 = (const 2i32, _8);
+//      StorageDead(_8);
+//      goto -> bb11;
+//  }
+//  bb11: {
+//      ...
+//      return;
+//  }
+// END rustc.node17.SimplifyBranches-initial.before.mir
+//
+// START rustc.node42.SimplifyBranches-initial.before.mir
+//  bb0: {
+//      ...
+//      _2 = std::option::Option<i32>::Some(const 42i32,);
+//      _5 = discriminant(_2);
+//      switchInt(_5) -> [0isize: bb4, otherwise: bb3];
+//  }
+//  bb1: { // arm1
+//      StorageLive(_7);
+//      _7 = _3;
+//      _1 = (const 1i32, _7);
+//      StorageDead(_7);
+//      goto -> bb11;
+//  }
+//  bb2: { // binding3(empty) and arm3
+//      _1 = (const 3i32, const 3i32);
+//      goto -> bb11;
+//  }
+//  bb3: {
+//      falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
+//  }
+//  bb4: {
+//      falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
+//  }
+//  bb5: {
+//      falseEdges -> [real: bb10, imaginary: bb6]; //pre_binding3
+//  }
+//  bb6: {
+//      unreachable;
+//  }
+//  bb7: { // binding1 and guard
+//      StorageLive(_3);
+//      _3 = ((_2 as Some).0: i32);
+//      StorageLive(_6);
+//      _6 = const guard() -> bb8;
+//  }
+//  bb8: { // end of guard
+//      switchInt(_6) -> [0u8: bb9, otherwise: bb1];
+//  }
+//  bb9: { // to pre_binding2
+//      falseEdges -> [real: bb5, imaginary: bb4];
+//  }
+//  bb10: { // binding2 and arm2
+//      StorageLive(_4);
+//      _4 = ((_2 as Some).0: i32);
+//      StorageLive(_8);
+//      _8 = _4;
+//      _1 = (const 2i32, _8);
+//      StorageDead(_8);
+//      goto -> bb11;
+//  }
+//  bb11: {
+//      ...
+//      return;
+//  }
+// END rustc.node42.SimplifyBranches-initial.before.mir
+//
+// START rustc.node67.SimplifyBranches-initial.before.mir
+// bb0: {
+//     ...
+//     _2 = std::option::Option<i32>::Some(const 1i32,);
+//     _7 = discriminant(_2);
+//     switchInt(_7) -> [1isize: bb3, otherwise: bb4];
+// }
+// bb1: { // arm1
+//      _1 = const 1i32;
+//      goto -> bb16;
+// }
+// bb2: { // arm3
+//     _1 = const 3i32;
+//      goto -> bb16;
+// }
+//
+//  bb3: {
+//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
+//  }
+//  bb4: {
+//      falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
+//  }
+//  bb5: {
+//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
+//  }
+//  bb6: {
+//      falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4
+//  }
+//  bb7: {
+//      unreachable;
+//  }
+//  bb8: { // binding1: Some(w) if guard()
+//      StorageLive(_3);
+//      _3 = ((_2 as Some).0: i32);
+//      StorageLive(_8);
+//      _8 = const guard() -> bb9;
+//  }
+//  bb9: { //end of guard
+//      switchInt(_8) -> [0u8: bb10, otherwise: bb1];
+//  }
+//  bb10: { // to pre_binding2
+//      falseEdges -> [real: bb4, imaginary: bb4];
+//  }
+//  bb11: { // binding2 & arm2
+//      StorageLive(_4);
+//      _4 = _2;
+//      _1 = const 2i32;
+//      goto -> bb16;
+//  }
+//  bb12: { // binding3: Some(y) if guard2(y)
+//      StorageLive(_5);
+//      _5 = ((_2 as Some).0: i32);
+//      StorageLive(_10);
+//      StorageLive(_11);
+//      _11 = _5;
+//      _10 = const guard2(_11) -> bb13;
+//  }
+//  bb13: { // end of guard2
+//      StorageDead(_11);
+//      switchInt(_10) -> [0u8: bb14, otherwise: bb2];
+//  }
+//  bb14: { // to pre_binding4
+//      falseEdges -> [real: bb6, imaginary: bb6];
+//  }
+//  bb15: { // binding4 & arm4
+//      StorageLive(_6);
+//      _6 = _2;
+//      _1 = const 4i32;
+//      goto -> bb16;
+//  }
+// bb16: {
+//     ...
+//     return;
+// }
+// END rustc.node67.SimplifyBranches-initial.before.mir