From 2d71c5f10c9c2ae02184e6d1fc2ec0c34dce00d6 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Fri, 13 Oct 2017 16:36:15 +0300 Subject: [PATCH] add TerminatorKind::FalseEdges and use it in matches --- src/librustc/ich/impls_mir.rs | 9 +- src/librustc/mir/mod.rs | 32 +++- src/librustc/mir/visit.rs | 7 + src/librustc_mir/borrow_check.rs | 3 +- src/librustc_mir/build/matches/mod.rs | 118 +++++++++---- src/librustc_mir/build/matches/test.rs | 4 + src/librustc_mir/dataflow/mod.rs | 6 + .../dataflow/move_paths/builder.rs | 1 + src/librustc_mir/transform/check_unsafety.rs | 3 +- src/librustc_mir/transform/inline.rs | 6 + src/librustc_mir/transform/no_landing_pads.rs | 3 +- src/librustc_mir/transform/qualify_consts.rs | 3 +- .../transform/simplify_branches.rs | 3 + src/librustc_mir/transform/type_check.rs | 9 +- src/librustc_passes/mir_stats.rs | 1 + src/librustc_trans/mir/analyze.rs | 3 +- src/librustc_trans/mir/block.rs | 3 +- src/librustc_trans_utils/collector.rs | 3 +- .../borrowck/borrowck-drop-from-guard.rs | 24 +++ .../borrowck-match-already-borrowed.rs | 18 ++ src/test/mir-opt/match_false_edges.rs | 166 ++++++++++++++++++ 21 files changed, 377 insertions(+), 48 deletions(-) create mode 100644 src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs create mode 100644 src/test/mir-opt/match_false_edges.rs diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 4bda89690b7..05436201e7a 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 c4a33bb07cd..8f86d1b9d78 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 + }, } 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 63652980f9b..47dbcee6394 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 819f67a39e9..2cb1a23ef5a 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 56c926eaa61..9d68fe5759c 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 binding_start_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(binding_start_blocks.iter().zip(binding_start_blocks.iter().skip(1))) + .map(|((arm_index, pattern, guard), + (binding_start_block, next_candidate_binding_start_block))| { Candidate { span: pattern.span, match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)], bindings: vec![], guard, arm_index, + binding_start_block: *binding_start_block, + next_candidate_binding_start_block: *next_candidate_binding_start_block, } }) .collect(); + let outer_source_info = self.source_info(span); + self.cfg.terminate(*binding_start_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, + binding_start_block: block, + next_candidate_binding_start_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 + binding_start_block: BasicBlock, + next_candidate_binding_start_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,24 @@ 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 { 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::FalseEdges { + real_target: candidate.binding_start_block, + imaginary_targets: + vec![candidate.next_candidate_binding_start_block]}); + + block = candidate.binding_start_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 +737,25 @@ 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_binding_start_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::FalseEdges { + real_target: arm_block, + imaginary_targets: + vec![candidate.next_candidate_binding_start_block]}); None } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 7b91c43aa37..cf3c9fefa47 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, + binding_start_block: candidate.binding_start_block, + next_candidate_binding_start_block: candidate.next_candidate_binding_start_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, + binding_start_block: candidate.binding_start_block, + next_candidate_binding_start_block: candidate.next_candidate_binding_start_block, } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index d27a4e7e9d9..f5517096e3a 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 8f473d035ee..79ea745125c 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 49ce3622399..80c8f22c102 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 9d32861aeda..f2453d39461 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 fa6bb644871..7de8de3c96b 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 3f3b9d177d7..583dfd9b616 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 0dff145ecbc..edbbe5305e9 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 ab5998a3480..d8dc7a8d5cc 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 1fa49614580..30e2ba61dbd 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 00815be278e..73f60ff29a8 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 { + 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 591aa974666..11d992bd4cf 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 cf9b80e5ed4..81c38dd3fe1 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 00000000000..8bab6e8dfce --- /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 or the MIT license +// , 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 1d21f40fcca..5f236014457 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 00000000000..81153c02244 --- /dev/null +++ b/src/test/mir-opt/match_false_edges.rs @@ -0,0 +1,166 @@ +// 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 or the MIT license +// , 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(_) if guard() => 1, + Some(_) => 2, + None => 3 + }; +} + +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.NLL.before.mir +// bb0: { +// ... +// _2 = std::option::Option::Some(const 42i32,); +// _3 = discriminant(_2); +// switchInt(_3) -> [0isize: bb8, otherwise: bb9]; +// } +// bb1: { // arm1 +// _1 = const 1i32; +// goto -> bb13; +// } +// bb2: { // arm2 +// _1 = const 2i32; +// goto -> bb13; +// } +// bb3: { // arm3 +// _1 = const 3i32; +// goto -> bb13; +// } +// bb4: { // binding1 +// ... +// _4 = const guard() -> bb10; +// } +// bb5: { // binding2 +// falseEdges -> [real: bb2, imaginary: bb6]; +// } +// bb6: { // binding3 +// falseEdges -> [real: bb3, imaginary: bb7]; +// } +// bb7: { +// unreachable; +// } +// bb8: { +// falseEdges -> [real: bb6, imaginary: bb7]; // from before_binding3 to unreachable +// } +// bb9: { +// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding1 to binding2 +// } +// bb10: { +// switchInt(_4) -> [0u8: bb11, otherwise: bb1]; // end of guard +// } +// bb11: { +// falseEdges -> [real: bb12, imaginary: bb5]; // after_guard to binding2 +// } +// bb12: { +// falseEdges -> [real: bb5, imaginary: bb6]; // from before_binding2 to binding3 +// } +// bb13: { +// ... +// return; +// } +// +// +// END rustc.node17.NLL.before.mir +// +// START rustc.node36.NLL.before.mir +// bb0: { +// ... +// _2 = std::option::Option::Some(const 1i32,); +// _7 = discriminant(_2); +// switchInt(_7) -> [1isize: bb10, otherwise: bb13]; +// } +// bb1: { // arm1 +// _1 = const 1i32; +// goto -> bb17; +// } +// bb2: { // arm2 +// _1 = const 2i32; +// goto -> bb17; +// } +// bb3: { // arm3 +// _1 = const 3i32; +// goto -> bb17; +// } +// bb4: { // arm4 +// _1 = const 4i32; +// goto -> bb17; +// } +// bb5: { // binding1: Some(w) if guard() => +// ... +// _8 = const guard() -> bb11; +// } +// bb6: { // binding2: x => +// ... +// _4 = _2; +// falseEdges -> [real: bb2, imaginary: bb7]; // after binding2 to binding3 +// } +// bb7: { // binding3: Some(y) if guard2(y) => +// ... +// _10 = const guard2(_11) -> bb14; +// } +// bb8: { // binding4: z_ => +// ... +// _6 = _2; +// falseEdges -> [real: bb4, imaginary: bb9]; // after binding3 to unreachable +// } +// bb9: { +// unreachable; +// } +// bb10: { +// falseEdges -> [real: bb5, imaginary: bb6]; // from before_binding1 to binding2 +// } +// bb11: { +// switchInt(_8) -> [0u8: bb12, otherwise: bb1]; // end of gurard +// } +// bb12: { +// falseEdges -> [real: bb13, imaginary: bb6]; // after guard to binding2 +// } +// bb13: { +// falseEdges -> [real: bb6, imaginary: bb7]; // from before_binding2 to binding3 +// } +// bb14: { +// ... +// switchInt(_10) -> [0u8: bb15, otherwise: bb3]; // end of guard2 +// } +// bb15: { +// falseEdges -> [real: bb16, imaginary: bb8]; // after guard2 to binding4 +// } +// bb16: { +// falseEdges -> [real: bb8, imaginary: bb9]; // from befor binding3 to binding4 +// } +// bb17: { +// ... +// return; +// } +// END rustc.node36.NLL.before.mir