mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-18 11:34:11 +00:00
add TerminatorKind::FalseEdges and use it in matches
This commit is contained in:
parent
2379faa933
commit
2d71c5f10c
@ -62,7 +62,8 @@ for mir::Terminator<'gcx> {
|
|||||||
mir::TerminatorKind::Drop { .. } |
|
mir::TerminatorKind::Drop { .. } |
|
||||||
mir::TerminatorKind::DropAndReplace { .. } |
|
mir::TerminatorKind::DropAndReplace { .. } |
|
||||||
mir::TerminatorKind::Yield { .. } |
|
mir::TerminatorKind::Yield { .. } |
|
||||||
mir::TerminatorKind::Call { .. } => false,
|
mir::TerminatorKind::Call { .. } |
|
||||||
|
mir::TerminatorKind::FalseEdges { .. } => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if hash_spans_unconditionally {
|
if hash_spans_unconditionally {
|
||||||
@ -210,6 +211,12 @@ for mir::TerminatorKind<'gcx> {
|
|||||||
target.hash_stable(hcx, hasher);
|
target.hash_stable(hcx, hasher);
|
||||||
cleanup.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,6 +682,11 @@ pub enum TerminatorKind<'tcx> {
|
|||||||
|
|
||||||
/// Indicates the end of the dropping of a generator
|
/// Indicates the end of the dropping of a generator
|
||||||
GeneratorDrop,
|
GeneratorDrop,
|
||||||
|
|
||||||
|
FalseEdges {
|
||||||
|
real_target: BasicBlock,
|
||||||
|
imaginary_targets: Vec<BasicBlock>
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Terminator<'tcx> {
|
impl<'tcx> Terminator<'tcx> {
|
||||||
@ -731,6 +736,11 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
}
|
}
|
||||||
Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
|
Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
|
||||||
Assert { ref target, .. } => slice::ref_slice(target).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]
|
vec![target]
|
||||||
}
|
}
|
||||||
Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind],
|
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, ")")
|
write!(fmt, ")")
|
||||||
}
|
},
|
||||||
|
FalseEdges { .. } => write!(fmt, "falseEdges")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -910,7 +926,12 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
}
|
}
|
||||||
Assert { cleanup: None, .. } => vec!["".into()],
|
Assert { cleanup: None, .. } => vec!["".into()],
|
||||||
Assert { .. } =>
|
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,
|
Resume => Resume,
|
||||||
Return => Return,
|
Return => Return,
|
||||||
Unreachable => Unreachable,
|
Unreachable => Unreachable,
|
||||||
|
FalseEdges { real_target, ref imaginary_targets } =>
|
||||||
|
FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
|
||||||
};
|
};
|
||||||
Terminator {
|
Terminator {
|
||||||
source_info: self.source_info,
|
source_info: self.source_info,
|
||||||
@ -1917,7 +1940,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
|||||||
Resume |
|
Resume |
|
||||||
Return |
|
Return |
|
||||||
GeneratorDrop |
|
GeneratorDrop |
|
||||||
Unreachable => false
|
Unreachable |
|
||||||
|
FalseEdges { .. } => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,8 +486,15 @@ macro_rules! make_mir_visitor {
|
|||||||
self.visit_operand(value, source_location);
|
self.visit_operand(value, source_location);
|
||||||
self.visit_branch(block, resume);
|
self.visit_branch(block, resume);
|
||||||
drop.map(|t| self.visit_branch(block, t));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +364,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'tcx>
|
|||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::Return |
|
TerminatorKind::Return |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Unreachable => {
|
TerminatorKind::Unreachable |
|
||||||
|
TerminatorKind::FalseEdges { .. } => {
|
||||||
// no data used, thus irrelevant to borrowck
|
// no data used, thus irrelevant to borrowck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use rustc::mir::*;
|
|||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use hair::*;
|
use hair::*;
|
||||||
use syntax::ast::{Name, NodeId};
|
use syntax::ast::{Name, NodeId};
|
||||||
use syntax_pos::{DUMMY_SP, Span};
|
use syntax_pos::Span;
|
||||||
|
|
||||||
// helper functions, broken out by category:
|
// helper functions, broken out by category:
|
||||||
mod simplify;
|
mod simplify;
|
||||||
@ -54,11 +54,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
(body, scope.unwrap_or(self.visibility_scope))
|
(body, scope.unwrap_or(self.visibility_scope))
|
||||||
}).collect();
|
}).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
|
// assemble a list of candidates: there is one candidate per
|
||||||
// pattern, which means there may be more than one candidate
|
// pattern, which means there may be more than one candidate
|
||||||
// *per arm*. These candidates are kept sorted such that the
|
// *per arm*. These candidates are kept sorted such that the
|
||||||
// highest priority candidate comes first in the list.
|
// highest priority candidate comes first in the list.
|
||||||
// (i.e. same order as in source)
|
// (i.e. same order as in source)
|
||||||
|
|
||||||
let candidates: Vec<_> =
|
let candidates: Vec<_> =
|
||||||
arms.iter()
|
arms.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@ -66,17 +72,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
arm.patterns.iter()
|
arm.patterns.iter()
|
||||||
.map(move |pat| (arm_index, pat, arm.guard.clone()))
|
.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 {
|
Candidate {
|
||||||
span: pattern.span,
|
span: pattern.span,
|
||||||
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
|
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
|
||||||
bindings: vec![],
|
bindings: vec![],
|
||||||
guard,
|
guard,
|
||||||
arm_index,
|
arm_index,
|
||||||
|
binding_start_block: *binding_start_block,
|
||||||
|
next_candidate_binding_start_block: *next_candidate_binding_start_block,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.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
|
// this will generate code to test discriminant_lvalue and
|
||||||
// branch to the appropriate arm block
|
// branch to the appropriate arm block
|
||||||
let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, 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)],
|
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
|
||||||
bindings: vec![],
|
bindings: vec![],
|
||||||
guard: None,
|
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
|
// 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.
|
// ...and then we branch to arm with this index.
|
||||||
arm_index: usize,
|
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)]
|
#[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();
|
candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
|
||||||
debug!("match_candidates: {:?} candidates fully matched", fully_matched);
|
debug!("match_candidates: {:?} candidates fully matched", fully_matched);
|
||||||
let mut unmatched_candidates = candidates.split_off(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
|
// If so, apply any bindings, test the guard (if any), and
|
||||||
// branch to the arm.
|
// 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) {
|
||||||
if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks,
|
|
||||||
candidate, is_last) {
|
|
||||||
block = b;
|
block = b;
|
||||||
} else {
|
} else {
|
||||||
// if None is returned, then any remaining candidates
|
// if None is returned, then any remaining candidates
|
||||||
// are unreachable (at least not through this path).
|
// 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);
|
self.test_candidates(span, arm_blocks, &unmatched_candidates, block);
|
||||||
|
|
||||||
// If the target candidates were exhaustive, then we are done.
|
// If the target candidates were exhaustive, then we are done.
|
||||||
if otherwise.is_empty() {
|
// But for borrowck continue build decision tree.
|
||||||
return vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all candidates were sorted into `target_candidates` somewhere, then
|
// If all candidates were sorted into `target_candidates` somewhere, then
|
||||||
// the initial set was inexhaustive.
|
// 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,
|
fn bind_and_guard_matched_candidate<'pat>(&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
arm_blocks: &mut ArmBlocks,
|
arm_blocks: &mut ArmBlocks,
|
||||||
candidate: Candidate<'pat, 'tcx>,
|
candidate: Candidate<'pat, 'tcx>)
|
||||||
is_last_arm: bool)
|
|
||||||
-> Option<BasicBlock> {
|
-> Option<BasicBlock> {
|
||||||
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
|
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
|
||||||
block, candidate);
|
block, candidate);
|
||||||
|
|
||||||
debug_assert!(candidate.match_pairs.is_empty());
|
debug_assert!(candidate.match_pairs.is_empty());
|
||||||
|
|
||||||
self.bind_matched_candidate(block, candidate.bindings);
|
|
||||||
|
|
||||||
let arm_block = arm_blocks.blocks[candidate.arm_index];
|
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 {
|
if let Some(guard) = candidate.guard {
|
||||||
// the block to branch to if the guard fails; if there is no
|
// 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 guard = self.hir.mirror(guard);
|
||||||
let source_info = self.source_info(guard.span);
|
let source_info = self.source_info(guard.span);
|
||||||
let cond = unpack!(block = self.as_local_operand(block, guard));
|
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,
|
self.cfg.terminate(block, source_info,
|
||||||
TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
|
TerminatorKind::if_(self.hir.tcx(), cond, arm_block,
|
||||||
Some(otherwise)
|
false_edge_block));
|
||||||
} 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();
|
let otherwise = self.cfg.start_new_block();
|
||||||
self.cfg.terminate(block, source_info,
|
self.cfg.terminate(false_edge_block, source_info,
|
||||||
TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
|
TerminatorKind::FalseEdges {
|
||||||
|
real_target: otherwise,
|
||||||
|
imaginary_targets:
|
||||||
|
vec![candidate.next_candidate_binding_start_block] });
|
||||||
Some(otherwise)
|
Some(otherwise)
|
||||||
} else {
|
} else {
|
||||||
let source_info = self.source_info(candidate.span);
|
self.cfg.terminate(block, candidate_source_info,
|
||||||
self.cfg.terminate(block, source_info,
|
TerminatorKind::FalseEdges {
|
||||||
TerminatorKind::Goto { target: arm_block });
|
real_target: arm_block,
|
||||||
|
imaginary_targets:
|
||||||
|
vec![candidate.next_candidate_binding_start_block]});
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -598,6 +598,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
bindings: candidate.bindings.clone(),
|
bindings: candidate.bindings.clone(),
|
||||||
guard: candidate.guard.clone(),
|
guard: candidate.guard.clone(),
|
||||||
arm_index: candidate.arm_index,
|
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(),
|
bindings: candidate.bindings.clone(),
|
||||||
guard: candidate.guard.clone(),
|
guard: candidate.guard.clone(),
|
||||||
arm_index: candidate.arm_index,
|
arm_index: candidate.arm_index,
|
||||||
|
binding_start_block: candidate.binding_start_block,
|
||||||
|
next_candidate_binding_start_block: candidate.next_candidate_binding_start_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||||||
TerminatorKind::Goto { target: _ } |
|
TerminatorKind::Goto { target: _ } |
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
|
TerminatorKind::FalseEdges { .. } |
|
||||||
TerminatorKind::Unreachable => { }
|
TerminatorKind::Unreachable => { }
|
||||||
|
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
|
@ -73,7 +73,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::Return |
|
TerminatorKind::Return |
|
||||||
TerminatorKind::Unreachable => {
|
TerminatorKind::Unreachable |
|
||||||
|
TerminatorKind::FalseEdges { .. } => {
|
||||||
// safe (at least as emitted during MIR construction)
|
// safe (at least as emitted during MIR construction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,6 +720,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Unreachable => { }
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
|||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Yield { .. } |
|
TerminatorKind::Yield { .. } |
|
||||||
TerminatorKind::SwitchInt { .. } => {
|
TerminatorKind::SwitchInt { .. } |
|
||||||
|
TerminatorKind::FalseEdges { .. } => {
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
},
|
},
|
||||||
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
|
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
|
||||||
|
@ -317,7 +317,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Yield { .. } |
|
TerminatorKind::Yield { .. } |
|
||||||
TerminatorKind::Unreachable => None,
|
TerminatorKind::Unreachable |
|
||||||
|
TerminatorKind::FalseEdges { .. } => None,
|
||||||
|
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
// Check for unused values. This usually means
|
// Check for unused values. This usually means
|
||||||
|
@ -61,6 +61,9 @@ impl MirPass for SimplifyBranches {
|
|||||||
}), expected, .. } if cond == expected => {
|
}), expected, .. } if cond == expected => {
|
||||||
TerminatorKind::Goto { target: target }
|
TerminatorKind::Goto { target: target }
|
||||||
},
|
},
|
||||||
|
TerminatorKind::FalseEdges { real_target, .. } => {
|
||||||
|
TerminatorKind::Goto { target: real_target }
|
||||||
|
},
|
||||||
_ => continue
|
_ => continue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -441,7 +441,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
TerminatorKind::Return |
|
TerminatorKind::Return |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::Drop { .. } => {
|
TerminatorKind::Drop { .. } |
|
||||||
|
TerminatorKind::FalseEdges { .. } => {
|
||||||
// no checks needed for these
|
// no checks needed for these
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,6 +686,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
self.assert_iscleanup(mir, block, cleanup, true);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +121,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||||||
TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
|
TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
|
||||||
TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
|
TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
|
||||||
TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
|
TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
|
||||||
|
TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
|
||||||
}, kind);
|
}, kind);
|
||||||
self.super_terminator_kind(block, kind, location);
|
self.super_terminator_kind(block, kind, location);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,8 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
|
|||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::SwitchInt { .. } |
|
TerminatorKind::SwitchInt { .. } |
|
||||||
TerminatorKind::Yield { .. } => {
|
TerminatorKind::Yield { .. } |
|
||||||
|
TerminatorKind::FalseEdges { .. } => {
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { cleanup: unwind, .. } |
|
TerminatorKind::Call { cleanup: unwind, .. } |
|
||||||
|
@ -583,7 +583,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||||||
cleanup);
|
cleanup);
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::GeneratorDrop |
|
mir::TerminatorKind::GeneratorDrop |
|
||||||
mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"),
|
mir::TerminatorKind::Yield { .. } |
|
||||||
|
mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +623,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||||||
mir::TerminatorKind::Unreachable |
|
mir::TerminatorKind::Unreachable |
|
||||||
mir::TerminatorKind::Assert { .. } => {}
|
mir::TerminatorKind::Assert { .. } => {}
|
||||||
mir::TerminatorKind::GeneratorDrop |
|
mir::TerminatorKind::GeneratorDrop |
|
||||||
mir::TerminatorKind::Yield { .. } => bug!(),
|
mir::TerminatorKind::Yield { .. } |
|
||||||
|
mir::TerminatorKind::FalseEdges { .. } => bug!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.super_terminator_kind(block, kind, location);
|
self.super_terminator_kind(block, kind, location);
|
||||||
|
24
src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs
Normal file
24
src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs
Normal file
@ -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 <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.
|
||||||
|
|
||||||
|
|
||||||
|
//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]
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,24 @@
|
|||||||
// revisions: ast mir
|
// revisions: ast mir
|
||||||
//[mir]compile-flags: -Z emit-end-regions -Z borrowck-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() {
|
fn main() {
|
||||||
let mut x = 1;
|
let mut x = 1;
|
||||||
let _x = &mut x;
|
let _x = &mut x;
|
||||||
|
166
src/test/mir-opt/match_false_edges.rs
Normal file
166
src/test/mir-opt/match_false_edges.rs
Normal file
@ -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 <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.
|
||||||
|
|
||||||
|
// 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<i32>::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<i32>::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
|
Loading…
Reference in New Issue
Block a user