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:
parent
1c0fa34310
commit
a276e755e7
@ -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()
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user