add span/scope-id to terminator

This commit is contained in:
Niko Matsakis 2016-03-18 08:52:13 -04:00
parent 3a16f57fbb
commit 9d00deee96
9 changed files with 167 additions and 76 deletions

View File

@ -230,6 +230,8 @@ pub struct BasicBlockData<'tcx> {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Terminator<'tcx> {
pub span: Span,
pub scope: ScopeId,
pub kind: TerminatorKind<'tcx>
}

View File

@ -44,9 +44,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
StmtKind::Expr { scope, expr } => {
unpack!(block = this.in_scope(scope, block, |this, _| {
let expr = this.hir.mirror(expr);
let expr_span = expr.span;
let temp = this.temp(expr.ty.clone());
unpack!(block = this.into(&temp, block, expr));
unpack!(block = this.build_drop(block, temp));
unpack!(block = this.build_drop(block, expr_span, temp));
block.unit()
}));
}

View File

@ -83,11 +83,15 @@ impl<'tcx> CFG<'tcx> {
pub fn terminate(&mut self,
block: BasicBlock,
scope: ScopeId,
span: Span,
kind: TerminatorKind<'tcx>) {
debug_assert!(self.block_data(block).terminator.is_none(),
"terminate: block {:?} already has a terminator set", block);
self.block_data_mut(block).terminator = Some(Terminator {
kind: kind
span: span,
scope: scope,
kind: kind,
});
}
}

View File

