introduce "call-site-scope" as the outermost scope

also, when exiting a scope, assign the final goto terminator with the
target scope's id
This commit is contained in:
Niko Matsakis 2016-03-23 12:26:37 -04:00
parent 1c0fa34310
commit a276e755e7
4 changed files with 82 additions and 55 deletions

View File

@ -261,7 +261,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
block
}
};
let extent = this.extent_of_outermost_scope();
let extent = this.extent_of_return_scope();
this.exit_scope(expr_span, extent, block, END_BLOCK);
this.cfg.start_new_block().unit()
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
use hair::cx::Cx;
use rustc::middle::region::CodeExtent;
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::middle::ty::{FnOutput, Ty};
use rustc::mir::repr::*;
use rustc_data_structures::fnv::FnvHashMap;
@ -153,12 +153,14 @@ macro_rules! unpack {
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
span: Span,
fn_id: ast::NodeId,
body_id: ast::NodeId,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_extent: CodeExtent,
return_ty: FnOutput<'tcx>,
ast_block: &'tcx hir::Block)
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
let tcx = hir.tcx();
let cfg = CFG { basic_blocks: vec![] };
let mut builder = Builder {
@ -178,18 +180,32 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
let mut block = START_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, arg_scope_id, span,
TerminatorKind::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, arg_scope_id, span,
TerminatorKind::Return);
let mut arg_decls = None; // assigned to `Some` in closures below
let call_site_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| {
let mut block = START_BLOCK;
let arg_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
unpack!(block = builder.in_scope(arg_extent, block, |builder, arg_scope_id| {
arg_decls = Some(unpack!(block = builder.args_and_body(block,
implicit_arguments,
explicit_arguments,
arg_scope_id,
ast_block)));
block.unit()
}));
builder.cfg.terminate(block, call_site_scope_id, span,
TerminatorKind::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, call_site_scope_id, span,
TerminatorKind::Return);
END_BLOCK.unit()
});
assert!(
builder.cfg.basic_blocks
@ -197,8 +213,8 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
.enumerate()
.all(|(index, block)| {
if block.terminator.is_none() {
panic!("no terminator on block {:?} in {:?}",
index, argument_extent)
panic!("no terminator on block {:?} in fn {:?}",
index, fn_id)
}
true
}));
@ -208,7 +224,7 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
basic_blocks: builder.cfg.basic_blocks,
scopes: builder.scope_datas,
var_decls: builder.var_decls,
arg_decls: arg_decls,
arg_decls: arg_decls.take().expect("args never built?"),
temp_decls: builder.temp_decls,
return_ty: return_ty,
span: span
@ -222,39 +238,40 @@ impl<'a,'tcx> Builder<'a,'tcx> {
mut block: BasicBlock,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_extent: CodeExtent,
argument_scope_id: ScopeId,
ast_block: &'tcx hir::Block)
-> BlockAnd<(Vec<ArgDecl<'tcx>>, ScopeId)>
-> BlockAnd<Vec<ArgDecl<'tcx>>>
{
self.in_scope(argument_extent, block, |this, argument_scope_id| {
// to start, translate the argument patterns and collect the argument types.
let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
// to start, translate the argument patterns and collect the argument types.
let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
let arg_decls =
implicits
.chain(explicits)
.enumerate()
.map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(index as u32);
if let Some(pattern) = pattern {
let pattern = this.hir.irrefutable_pat(pattern);
unpack!(block = this.lvalue_into_pattern(block,
argument_scope_id,
pattern,
&lvalue));
}
// Make sure we drop (parts of) the argument even when not matched on.
this.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty);
ArgDecl { ty: ty, spread: false }
})
.collect();
implicits
.chain(explicits)
.enumerate()
.map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(index as u32);
if let Some(pattern) = pattern {
let pattern = self.hir.irrefutable_pat(pattern);
unpack!(block = self.lvalue_into_pattern(block,
argument_scope_id,
pattern,
&lvalue));
}
// start the first basic block and translate the body
unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block));
// Make sure we drop (parts of) the argument even when not matched on.
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty);
block.and((arg_decls, argument_scope_id))
})
ArgDecl { ty: ty, spread: false }
})
.collect();
// start the first basic block and translate the body
unpack!(block = self.ast_block(&Lvalue::ReturnPointer, block, ast_block));
block.and(arg_decls)
}
fn get_unit_temp(&mut self) -> Lvalue<'tcx> {

View File

@ -87,7 +87,7 @@ should go to.
*/
use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary};
use rustc::middle::region::CodeExtent;
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::middle::lang_items;
use rustc::middle::subst::{Substs, Subst, VecPerParamSpace};
use rustc::middle::ty::{self, Ty, TyCtxt};
@ -326,9 +326,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
.push(self.cfg.current_location(block));
}
let scope_id = self.innermost_scope_id();
assert!(scope_count < self.scopes.len(),
"should never use `exit_scope` to pop *ALL* scopes");
let scope = self.scopes.iter().rev().skip(scope_count)
.next()
.unwrap();
self.cfg.terminate(block,
scope_id,
scope.id,
span,
TerminatorKind::Goto { target: target });
}
@ -365,8 +369,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
self.scopes.last().map(|scope| scope.extent).unwrap()
}
pub fn extent_of_outermost_scope(&self) -> CodeExtent {
self.scopes.first().map(|scope| scope.extent).unwrap()
/// Returns the extent of the scope which should be exited by a
/// return.
pub fn extent_of_return_scope(&self) -> CodeExtent {
// The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
// We want `scopes[1]`, which is the `ParameterScope`.
assert!(self.scopes.len() >= 2);
assert!(match self.hir.tcx().region_maps.code_extent_data(self.scopes[1].extent) {
CodeExtentData::ParameterScope { .. } => true,
_ => false,
});
self.scopes[1].extent
}
// Scheduling drops

View File

@ -27,7 +27,6 @@ use hair::cx::Cx;
use rustc::mir::mir_map::MirMap;
use rustc::middle::infer;
use rustc::middle::region::CodeExtentData;
use rustc::middle::traits::ProjectionMode;
use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::util::common::ErrorReported;
@ -180,15 +179,13 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
})
.collect();
let parameter_scope =
cx.tcx().region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
let (mut mir, scope_auxiliary) =
build::construct(cx,
span,
fn_id,
body.id,
implicit_arg_tys,
arguments,
parameter_scope,
fn_sig.output,
body);