From 2d71c5f10c9c2ae02184e6d1fc2ec0c34dce00d6 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Fri, 13 Oct 2017 16:36:15 +0300 Subject: [PATCH 1/5] 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 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 + }, } 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..9d68fe5759c6a 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 7b91c43aa3722..cf3c9fefa4766 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 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 { + 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 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 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..81153c0224425 --- /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 From a954dcc72edea804d866b01ec09d10fdb5add37a Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Tue, 31 Oct 2017 13:50:04 +0300 Subject: [PATCH 2/5] fix opt-mir test and remove false edge if no guard --- src/librustc_mir/build/matches/mod.rs | 5 +- src/test/mir-opt/match_false_edges.rs | 144 +++++++++++++------------- 2 files changed, 75 insertions(+), 74 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 9d68fe5759c6a..d831d8ba2c42c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -752,10 +752,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(otherwise) } else { self.cfg.terminate(block, candidate_source_info, - TerminatorKind::FalseEdges { - real_target: arm_block, - imaginary_targets: - vec![candidate.next_candidate_binding_start_block]}); + TerminatorKind::Goto { target: arm_block }); None } } diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 81153c0224425..38e76b001da8d 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -21,8 +21,8 @@ fn guard2(_:i32) -> bool { fn full_tested_match() { let _ = match Some(42) { - Some(_) if guard() => 1, - Some(_) => 2, + Some(x) if guard() => 1 + x, + Some(y) => 2 + y, None => 3 }; } @@ -42,50 +42,54 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); -// _3 = discriminant(_2); -// switchInt(_3) -> [0isize: bb8, otherwise: bb9]; +// _5 = discriminant(_2); +// switchInt(_5) -> [0isize: bb6, otherwise: bb7]; // } // bb1: { // arm1 -// _1 = const 1i32; -// goto -> bb13; +// StorageLive(_7); +// _7 = _3; +// _1 = Add(const 1i32, _7); +// ... +// goto -> bb11; // } -// bb2: { // arm2 -// _1 = const 2i32; -// goto -> bb13; +// bb2: { // binding1 guard +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = const guard() -> bb8; // } -// bb3: { // arm3 -// _1 = const 3i32; -// goto -> bb13; +// bb3: { // binding2 & arm2 +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = _4; +// _1 = Add(const 2i32, _8); +// StorageDead(_8); +// goto -> bb11; // } -// bb4: { // binding1 -// ... -// _4 = const guard() -> bb10; +// bb4: { // binding3(empty) arm3 +// _1 = const 3i32; +// goto -> bb11; // } -// bb5: { // binding2 -// falseEdges -> [real: bb2, imaginary: bb6]; +// bb5: { +// unreachable; // } -// bb6: { // binding3 -// falseEdges -> [real: bb3, imaginary: bb7]; +// bb6: { +// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding3 to unreachable // } // bb7: { -// unreachable; +// falseEdges -> [real: bb2, imaginary: bb3]; // from before_binding1 to binding2 // } // bb8: { -// falseEdges -> [real: bb6, imaginary: bb7]; // from before_binding3 to unreachable +// switchInt(_6) -> [0u8: bb9, otherwise: bb1]; // end of guard // } // bb9: { -// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding1 to binding2 +// falseEdges -> [real: bb10, imaginary: bb3]; // after_guard to binding2 // } // bb10: { -// switchInt(_4) -> [0u8: bb11, otherwise: bb1]; // end of guard +// falseEdges -> [real: bb3, imaginary: bb4]; // from before_binding2 to binding3 // } // bb11: { -// falseEdges -> [real: bb12, imaginary: bb5]; // after_guard to binding2 -// } -// bb12: { -// falseEdges -> [real: bb5, imaginary: bb6]; // from before_binding2 to binding3 -// } -// bb13: { // ... // return; // } @@ -93,74 +97,74 @@ fn main() { // // END rustc.node17.NLL.before.mir // -// START rustc.node36.NLL.before.mir +// START rustc.node40.NLL.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); // _7 = discriminant(_2); -// switchInt(_7) -> [1isize: bb10, otherwise: bb13]; +// switchInt(_7) -> [1isize: bb8, otherwise: bb11]; // } // bb1: { // arm1 // _1 = const 1i32; -// goto -> bb17; -// } -// bb2: { // arm2 -// _1 = const 2i32; -// goto -> bb17; +// goto -> bb15; // } -// bb3: { // arm3 +// bb2: { // arm3 // _1 = const 3i32; -// goto -> bb17; +// goto -> bb15; // } -// bb4: { // arm4 -// _1 = const 4i32; -// goto -> bb17; -// } -// bb5: { // binding1: Some(w) if guard() => -// ... -// _8 = const guard() -> bb11; +// bb3: { // binding1: Some(w) if guard() => +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> bb9; // } -// bb6: { // binding2: x => -// ... +// bb4: { // binding2 & arm2 +// StorageLive(_4); // _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_ => -// ... +// _1 = const 2i32; +// goto -> bb15; +// } +// bb5: { // binding3: Some(y) if guard2(y) => +// StorageLive(_5); +// _5 = ((_2 as Some).0: i32); +// StorageLive(_10); +// StorageLive(_11); +// _11 = _5; +// _10 = const guard2(_11) -> bb12; +// } +// bb6: { // binding4 & arm4 +// StorageLive(_6); // _6 = _2; -// falseEdges -> [real: bb4, imaginary: bb9]; // after binding3 to unreachable +// _1 = const 4i32; +// goto -> bb15; // } -// bb9: { +// bb7: { // unreachable; // } +// bb8: { +// falseEdges -> [real: bb3, imaginary: bb4]; // from before_binding1 to binding2 +// } +// bb9: { +// switchInt(_8) -> [0u8: bb10, otherwise: bb1]; // end of gurard +// } // bb10: { -// falseEdges -> [real: bb5, imaginary: bb6]; // from before_binding1 to binding2 +// falseEdges -> [real: bb11, imaginary: bb4]; // after guard to binding2 // } // bb11: { -// switchInt(_8) -> [0u8: bb12, otherwise: bb1]; // end of gurard +// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding2 to binding3 // } // bb12: { -// falseEdges -> [real: bb13, imaginary: bb6]; // after guard to binding2 +// StorageDead(_11); +// switchInt(_10) -> [0u8: bb13, otherwise: bb2]; // end of guard2 // } // bb13: { -// falseEdges -> [real: bb6, imaginary: bb7]; // from before_binding2 to binding3 +// falseEdges -> [real: bb14, imaginary: bb6]; // after guard2 to binding4 // } // bb14: { -// ... -// switchInt(_10) -> [0u8: bb15, otherwise: bb3]; // end of guard2 +// falseEdges -> [real: bb6, imaginary: bb7]; // from befor binding4 to unreachable // } // 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 +// END rustc.node40.NLL.before.mir From cb2867da88f1653d74bcb771445e6d1e3fc1de5b Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Tue, 31 Oct 2017 18:02:14 +0300 Subject: [PATCH 3/5] fix pre binding false edges --- src/librustc_mir/build/matches/mod.rs | 31 ++--- src/librustc_mir/build/matches/test.rs | 8 +- src/test/mir-opt/match_false_edges.rs | 162 +++++++++++++------------ 3 files changed, 104 insertions(+), 97 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index d831d8ba2c42c..b65d859e7d756 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -56,7 +56,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // 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) + 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 @@ -72,23 +72,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm.patterns.iter() .map(move |pat| (arm_index, pat, arm.guard.clone())) }) - .zip(binding_start_blocks.iter().zip(binding_start_blocks.iter().skip(1))) + .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1))) .map(|((arm_index, pattern, guard), - (binding_start_block, next_candidate_binding_start_block))| { + (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, - binding_start_block: *binding_start_block, - next_candidate_binding_start_block: *next_candidate_binding_start_block, + 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(*binding_start_blocks.last().unwrap(), + self.cfg.terminate(*pre_binding_blocks.last().unwrap(), outer_source_info, TerminatorKind::Unreachable); // this will generate code to test discriminant_lvalue and @@ -165,8 +165,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // since we don't call `match_candidates`, next fields is unused arm_index: 0, - binding_start_block: block, - next_candidate_binding_start_block: block + pre_binding_block: block, + next_candidate_pre_binding_block: block }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -298,8 +298,8 @@ pub struct Candidate<'pat, 'tcx:'pat> { arm_index: usize, // ...and the blocks for add false edges between candidates - binding_start_block: BasicBlock, - next_candidate_binding_start_block: BasicBlock, + pre_binding_block: BasicBlock, + next_candidate_pre_binding_block: BasicBlock, } #[derive(Clone, Debug)] @@ -723,12 +723,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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: candidate.binding_start_block, + real_target: block, imaginary_targets: - vec![candidate.next_candidate_binding_start_block]}); + vec![candidate.next_candidate_pre_binding_block]}); - block = candidate.binding_start_block; self.bind_matched_candidate(block, candidate.bindings); if let Some(guard) = candidate.guard { @@ -748,7 +751,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::FalseEdges { real_target: otherwise, imaginary_targets: - vec![candidate.next_candidate_binding_start_block] }); + vec![candidate.next_candidate_pre_binding_block] }); Some(otherwise) } else { self.cfg.terminate(block, candidate_source_info, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index cf3c9fefa4766..4792bf2b213e6 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -598,8 +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, + pre_binding_block: candidate.pre_binding_block, + next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block, } } @@ -661,8 +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, + pre_binding_block: candidate.pre_binding_block, + next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block, } } diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 38e76b001da8d..53e5deeb9bd89 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -43,7 +43,7 @@ fn main() { // ... // _2 = std::option::Option::Some(const 42i32,); // _5 = discriminant(_2); -// switchInt(_5) -> [0isize: bb6, otherwise: bb7]; +// switchInt(_5) -> [0isize: bb5, otherwise: bb3]; // } // bb1: { // arm1 // StorageLive(_7); @@ -52,13 +52,35 @@ fn main() { // ... // goto -> bb11; // } -// bb2: { // binding1 guard +// bb2: { // binding3(empty) and arm3 +// _1 = 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; // } -// bb3: { // binding2 & arm2 +// bb8: { // end of guard +// switchInt(_6) -> [0u8: bb9, otherwise: bb1]; +// } +// bb9: { // to pre_binding2 +// falseEdges -> [real: bb4, imaginary: bb4]; +// } +// bb10: { // binding2 and arm2 // StorageLive(_4); // _4 = ((_2 as Some).0: i32); // StorageLive(_8); @@ -67,28 +89,6 @@ fn main() { // StorageDead(_8); // goto -> bb11; // } -// bb4: { // binding3(empty) arm3 -// _1 = const 3i32; -// goto -> bb11; -// } -// bb5: { -// unreachable; -// } -// bb6: { -// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding3 to unreachable -// } -// bb7: { -// falseEdges -> [real: bb2, imaginary: bb3]; // from before_binding1 to binding2 -// } -// bb8: { -// switchInt(_6) -> [0u8: bb9, otherwise: bb1]; // end of guard -// } -// bb9: { -// falseEdges -> [real: bb10, imaginary: bb3]; // after_guard to binding2 -// } -// bb10: { -// falseEdges -> [real: bb3, imaginary: bb4]; // from before_binding2 to binding3 -// } // bb11: { // ... // return; @@ -102,68 +102,72 @@ fn main() { // ... // _2 = std::option::Option::Some(const 1i32,); // _7 = discriminant(_2); -// switchInt(_7) -> [1isize: bb8, otherwise: bb11]; +// switchInt(_7) -> [1isize: bb3, otherwise: bb4]; // } // bb1: { // arm1 // _1 = const 1i32; -// goto -> bb15; +// goto -> bb16; // } // bb2: { // arm3 // _1 = const 3i32; -// goto -> bb15; -// } -// bb3: { // binding1: Some(w) if guard() => -// StorageLive(_3); -// _3 = ((_2 as Some).0: i32); -// StorageLive(_8); -// _8 = const guard() -> bb9; -// } -// bb4: { // binding2 & arm2 -// StorageLive(_4); -// _4 = _2; -// _1 = const 2i32; -// goto -> bb15; -// } -// bb5: { // binding3: Some(y) if guard2(y) => -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); -// StorageLive(_10); -// StorageLive(_11); -// _11 = _5; -// _10 = const guard2(_11) -> bb12; -// } -// bb6: { // binding4 & arm4 -// StorageLive(_6); -// _6 = _2; -// _1 = const 4i32; -// goto -> bb15; -// } -// bb7: { -// unreachable; +// goto -> bb16; // } -// bb8: { -// falseEdges -> [real: bb3, imaginary: bb4]; // from before_binding1 to binding2 -// } -// bb9: { -// switchInt(_8) -> [0u8: bb10, otherwise: bb1]; // end of gurard -// } -// bb10: { -// falseEdges -> [real: bb11, imaginary: bb4]; // after guard to binding2 -// } -// bb11: { -// falseEdges -> [real: bb4, imaginary: bb5]; // from before_binding2 to binding3 -// } -// bb12: { +// +// 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: bb13, otherwise: bb2]; // end of guard2 -// } -// bb13: { -// falseEdges -> [real: bb14, imaginary: bb6]; // after guard2 to binding4 -// } -// bb14: { -// falseEdges -> [real: bb6, imaginary: bb7]; // from befor binding4 to unreachable -// } -// bb15: { +// 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; // } From 59d31846243387dd2d392a5572cd48e656ff7353 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Wed, 1 Nov 2017 16:21:30 +0300 Subject: [PATCH 4/5] add one more sample --- src/test/mir-opt/match_false_edges.rs | 74 ++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 53e5deeb9bd89..e0015fe7d766b 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -18,12 +18,19 @@ fn guard2(_:i32) -> bool { true } -fn full_tested_match() -{ +fn full_tested_match() { let _ = match Some(42) { Some(x) if guard() => 1 + x, Some(y) => 2 + y, - None => 3 + None => 3, + }; +} + +fn full_tested_match2() { + let _ = match Some(42) { + Some(x) if guard() => 1 + x, + None => 3, + Some(y) => 2 + y, }; } @@ -93,11 +100,66 @@ fn main() { // ... // return; // } -// -// // END rustc.node17.NLL.before.mir // // START rustc.node40.NLL.before.mir +// bb0: { +// ... +// _2 = std::option::Option::Some(const 42i32,); +// _5 = discriminant(_2); +// switchInt(_5) -> [0isize: bb4, otherwise: bb3]; +// } +// bb1: { // arm1 +// StorageLive(_7); +// _7 = _3; +// _1 = Add(const 1i32, _7); +// ... +// goto -> bb11; +// } +// bb2: { // binding3(empty) and arm3 +// _1 = 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 = Add(const 2i32, _8); +// StorageDead(_8); +// goto -> bb11; +// } +// bb11: { +// ... +// return; +// } +// END rustc.node40.NLL.before.mir +// +// START rustc.node63.NLL.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); @@ -171,4 +233,4 @@ fn main() { // ... // return; // } -// END rustc.node40.NLL.before.mir +// END rustc.node63.NLL.before.mir From d9e64ebaaaf4cf69d790020f41c3a1006903d3cf Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Thu, 2 Nov 2017 10:21:36 +0300 Subject: [PATCH 5/5] change mir stage in test --- src/test/mir-opt/match_false_edges.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index e0015fe7d766b..1a2e5af95d048 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -45,7 +45,7 @@ fn main() { // END RUST SOURCE // -// START rustc.node17.NLL.before.mir +// START rustc.node17.SimplifyBranches-initial.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); @@ -87,7 +87,7 @@ fn main() { // bb9: { // to pre_binding2 // falseEdges -> [real: bb4, imaginary: bb4]; // } -// bb10: { // binding2 and arm2 +// bb10: { // bindingNoLandingPads.before.mir2 and arm2 // StorageLive(_4); // _4 = ((_2 as Some).0: i32); // StorageLive(_8); @@ -100,9 +100,9 @@ fn main() { // ... // return; // } -// END rustc.node17.NLL.before.mir +// END rustc.node17.SimplifyBranches-initial.before.mir // -// START rustc.node40.NLL.before.mir +// START rustc.node40.SimplifyBranches-initial.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); @@ -157,9 +157,9 @@ fn main() { // ... // return; // } -// END rustc.node40.NLL.before.mir +// END rustc.node40.SimplifyBranches-initial.before.mir // -// START rustc.node63.NLL.before.mir +// START rustc.node63.SimplifyBranches-initial.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); @@ -233,4 +233,4 @@ fn main() { // ... // return; // } -// END rustc.node63.NLL.before.mir +// END rustc.node63.SimplifyBranches-initial.before.mir