diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index f04dede6e4005..56c926eaa6153 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::Span; +use syntax_pos::{DUMMY_SP, Span}; // helper functions, broken out by category: mod simplify; @@ -398,10 +398,12 @@ 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 candidate in candidates { + for (index, candidate) in candidates.into_iter().enumerate() { // If so, apply any bindings, test the guard (if any), and // branch to the arm. - if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { + let is_last = index == fully_matched - 1; + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, + candidate, is_last) { block = b; } else { // if None is returned, then any remaining candidates @@ -664,7 +666,8 @@ 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>) + candidate: Candidate<'pat, 'tcx>, + is_last_arm: bool) -> Option { debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", block, candidate); @@ -685,10 +688,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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)); + let otherwise = self.cfg.start_new_block(); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); + Some(otherwise) } else { let source_info = self.source_info(candidate.span); self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: arm_block }); + TerminatorKind::Goto { target: arm_block }); None } } diff --git a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs new file mode 100644 index 0000000000000..1d21f40fccaef --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn main() { + let mut x = 1; + let _x = &mut x; + let _ = match x { + x => x + 1, //[ast]~ ERROR E0503 + //[mir]~^ ERROR (Mir) [E0503] + //[mir]~| ERROR (Ast) [E0503] + y => y + 2, //[ast]~ ERROR [E0503] + //[mir]~^ ERROR (Mir) [E0503] + //[mir]~| ERROR (Ast) [E0503] + }; +}