MIR-borrowck: add false edges to match arms

This commit is contained in:
Your Name 2017-10-11 17:39:45 +03:00
parent 264aafe056
commit 8a28c676c8
2 changed files with 49 additions and 5 deletions

View file

@ -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
}
}

View file

@ -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]
};
}