1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! An experimental pass that scources for `#[rustc_mir]` attributes,
12 //! builds the resulting MIR, and dumps it out into a file for inspection.
14 //! The attribute formats that are currently accepted are:
16 //! - `#[rustc_mir(graphviz="file.gv")]`
17 //! - `#[rustc_mir(pretty="file.mir")]`
20 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21 use rustc::dep_graph::DepNode;
23 use rustc::mir::transform::MirSource;
24 use rustc::mir::visit::MutVisitor;
29 use rustc::traits::Reveal;
30 use rustc::ty::{self, Ty, TyCtxt};
31 use rustc::ty::maps::Providers;
32 use rustc::ty::subst::Substs;
34 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
35 use rustc::util::nodemap::DefIdSet;
40 use std::cell::RefCell;
44 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
45 tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task);
47 fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
48 for &body_owner_def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
49 tcx.item_mir(body_owner_def_id);
54 pub fn provide(providers: &mut Providers) {
55 providers.mir = build_mir;
56 providers.mir_keys = mir_keys;
59 fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
61 assert_eq!(krate, LOCAL_CRATE);
63 let mut set = DefIdSet();
65 // All body-owners have MIR associated with them.
66 set.extend(tcx.body_owners());
68 // Additionally, tuple struct/variant constructors have MIR, but
69 // they don't have a BodyId, so we need to build them separately.
70 struct GatherCtors<'a, 'tcx: 'a> {
71 tcx: TyCtxt<'a, 'tcx, 'tcx>,
72 set: &'a mut DefIdSet,
74 impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
75 fn visit_variant_data(&mut self,
76 v: &'tcx hir::VariantData,
78 _: &'tcx hir::Generics,
81 if let hir::VariantData::Tuple(_, node_id) = *v {
82 self.set.insert(self.tcx.hir.local_def_id(node_id));
84 intravisit::walk_struct_def(self, v)
86 fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
87 NestedVisitorMap::None
90 tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
98 fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
99 -> &'tcx RefCell<Mir<'tcx>> {
100 let id = tcx.hir.as_local_node_id(def_id).unwrap();
101 let unsupported = || {
102 span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
105 // Figure out what primary body this item has.
106 let body_id = match tcx.hir.get(id) {
107 hir::map::NodeItem(item) => {
109 hir::ItemConst(_, body) |
110 hir::ItemStatic(_, _, body) |
111 hir::ItemFn(.., body) => body,
115 hir::map::NodeTraitItem(item) => {
117 hir::TraitItemKind::Const(_, Some(body)) |
118 hir::TraitItemKind::Method(_,
119 hir::TraitMethod::Provided(body)) => body,
123 hir::map::NodeImplItem(item) => {
125 hir::ImplItemKind::Const(_, body) |
126 hir::ImplItemKind::Method(_, body) => body,
130 hir::map::NodeExpr(expr) => {
131 // FIXME(eddyb) Closures should have separate
132 // function definition IDs and expression IDs.
133 // Type-checking should not let closures get
134 // this far in a constant position.
135 // Assume that everything other than closures
136 // is a constant "initializer" expression.
138 hir::ExprClosure(_, _, body, _) => body,
139 _ => hir::BodyId { node_id: expr.id }
142 hir::map::NodeVariant(variant) =>
143 return create_constructor_shim(tcx, id, &variant.node.data),
144 hir::map::NodeStructCtor(ctor) =>
145 return create_constructor_shim(tcx, id, ctor),
149 let src = MirSource::from_node(tcx, id);
150 tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
151 let cx = Cx::new(&infcx, src);
152 let mut mir = if cx.tables().tainted_by_errors {
153 build::construct_error(cx, body_id)
154 } else if let MirSource::Fn(id) = src {
155 // fetch the fully liberated fn signature (that is, all bound
156 // types/lifetimes replaced)
157 let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
159 let ty = tcx.type_of(tcx.hir.local_def_id(id));
160 let mut abi = fn_sig.abi;
161 let implicit_argument = if let ty::TyClosure(..) = ty.sty {
162 // HACK(eddyb) Avoid having RustCall on closures,
163 // as it adds unnecessary (and wrong) auto-tupling.
165 Some((closure_self_ty(tcx, id, body_id), None))
170 let body = tcx.hir.body(body_id);
171 let explicit_arguments =
175 .map(|(index, arg)| {
176 (fn_sig.inputs()[index], Some(&*arg.pat))
179 let arguments = implicit_argument.into_iter().chain(explicit_arguments);
180 build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
182 build::construct_const(cx, body_id)
185 // Convert the Mir to global types.
186 let mut globalizer = GlobalizeMir {
190 globalizer.visit_mir(&mut mir);
192 mem::transmute::<Mir, Mir<'tcx>>(mir)
195 mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
201 /// A pass to lift all the types and substitutions in a Mir
202 /// to the global tcx. Sadly, we don't have a "folder" that
203 /// can change 'tcx so we have to transmute afterwards.
204 struct GlobalizeMir<'a, 'gcx: 'a> {
205 tcx: TyCtxt<'a, 'gcx, 'gcx>,
209 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
210 fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
211 if let Some(lifted) = self.tcx.lift(ty) {
215 "found type `{:?}` with inference types/regions in MIR",
220 fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
221 if let Some(lifted) = self.tcx.lift(substs) {
225 "found substs `{:?}` with inference types/regions in MIR",
231 fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
232 ctor_id: ast::NodeId,
233 v: &'tcx hir::VariantData)
234 -> &'tcx RefCell<Mir<'tcx>>
236 let span = tcx.hir.span(ctor_id);
237 if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
238 let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
239 tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
241 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
243 // Convert the Mir to global types.
244 let tcx = infcx.tcx.global_tcx();
245 let mut globalizer = GlobalizeMir {
249 globalizer.visit_mir(&mut mir);
251 mem::transmute::<Mir, Mir<'tcx>>(mir)
254 mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
259 span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
263 ///////////////////////////////////////////////////////////////////////////
264 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
266 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
267 closure_expr_id: ast::NodeId,
268 body_id: hir::BodyId)
270 let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
272 let region = ty::ReFree(ty::FreeRegion {
273 scope: Some(tcx.item_extent(body_id.node_id)),
274 bound_region: ty::BoundRegion::BrEnv,
276 let region = tcx.mk_region(region);
278 match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
279 ty::ClosureKind::Fn =>
281 ty::TypeAndMut { ty: closure_ty,
282 mutbl: hir::MutImmutable }),
283 ty::ClosureKind::FnMut =>
285 ty::TypeAndMut { ty: closure_ty,
286 mutbl: hir::MutMutable }),
287 ty::ClosureKind::FnOnce =>