// 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;
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 {
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
.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
}));
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
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();
-
- // start the first basic block and translate the body
- unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block));
-
- block.and((arg_decls, argument_scope_id))
- })
+ 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));
+ }
+
+ // 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);
+
+ 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> {
*/
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};
.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 });
}
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