From 374ea14412fbb35ca344b7d7cbe67405d63e0e42 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Feb 2017 11:16:14 +0200 Subject: [PATCH] rustc_mir: expose MIR building through ty::maps::Provider. --- src/librustc_driver/driver.rs | 5 +- src/librustc_mir/mir_map.rs | 158 ++++++++++++++++++++++------------ 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6dbdf55f1ca3..c1cfc0234e14 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -872,9 +872,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let index = stability::Index::new(&hir_map); - let local_providers = ty::maps::Providers::default(); - let mut extern_providers = ty::maps::Providers::default(); + let mut local_providers = ty::maps::Providers::default(); + mir::mir_map::provide(&mut local_providers); + let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); TyCtxt::create_and_enter(sess, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 913b0d5fb8ae..dedc55404496 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -17,6 +17,7 @@ //! - `#[rustc_mir(pretty="file.mir")]` use build; +use rustc::hir::def_id::DefId; use rustc::dep_graph::DepNode; use rustc::mir::Mir; use rustc::mir::transform::MirSource; @@ -24,9 +25,9 @@ use rustc::mir::visit::MutVisitor; use pretty; use hair::cx::Cx; -use rustc::infer::InferCtxt; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; @@ -34,6 +35,7 @@ use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; +use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -42,6 +44,103 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { }.as_deep_visitor()); } +pub fn provide(providers: &mut Providers) { + providers.mir = build_mir; +} + +fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) + -> &'tcx RefCell> { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let unsupported = || { + span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id); + }; + + // Figure out what primary body this item has. + let body_id = match tcx.hir.get(id) { + hir::map::NodeItem(item) => { + match item.node { + hir::ItemConst(_, body) | + hir::ItemStatic(_, _, body) | + hir::ItemFn(.., body) => body, + _ => unsupported() + } + } + hir::map::NodeTraitItem(item) => { + match item.node { + hir::TraitItemKind::Const(_, Some(body)) | + hir::TraitItemKind::Method(_, + hir::TraitMethod::Provided(body)) => body, + _ => unsupported() + } + } + hir::map::NodeImplItem(item) => { + match item.node { + hir::ImplItemKind::Const(_, body) | + hir::ImplItemKind::Method(_, body) => body, + _ => unsupported() + } + } + hir::map::NodeExpr(expr) => { + // FIXME(eddyb) Closures should have separate + // function definition IDs and expression IDs. + // Type-checking should not let closures get + // this far in a constant position. + // Assume that everything other than closures + // is a constant "initializer" expression. + match expr.node { + hir::ExprClosure(_, _, body, _) => body, + _ => hir::BodyId { node_id: expr.id } + } + } + _ => unsupported() + }; + + let src = MirSource::from_node(tcx, id); + tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| { + let cx = Cx::new(&infcx, src); + let mut mir = if let MirSource::Fn(id) = src { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); + + let ty = tcx.item_type(tcx.hir.local_def_id(id)); + let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty { + (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None))) + } else { + (ty.fn_abi(), None) + }; + + let body = tcx.hir.body(body_id); + let explicit_arguments = + body.arguments + .iter() + .enumerate() + .map(|(index, arg)| { + (fn_sig.inputs()[index], Some(&*arg.pat)) + }); + + let arguments = implicit_argument.into_iter().chain(explicit_arguments); + build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body) + } else { + build::construct_const(cx, body_id) + }; + + // Convert the Mir to global types. + let mut globalizer = GlobalizeMir { + tcx: tcx, + span: mir.span + }; + globalizer.visit_mir(&mut mir); + let mir = unsafe { + mem::transmute::>(mir) + }; + + pretty::dump_mir(tcx, "mir_map", &0, src, &mir); + + tcx.alloc_mir(mir) + }) +} + /// A pass to lift all the types and substitutions in a Mir /// to the global tcx. Sadly, we don't have a "folder" that /// can change 'tcx so we have to transmute afterwards. @@ -79,68 +178,13 @@ struct BuildMir<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } -fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - body_id: hir::BodyId) - -> (Mir<'tcx>, MirSource) { - let tcx = infcx.tcx.global_tcx(); - - let item_id = tcx.hir.body_owner(body_id); - let src = MirSource::from_node(tcx, item_id); - let cx = Cx::new(infcx, src); - if let MirSource::Fn(id) = src { - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); - - let ty = tcx.item_type(tcx.hir.local_def_id(id)); - let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty { - (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None))) - } else { - (ty.fn_abi(), None) - }; - - let body = tcx.hir.body(body_id); - let explicit_arguments = - body.arguments - .iter() - .enumerate() - .map(|(index, arg)| { - (fn_sig.inputs()[index], Some(&*arg.pat)) - }); - - let arguments = implicit_argument.into_iter().chain(explicit_arguments); - (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src) - } else { - (build::construct_const(cx, body_id), src) - } -} - impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_nested_body(&mut self, body_id: hir::BodyId) { - self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| { - let (mut mir, src) = build(&infcx, body_id); - - // Convert the Mir to global types. - let tcx = infcx.tcx.global_tcx(); - let mut globalizer = GlobalizeMir { - tcx: tcx, - span: mir.span - }; - globalizer.visit_mir(&mut mir); - let mir = unsafe { - mem::transmute::>(mir) - }; - - pretty::dump_mir(tcx, "mir_map", &0, src, &mir); - - let mir = tcx.alloc_mir(mir); - let def_id = tcx.hir.local_def_id(src.item_id()); - tcx.maps.mir.borrow_mut().insert(def_id, mir); - }); + self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id)); let body = self.tcx.hir.body(body_id); self.visit_body(body);