@ -68,6 +68,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block());
this.cfg.terminate(block,
scope_id,
expr_span,
TerminatorKind::If {
cond: Operand::Consume(lt),
targets: (success, failure),

View File

@ -53,7 +53,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let mut then_block = this.cfg.start_new_block();
let mut else_block = this.cfg.start_new_block();
this.cfg.terminate(block, TerminatorKind::If {
this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::If {
cond: operand,
targets: (then_block, else_block)
});
@ -70,8 +70,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
};
let join_block = this.cfg.start_new_block();
this.cfg.terminate(then_block, TerminatorKind::Goto { target: join_block });
this.cfg.terminate(else_block, TerminatorKind::Goto { target: join_block });
this.cfg.terminate(then_block,
scope_id,
expr_span,
TerminatorKind::Goto { target: join_block });
this.cfg.terminate(else_block,
scope_id,
expr_span,
TerminatorKind::Goto { target: join_block });
join_block.unit()
}
@ -97,10 +103,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block),
};
this.cfg.terminate(block, TerminatorKind::If { cond: lhs, targets: blocks });
this.cfg.terminate(block,
scope_id,
expr_span,
TerminatorKind::If { cond: lhs, targets: blocks });
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
this.cfg.terminate(else_block, TerminatorKind::If {
this.cfg.terminate(else_block, scope_id, expr_span, TerminatorKind::If {
cond: rhs,
targets: (true_block, false_block)
});
@ -121,8 +130,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
literal: this.hir.false_literal(),
});
this.cfg.terminate(true_block, TerminatorKind::Goto { target: join_block });
this.cfg.terminate(false_block, TerminatorKind::Goto { target: join_block });
this.cfg.terminate(true_block,
scope_id,
expr_span,
TerminatorKind::Goto { target: join_block });
this.cfg.terminate(false_block,
scope_id,
expr_span,
TerminatorKind::Goto { target: join_block });
join_block.unit()
}
@ -146,7 +161,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let exit_block = this.cfg.start_new_block();
// start the loop
this.cfg.terminate(block, TerminatorKind::Goto { target: loop_block });
this.cfg.terminate(block,
scope_id,
expr_span,
TerminatorKind::Goto { target: loop_block });
let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
// conduct the test, if necessary
@ -159,6 +177,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
this.cfg.terminate(loop_block_end,
scope_id,
expr_span,
TerminatorKind::If {
cond: cond,
targets: (body_block, exit_block)
@ -175,7 +195,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end, TerminatorKind::Goto { target: loop_block });
this.cfg.terminate(body_block_end,
scope_id,
expr_span,
TerminatorKind::Goto { target: loop_block });
});
// If the loop may reach its exit_block, we assign an empty tuple to the
// destination to keep the MIR well-formed.
@ -188,9 +211,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// Note: we evaluate assignments right-to-left. This
// is better for borrowck interaction with overloaded
// operators like x[j] = x[i].
let lhs = this.hir.mirror(lhs);
let lhs_span = lhs.span;
let rhs = unpack!(block = this.as_operand(block, rhs));
let lhs = unpack!(block = this.as_lvalue(block, lhs));
unpack!(block = this.build_drop(block, lhs.clone()));
unpack!(block = this.build_drop(block, lhs_span, lhs.clone()));
this.cfg.push_assign(block, scope_id, expr_span, &lhs, Rvalue::Use(rhs));
block.unit()
}
@ -254,7 +279,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let success = this.cfg.start_new_block();
let cleanup = this.diverge_cleanup();
this.cfg.terminate(block, TerminatorKind::Call {
this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::Call {
func: fun,
args: args,
cleanup: cleanup,

View File

@ -71,6 +71,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
})
.map(|(arm_index, pattern, guard)| {
Candidate {
span: pattern.span,
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard: guard,
@ -87,7 +88,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// an empty vector to be returned here, but the algorithm is
// not entirely precise
if !otherwise.is_empty() {
let join_block = self.join_otherwise_blocks(otherwise);
let join_block = self.join_otherwise_blocks(span, otherwise);
self.panic(join_block, "something about matches algorithm not being precise", span);
}
@ -97,7 +98,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() {
let mut arm_block = arm_blocks.blocks[arm_index];
unpack!(arm_block = self.into(destination, arm_block, arm_body));
self.cfg.terminate(arm_block, TerminatorKind::Goto { target: end_block });
self.cfg.terminate(arm_block,
var_scope_id,
span,
TerminatorKind::Goto { target: end_block });
}
end_block.unit()
@ -146,6 +150,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// create a dummy candidate
let mut candidate = Candidate {
span: irrefutable_pat.span,
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
bindings: vec![],
guard: None,
@ -206,6 +211,9 @@ struct ArmBlocks {
#[derive(Clone, Debug)]
pub struct Candidate<'pat, 'tcx:'pat> {
// span of the original pattern that gave rise to this candidate
span: Span,
// all of these must be satisfied...
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
@ -370,20 +378,25 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
// Otherwise, let's process those remaining candidates.
let join_block = self.join_otherwise_blocks(otherwise);
let join_block = self.join_otherwise_blocks(span, otherwise);
self.match_candidates(span, arm_blocks, untested_candidates, join_block)
}
fn join_otherwise_blocks(&mut self,
span: Span,
otherwise: Vec<BasicBlock>)
-> BasicBlock
{
let scope_id = self.innermost_scope_id();
if otherwise.len() == 1 {
otherwise[0]
} else {
let join_block = self.cfg.start_new_block();
for block in otherwise {
self.cfg.terminate(block, TerminatorKind::Goto { target: join_block });
self.cfg.terminate(block,
scope_id,
span,
TerminatorKind::Goto { target: join_block });
}
join_block
}
@ -550,16 +563,25 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let arm_block = arm_blocks.blocks[candidate.arm_index];
let scope_id = self.innermost_scope_id();
if let Some(guard) = candidate.guard {
// the block to branch to if the guard fails; if there is no
// guard, this block is simply unreachable
let guard = self.hir.mirror(guard);
let guard_span = guard.span;
let cond = unpack!(block = self.as_operand(block, guard));
let otherwise = self.cfg.start_new_block();
self.cfg.terminate(block, TerminatorKind::If { cond: cond,
targets: (arm_block, otherwise)});
self.cfg.terminate(block,
scope_id,
guard_span,
TerminatorKind::If { cond: cond,
targets: (arm_block, otherwise)});
Some(otherwise)
} else {
self.cfg.terminate(block, TerminatorKind::Goto { target: arm_block });
self.cfg.terminate(block,
scope_id,
candidate.span,
TerminatorKind::Goto { target: arm_block });
None
}
}

View File

@ -153,7 +153,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let target_blocks: Vec<_> =
(0..num_enum_variants).map(|_| self.cfg.start_new_block())
.collect();
self.cfg.terminate(block, TerminatorKind::Switch {
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
discr: lvalue.clone(),
adt_def: adt_def,
targets: target_blocks.clone()
@ -168,12 +168,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
.map(|_| self.cfg.start_new_block())
.chain(Some(otherwise))
.collect();
self.cfg.terminate(block, TerminatorKind::SwitchInt {
discr: lvalue.clone(),
switch_ty: switch_ty,
values: options.clone(),
targets: targets.clone(),
});
self.cfg.terminate(block,
scope_id,
test.span,
TerminatorKind::SwitchInt {
discr: lvalue.clone(),
switch_ty: switch_ty,
values: options.clone(),
targets: targets.clone(),
});
targets
}
@ -226,7 +229,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let eq_result = self.temp(bool_ty);
let eq_block = self.cfg.start_new_block();
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, Terminator::Call {
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call {
func: Operand::Constant(Constant {
span: test.span,
ty: mty,
@ -239,7 +242,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// check the result
let block = self.cfg.start_new_block();
self.cfg.terminate(eq_block, Terminator::If {
self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If {
cond: Operand::Consume(eq_result),
targets: (block, fail),
});
@ -286,7 +289,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// branch based on result
let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
self.cfg.start_new_block()];
self.cfg.terminate(block, TerminatorKind::If {
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If {
cond: Operand::Consume(result),
targets: (target_blocks[0], target_blocks[1])
});
@ -313,7 +316,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// branch based on result
let target_block = self.cfg.start_new_block();
self.cfg.terminate(block, TerminatorKind::If {
self.cfg.terminate(block, scope_id, span, TerminatorKind::If {
cond: Operand::Consume(result),
targets: (target_block, fail_block)
});
@ -466,6 +469,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
.map(|(_, mp)| mp.clone())
.collect();
Candidate {
span: candidate.span,
match_pairs: other_match_pairs,
bindings: candidate.bindings.clone(),
guard: candidate.guard.clone(),
@ -507,6 +511,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect();
Candidate {
span: candidate.span,
match_pairs: all_match_pairs,
bindings: candidate.bindings.clone(),
guard: candidate.guard.clone(),

View File

@ -160,14 +160,17 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
let mut block = START_BLOCK;
let arg_decls = unpack!(block = builder.args_and_body(block,
implicit_arguments,
explicit_arguments,
argument_extent,
ast_block));
let (arg_decls, arg_scope_id) =
unpack!(block = builder.args_and_body(block,
implicit_arguments,
explicit_arguments,
argument_extent,
ast_block));
builder.cfg.terminate(block, TerminatorKind::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, TerminatorKind::Return);
builder.cfg.terminate(block, arg_scope_id, span,
TerminatorKind::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, arg_scope_id, span,
TerminatorKind::Return);
MirPlusPlus {
mir: Mir {
@ -190,7 +193,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_extent: CodeExtent,
ast_block: &'tcx hir::Block)
-> BlockAnd<Vec<ArgDecl<'tcx>>>
-> BlockAnd<(Vec<ArgDecl<'tcx>>, ScopeId)>
{
self.in_scope(argument_extent, block, |this, argument_scope_id| {
// to start, translate the argument patterns and collect the argument types.
@ -219,7 +222,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// start the first basic block and translate the body
unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block));
block.and(arg_decls)
block.and((arg_decls, argument_scope_id))
})
}

View File

@ -116,6 +116,7 @@ pub struct Scope<'tcx> {
}
struct DropData<'tcx> {
span: Span,
value: Lvalue<'tcx>,
// NB: per-drop “cache” is necessary for the build_scope_drops function below.
/// The cached block for the cleanups-on-diverge path. This block contains code to run the
@ -288,14 +289,19 @@ impl<'a,'tcx> Builder<'a,'tcx> {
if let Some(ref free_data) = scope.free {
let next = self.cfg.start_new_block();
let free = build_free(self.hir.tcx(), tmp.clone(), free_data, next);
self.cfg.terminate(block, free);
self.cfg.terminate(block, scope.id, span, free);
block = next;
}
self.scope_auxiliary[scope.id.index()]
.postdoms
.push(self.cfg.current_location(block));
}
self.cfg.terminate(block, TerminatorKind::Goto { target: target });
let scope_id = self.innermost_scope_id();
self.cfg.terminate(block,
scope_id,
span,
TerminatorKind::Goto { target: target });
}
// Finding scopes
@ -351,6 +357,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// No need to invalidate any caches here. The just-scheduled drop will branch into
// the drop that comes before it in the vector.
scope.drops.push(DropData {
span: span,
value: lvalue.clone(),
cached_block: None
});
@ -429,14 +436,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
/// Utility function for *non*-scope code to build their own drops
pub fn build_drop(&mut self, block: BasicBlock, value: Lvalue<'tcx>) -> BlockAnd<()> {
pub fn build_drop(&mut self,
block: BasicBlock,
span: Span,
value: Lvalue<'tcx>)
-> BlockAnd<()> {
let scope_id = self.innermost_scope_id();
let next_target = self.cfg.start_new_block();
let diverge_target = self.diverge_cleanup();
self.cfg.terminate(block, TerminatorKind::Drop {
value: value,
target: next_target,
unwind: diverge_target,
});
self.cfg.terminate(block,
scope_id,
span,
TerminatorKind::Drop {
value: value,
target: next_target,
unwind: diverge_target,
});
next_target.unit()
}
@ -445,10 +460,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// =========
// FIXME: should be moved into their own module
pub fn panic_bounds_check(&mut self,
block: BasicBlock,
index: Operand<'tcx>,
len: Operand<'tcx>,
span: Span) {
block: BasicBlock,
index: Operand<'tcx>,
len: Operand<'tcx>,
span: Span) {
// fn(&(filename: &'static str, line: u32), index: usize, length: usize) -> !
let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region?
let func = self.lang_function(lang_items::PanicBoundsCheckFnLangItem);
@ -474,7 +489,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple;
Rvalue::Ref(region, BorrowKind::Shared, tuple));
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, TerminatorKind::Call {
self.cfg.terminate(block, scope_id, span, TerminatorKind::Call {
func: Operand::Constant(func),
args: vec![Operand::Consume(tuple_ref), index, len],
destination: None,
@ -516,7 +531,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple;
Rvalue::Ref(region, BorrowKind::Shared, tuple));
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, TerminatorKind::Call {
self.cfg.terminate(block, scope_id, span, TerminatorKind::Call {
func: Operand::Constant(func),
args: vec![Operand::Consume(tuple_ref)],
cleanup: cleanup,
@ -575,7 +590,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
});
let next = cfg.start_new_block();
cfg.terminate(block, TerminatorKind::Drop {
cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
value: drop_data.value.clone(),
target: next,
unwind: on_diverge
@ -599,12 +614,15 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
let mut last_drop_block = None;
for drop_data in scope.drops.iter_mut().rev() {
if let Some(cached_block) = drop_data.cached_block {
if let Some((previous_block, previous_value)) = previous {
cfg.terminate(previous_block, TerminatorKind::Drop {
value: previous_value,
target: cached_block,
unwind: None
});
if let Some((previous_block, previous_span, previous_value)) = previous {
cfg.terminate(previous_block,
scope.id,
previous_span,
TerminatorKind::Drop {
value: previous_value,
target: cached_block,
unwind: None
});
return last_drop_block.unwrap();
} else {
return cached_block;
@ -612,23 +630,26 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
} else {
let block = cfg.start_new_cleanup_block();
drop_data.cached_block = Some(block);
if let Some((previous_block, previous_value)) = previous {
cfg.terminate(previous_block, TerminatorKind::Drop {
value: previous_value,
target: block,
unwind: None
});
if let Some((previous_block, previous_span, previous_value)) = previous {
cfg.terminate(previous_block,
scope.id,
previous_span,
TerminatorKind::Drop {
value: previous_value,
target: block,
unwind: None
});
} else {
last_drop_block = Some(block);
}
previous = Some((block, drop_data.value.clone()));
previous = Some((block, drop_data.span, drop_data.value.clone()));
}
}
// Prepare the end target for this chain.
let mut target = target.unwrap_or_else(||{
let b = cfg.start_new_cleanup_block();
cfg.terminate(b, TerminatorKind::Resume);
cfg.terminate(b, scope.id, DUMMY_SP, TerminatorKind::Resume); // TODO
b
});
@ -638,19 +659,25 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
cached_block
} else {
let into = cfg.start_new_cleanup_block();
cfg.terminate(into, build_free(tcx, unit_temp, free_data, target));
cfg.terminate(into,
scope.id,
free_data.span,
build_free(tcx, unit_temp, free_data, target));
free_data.cached_block = Some(into);
into
}
};
if let Some((previous_block, previous_value)) = previous {
if let Some((previous_block, previous_span, previous_value)) = previous {
// Finally, branch into that just-built `target` from the `previous_block`.
cfg.terminate(previous_block, TerminatorKind::Drop {
value: previous_value,
target: target,
unwind: None
});
cfg.terminate(previous_block,
scope.id,
previous_span,
TerminatorKind::Drop {
value: previous_value,
target: target,
unwind: None
});
last_drop_block.unwrap()
} else {
// If `previous.is_none()`, there were no drops in this scope we return the