diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2016-04-15 17:11:24 +0300 |
|---|---|---|
| committer | Eduard Burtescu <edy.burt@gmail.com> | 2016-05-07 07:14:54 +0300 |
| commit | cde2f5f11639edb2f943b6caa5f3b930c0c4f214 (patch) | |
| tree | 4418cb00a2f3ec654be13b58aa63c0e6a6b9af11 | |
| parent | bbc41aa9a674b80c4423ca6196fb334fd4d17776 (diff) | |
| download | rust-cde2f5f11639edb2f943b6caa5f3b930c0c4f214.tar.gz rust-cde2f5f11639edb2f943b6caa5f3b930c0c4f214.zip | |
mir: factor out the parts of MIR building which are not fn-specific.
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 228 | ||||
| -rw-r--r-- | src/librustc_mir/mir_map.rs | 110 |
2 files changed, 157 insertions, 181 deletions
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1ed5fabf274..004a2aada6a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -10,12 +10,13 @@ use hair::cx::Cx; use rustc::middle::region::{CodeExtent, CodeExtentData}; -use rustc::ty::{self, FnOutput, Ty}; +use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::hir; use rustc::hir::pat_util::pat_is_binding; use std::ops::{Index, IndexMut}; +use syntax::abi::Abi; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::keywords; @@ -159,53 +160,31 @@ macro_rules! unpack { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -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)>, - return_ty: FnOutput<'tcx>, - ast_block: &'tcx hir::Block) - -> (Mir<'tcx>, ScopeAuxiliaryVec) { +pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a,'tcx>, + fn_id: ast::NodeId, + arguments: A, + return_ty: ty::FnOutput<'tcx>, + ast_block: &'tcx hir::Block) + -> (Mir<'tcx>, ScopeAuxiliaryVec) + where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)> +{ let tcx = hir.tcx(); - let cfg = CFG { basic_blocks: vec![] }; - - let mut builder = Builder { - hir: hir, - cfg: cfg, - fn_span: span, - scopes: vec![], - scope_datas: vec![], - scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] }, - loop_scopes: vec![], - temp_decls: vec![], - var_decls: vec![], - var_indices: FnvHashMap(), - unit_temp: None, - cached_resume_block: None, - cached_return_block: None - }; - - assert_eq!(builder.cfg.start_new_block(), START_BLOCK); + let span = tcx.map.span(fn_id); + let mut builder = Builder::new(hir, span); - let mut arg_decls = None; // assigned to `Some` in closures below + let body_id = ast_block.id; 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, - return_ty, - implicit_arguments, - explicit_arguments, - arg_scope_id, - ast_block))); - block.unit() + let arg_extent = + tcx.region_maps.lookup_code_extent( + CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id }); + let mut block = START_BLOCK; + let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, + |builder, call_site_scope_id| { + let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, + |builder, arg_scope_id| { + builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block) })); let return_block = builder.return_block(); @@ -213,20 +192,19 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, TerminatorKind::Goto { target: return_block }); builder.cfg.terminate(return_block, call_site_scope_id, span, TerminatorKind::Return); - return_block.unit() - }); - - assert!( - builder.cfg.basic_blocks - .iter() - .enumerate() - .all(|(index, block)| { - if block.terminator.is_none() { - bug!("no terminator on block {:?} in fn {:?}", - index, fn_id) - } - true - })); + return_block.and(arg_decls) + })); + assert_eq!(block, builder.return_block()); + + match tcx.node_id_to_type(fn_id).sty { + ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { + // RustCall pseudo-ABI untuples the last argument. + if let Some(arg_decl) = arg_decls.last_mut() { + arg_decl.spread = true; + } + } + _ => {} + } // Gather the upvars of a closure, if any. let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { @@ -251,72 +229,98 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, }).collect() }); - ( - Mir { - basic_blocks: builder.cfg.basic_blocks, - scopes: builder.scope_datas, - var_decls: builder.var_decls, - arg_decls: arg_decls.take().expect("args never built?"), - temp_decls: builder.temp_decls, - upvar_decls: upvar_decls, - return_ty: return_ty, - span: span - }, - builder.scope_auxiliary, - ) + builder.finish(upvar_decls, arg_decls, return_ty) } impl<'a,'tcx> Builder<'a,'tcx> { - fn args_and_body(&mut self, - mut block: BasicBlock, - return_ty: FnOutput<'tcx>, - implicit_arguments: Vec<Ty<'tcx>>, - explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>, - argument_scope_id: ScopeId, - ast_block: &'tcx hir::Block) - -> BlockAnd<Vec<ArgDecl<'tcx>>> + fn new(hir: Cx<'a, 'tcx>, span: Span) -> Builder<'a, 'tcx> { + let mut builder = Builder { + hir: hir, + cfg: CFG { basic_blocks: vec![] }, + fn_span: span, + scopes: vec![], + scope_datas: vec![], + scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] }, + loop_scopes: vec![], + temp_decls: vec![], + var_decls: vec![], + var_indices: FnvHashMap(), + unit_temp: None, + cached_resume_block: None, + cached_return_block: None + }; + + assert_eq!(builder.cfg.start_new_block(), START_BLOCK); + + builder + } + + fn finish(self, + upvar_decls: Vec<UpvarDecl>, + arg_decls: Vec<ArgDecl<'tcx>>, + return_ty: ty::FnOutput<'tcx>) + -> (Mir<'tcx>, ScopeAuxiliaryVec) { + for (index, block) in self.cfg.basic_blocks.iter().enumerate() { + if block.terminator.is_none() { + span_bug!(self.fn_span, "no terminator on block {:?}", index); + } + } + + (Mir { + basic_blocks: self.cfg.basic_blocks, + scopes: self.scope_datas, + var_decls: self.var_decls, + arg_decls: arg_decls, + temp_decls: self.temp_decls, + upvar_decls: upvar_decls, + return_ty: return_ty, + span: self.fn_span + }, self.scope_auxiliary) + } + + fn args_and_body<A>(&mut self, + mut block: BasicBlock, + return_ty: ty::FnOutput<'tcx>, + arguments: A, + argument_scope_id: ScopeId, + ast_block: &'tcx hir::Block) + -> BlockAnd<Vec<ArgDecl<'tcx>>> + where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::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 = self.hir.irrefutable_pat(pattern); - unpack!(block = self.lvalue_into_pattern(block, - argument_scope_id, - pattern, - &lvalue)); - } + let arg_decls = arguments.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); - - let mut name = keywords::Invalid.name(); - if let Some(pat) = pattern { - if let hir::PatKind::Ident(_, ref ident, _) = pat.node { - if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) { - name = ident.node.name; - } + // 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); + + let mut name = keywords::Invalid.name(); + if let Some(pat) = pattern { + if let hir::PatKind::Ident(_, ref ident, _) = pat.node { + if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) { + name = ident.node.name; } } + } - ArgDecl { - ty: ty, - spread: false, - debug_name: name - } - }) - .collect(); + ArgDecl { + ty: ty, + spread: false, + debug_name: name + } + }).collect(); // FIXME(#32959): temporary hack for the issue at hand - let return_is_unit = if let FnOutput::FnConverging(t) = return_ty { + let return_is_unit = if let ty::FnConverging(t) = return_ty { t.is_nil() } else { false diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 97daa64994d..dad1f157288 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -28,11 +28,9 @@ use rustc::mir::mir_map::MirMap; use rustc::infer; use rustc::traits::ProjectionMode; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; -use syntax::abi::Abi; use syntax::ast; use syntax::codemap::Span; @@ -58,6 +56,24 @@ struct BuildMir<'a, 'tcx: 'a> { map: &'a mut MirMap<'tcx>, } +impl<'a, 'tcx> BuildMir<'a, 'tcx> { + fn build<F>(&mut self, id: ast::NodeId, f: F) + where F: for<'b> FnOnce(Cx<'b, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec) + { + let param_env = ty::ParameterEnvironment::for_item(self.tcx, id); + let infcx = infer::new_infer_ctxt(self.tcx, + &self.tcx.tables, + Some(param_env), + ProjectionMode::AnyFinal); + + let (mir, scope_auxiliary) = f(Cx::new(&infcx)); + + pretty::dump_mir(self.tcx, "mir_map", &0, id, &mir, Some(&scope_auxiliary)); + + assert!(self.map.map.insert(id, mir).is_none()) + } +} + impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'tcx>, @@ -65,82 +81,38 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { body: &'tcx hir::Block, span: Span, id: ast::NodeId) { - let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk { - vec![closure_self_ty(&self.tcx, id, body.id)] + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) { + Some(f) => f.clone(), + None => { + span_bug!(span, "no liberated fn sig for {:?}", id); + } + }; + + let implicit_argument = if let intravisit::FnKind::Closure(..) = fk { + Some((closure_self_ty(&self.tcx, id, body.id), None)) } else { - vec![] + None }; - let param_env = ty::ParameterEnvironment::for_item(self.tcx, id); - let infcx = infer::new_infer_ctxt(self.tcx, - &self.tcx.tables, - Some(param_env), - ProjectionMode::AnyFinal); + let explicit_arguments = + decl.inputs + .iter() + .enumerate() + .map(|(index, arg)| { + (fn_sig.inputs[index], Some(&*arg.pat)) + }); - match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) { - Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()), - Err(ErrorReported) => {} - } + self.build(id, |cx| { + let arguments = implicit_argument.into_iter().chain(explicit_arguments); + build::construct_fn(cx, id, arguments, fn_sig.output, body) + }); intravisit::walk_fn(self, fk, decl, body, span); } } -fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, - implicit_arg_tys: Vec<Ty<'tcx>>, - fn_id: ast::NodeId, - span: Span, - decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block) - -> Result<Mir<'tcx>, ErrorReported> { - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) { - Some(f) => f.clone(), - None => { - span_bug!(span, "no liberated fn sig for {:?}", fn_id); - } - }; - - let arguments = - decl.inputs - .iter() - .enumerate() - .map(|(index, arg)| { - (fn_sig.inputs[index], &*arg.pat) - }) - .collect(); - - let (mut mir, scope_auxiliary) = - build::construct(cx, - span, - fn_id, - body.id, - implicit_arg_tys, - arguments, - fn_sig.output, - body); - - match cx.tcx().node_id_to_type(fn_id).sty { - ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { - // RustCall pseudo-ABI untuples the last argument. - if let Some(arg_decl) = mir.arg_decls.last_mut() { - arg_decl.spread = true; - } - } - _ => {} - } - - pretty::dump_mir(cx.tcx(), - "mir_map", - &0, - fn_id, - &mir, - Some(&scope_auxiliary)); - - Ok(mir) -} - fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>, closure_expr_id: ast::NodeId, body_id: ast::NodeId) |
