Add destruction extents around blocks and statements in HAIR.

This commit is contained in:
Felix S. Klock II 2017-05-23 13:18:20 +02:00
parent 609813bbc2
commit cbed41a174
4 changed files with 60 additions and 22 deletions

View File

@ -21,21 +21,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ast_block: &'tcx hir::Block,
source_info: SourceInfo)
-> BlockAnd<()> {
let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block);
self.in_scope(extent, block, move |this| {
if targeted_by_break {
// This is a `break`-able block (currently only `catch { ... }`)
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(None, exit_block,
destination.clone(), |this| {
let Block { extent, opt_destruction_extent, span, stmts, expr, targeted_by_break } =
self.hir.mirror(ast_block);
self.in_opt_scope(opt_destruction_extent, block, move |this| {
this.in_scope(extent, block, move |this| {
if targeted_by_break {
// This is a `break`-able block (currently only `catch { ... }`)
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(
None, exit_block, destination.clone(), |this| {
this.ast_block_stmts(destination, block, span, stmts, expr)
});
this.cfg.terminate(unpack!(block_exit), source_info,
TerminatorKind::Goto { target: exit_block });
exit_block.unit()
} else {
this.ast_block_stmts(destination, block, span, stmts, expr)
});
this.cfg.terminate(unpack!(block_exit), source_info,
TerminatorKind::Goto { target: exit_block });
exit_block.unit()
} else {
this.ast_block_stmts(destination, block, span, stmts, expr)
}
}
})
})
}
@ -67,12 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let mut let_extent_stack = Vec::with_capacity(8);
let outer_visibility_scope = this.visibility_scope;
for stmt in stmts {
let Stmt { span: _, kind } = this.hir.mirror(stmt);
let Stmt { span: _, kind, opt_destruction_extent } = this.hir.mirror(stmt);
match kind {
StmtKind::Expr { scope, expr } => {
unpack!(block = this.in_scope(scope, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
unpack!(block = this.in_opt_scope(opt_destruction_extent, block, |this| {
this.in_scope(scope, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
})
}));
}
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
@ -89,10 +94,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Evaluate the initializer, if present.
if let Some(init) = initializer {
unpack!(block = this.in_scope(init_scope, block, move |this| {
// FIXME #30046 ^~~~
this.expr_into_pattern(block, pattern, init)
}));
unpack!(block = this.in_opt_scope(
opt_destruction_extent, block, move |this| {
this.in_scope(init_scope, block, move |this| {
// FIXME #30046 ^~~~
this.expr_into_pattern(block, pattern, init)
})
}));
} else {
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.storage_live_binding(block, node, span);

View File

@ -269,6 +269,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
res
}
pub fn in_opt_scope<F, R>(&mut self,
opt_extent: Option<CodeExtent>,
mut block: BasicBlock,
f: F)
-> BlockAnd<R>
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
{
debug!("in_opt_scope(opt_extent={:?}, block={:?})", opt_extent, block);
if let Some(extent) = opt_extent { self.push_scope(extent); }
let rv = unpack!(block = f(self));
if let Some(extent) = opt_extent {
unpack!(block = self.pop_scope(extent, block));
}
debug!("in_scope: exiting opt_extent={:?} block={:?}", opt_extent, block);
block.and(rv)
}
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
pub fn in_scope<F, R>(&mut self,

View File

@ -22,9 +22,14 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
// We have to eagerly translate the "spine" of the statements
// in order to get the lexical scoping correctly.
let stmts = mirror_stmts(cx, self.id, &*self.stmts);
let opt_def_id = cx.tcx.hir.opt_local_def_id(self.id);
let opt_destruction_extent = opt_def_id.and_then(|def_id| {
cx.tcx.region_maps(def_id).opt_destruction_extent(self.id)
});
Block {
targeted_by_break: self.targeted_by_break,
extent: CodeExtent::Misc(self.id),
opt_destruction_extent: opt_destruction_extent,
span: self.span,
stmts: stmts,
expr: self.expr.to_ref(),
@ -37,7 +42,11 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
stmts: &'tcx [hir::Stmt])
-> Vec<StmtRef<'tcx>> {
let mut result = vec![];
let opt_def_id = cx.tcx.hir.opt_local_def_id(block_id);
for (index, stmt) in stmts.iter().enumerate() {
let opt_dxn_ext = opt_def_id.and_then(|def_id| {
cx.tcx.region_maps(def_id).opt_destruction_extent(stmt.node.id())
});
match stmt.node {
hir::StmtExpr(ref expr, id) |
hir::StmtSemi(ref expr, id) => {
@ -47,6 +56,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
scope: CodeExtent::Misc(id),
expr: expr.to_ref(),
},
opt_destruction_extent: opt_dxn_ext,
})))
}
hir::StmtDecl(ref decl, id) => {
@ -69,6 +79,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
pattern: pattern,
initializer: local.init.to_ref(),
},
opt_destruction_extent: opt_dxn_ext,
})));
}
}

View File

@ -33,6 +33,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt
pub struct Block<'tcx> {
pub targeted_by_break: bool,
pub extent: CodeExtent,
pub opt_destruction_extent: Option<CodeExtent>,
pub span: Span,
pub stmts: Vec<StmtRef<'tcx>>,
pub expr: Option<ExprRef<'tcx>>,
@ -47,6 +48,7 @@ pub enum StmtRef<'tcx> {
pub struct Stmt<'tcx> {
pub span: Span,
pub kind: StmtKind<'tcx>,
pub opt_destruction_extent: Option<CodeExtent>,
}
#[derive(Clone, Debug)]