about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-10-15 02:20:13 +0000
committerbors <bors@rust-lang.org>2017-10-15 02:20:13 +0000
commitf5eb33f4e5ea2b78cfcc34cc42dda8701b2a0f85 (patch)
treeeb19a929d88e0a63be9c1a4057c0329faacbfbcc /src
parenta457e298115fd1811f3b5c4ec889067279b218f7 (diff)
parent8a28c676c89173a88c2568deb8964e0960f2afb6 (diff)
downloadrust-f5eb33f4e5ea2b78cfcc34cc42dda8701b2a0f85.tar.gz
rust-f5eb33f4e5ea2b78cfcc34cc42dda8701b2a0f85.zip
Auto merge of #45200 - mikhail-m1:match-with-false-edges, r=nikomatsakis
MIR-borrowck: add false edges to match arms

basic fix for https://github.com/rust-lang/rust/issues/45043, should be modified with #45184
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/build/matches/mod.rs29
-rw-r--r--src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs25
2 files changed, 49 insertions, 5 deletions
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index f04dede6e40..56c926eaa61 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<BasicBlock> {
         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 00000000000..1d21f40fcca
--- /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 <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.
+
+// 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]
+    };
+}