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::DefId;
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};
39 use std::cell::RefCell;
42 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
43 tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task);
45 fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
46 tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
47 tcx.item_mir(body_owner_def_id);
50 // Tuple struct/variant constructors don't have a BodyId, so we need
51 // to build them separately.
52 struct GatherCtors<'a, 'tcx: 'a> {
53 tcx: TyCtxt<'a, 'tcx, 'tcx>
55 impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
56 fn visit_variant_data(&mut self,
57 v: &'tcx hir::VariantData,
59 _: &'tcx hir::Generics,
62 if let hir::VariantData::Tuple(_, node_id) = *v {
63 self.tcx.item_mir(self.tcx.hir.local_def_id(node_id));
65 intravisit::walk_struct_def(self, v)
67 fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
68 NestedVisitorMap::None
71 tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
77 pub fn provide(providers: &mut Providers) {
78 providers.mir = build_mir;
81 fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
82 -> &'tcx RefCell<Mir<'tcx>> {
83 let id = tcx.hir.as_local_node_id(def_id).unwrap();
84 let unsupported = || {
85 span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
88 // Figure out what primary body this item has.
89 let body_id = match tcx.hir.get(id) {
90 hir::map::NodeItem(item) => {
92 hir::ItemConst(_, body) |
93 hir::ItemStatic(_, _, body) |
94 hir::ItemFn(.., body) => body,
98 hir::map::NodeTraitItem(item) => {
100 hir::TraitItemKind::Const(_, Some(body)) |
101 hir::TraitItemKind::Method(_,
102 hir::TraitMethod::Provided(body)) => body,
106 hir::map::NodeImplItem(item) => {
108 hir::ImplItemKind::Const(_, body) |
109 hir::ImplItemKind::Method(_, body) => body,
113 hir::map::NodeExpr(expr) => {
114 // FIXME(eddyb) Closures should have separate
115 // function definition IDs and expression IDs.
116 // Type-checking should not let closures get
117 // this far in a constant position.
118 // Assume that everything other than closures
119 // is a constant "initializer" expression.
121 hir::ExprClosure(_, _, body, _) => body,
122 _ => hir::BodyId { node_id: expr.id }
125 hir::map::NodeVariant(variant) =>
126 return create_constructor_shim(tcx, id, &variant.node.data),
127 hir::map::NodeStructCtor(ctor) =>
128 return create_constructor_shim(tcx, id, ctor),
132 let src = MirSource::from_node(tcx, id);
133 tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
134 let cx = Cx::new(&infcx, src);
135 let mut mir = if cx.tables().tainted_by_errors {
136 build::construct_error(cx, body_id)
137 } else if let MirSource::Fn(id) = src {
138 // fetch the fully liberated fn signature (that is, all bound
139 // types/lifetimes replaced)
140 let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
142 let ty = tcx.type_of(tcx.hir.local_def_id(id));
143 let mut abi = fn_sig.abi;
144 let implicit_argument = if let ty::TyClosure(..) = ty.sty {
145 // HACK(eddyb) Avoid having RustCall on closures,
146 // as it adds unnecessary (and wrong) auto-tupling.
148 Some((closure_self_ty(tcx, id, body_id), None))
153 let body = tcx.hir.body(body_id);
154 let explicit_arguments =
158 .map(|(index, arg)| {
159 (fn_sig.inputs()[index], Some(&*arg.pat))
162 let arguments = implicit_argument.into_iter().chain(explicit_arguments);
163 build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
165 build::construct_const(cx, body_id)
168 // Convert the Mir to global types.
169 let mut globalizer = GlobalizeMir {
173 globalizer.visit_mir(&mut mir);
175 mem::transmute::<Mir, Mir<'tcx>>(mir)
178 mir_util::dump_mir(tcx, "mir_map", &0, src, &mir);
184 /// A pass to lift all the types and substitutions in a Mir
185 /// to the global tcx. Sadly, we don't have a "folder" that
186 /// can change 'tcx so we have to transmute afterwards.
187 struct GlobalizeMir<'a, 'gcx: 'a> {
188 tcx: TyCtxt<'a, 'gcx, 'gcx>,
192 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
193 fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
194 if let Some(lifted) = self.tcx.lift(ty) {
198 "found type `{:?}` with inference types/regions in MIR",
203 fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
204 if let Some(lifted) = self.tcx.lift(substs) {
208 "found substs `{:?}` with inference types/regions in MIR",
214 fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
215 ctor_id: ast::NodeId,
216 v: &'tcx hir::VariantData)
217 -> &'tcx RefCell<Mir<'tcx>>
219 let span = tcx.hir.span(ctor_id);
220 if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
221 let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
222 tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
224 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
226 // Convert the Mir to global types.
227 let tcx = infcx.tcx.global_tcx();
228 let mut globalizer = GlobalizeMir {
232 globalizer.visit_mir(&mut mir);
234 mem::transmute::<Mir, Mir<'tcx>>(mir)
237 mir_util::dump_mir(tcx, "mir_map", &0, src, &mir);
242 span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
246 ///////////////////////////////////////////////////////////////////////////
247 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
249 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
250 closure_expr_id: ast::NodeId,
251 body_id: hir::BodyId)
253 let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
255 let region = ty::Region::ReFree(ty::FreeRegion {
256 scope: tcx.region_maps.item_extent(body_id.node_id),
257 bound_region: ty::BoundRegion::BrEnv,
259 let region = tcx.mk_region(region);
261 match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
262 ty::ClosureKind::Fn =>
264 ty::TypeAndMut { ty: closure_ty,
265 mutbl: hir::MutImmutable }),
266 ty::ClosureKind::FnMut =>
268 ty::TypeAndMut { ty: closure_ty,
269 mutbl: hir::MutMutable }),
270 ty::ClosureKind::FnOnce =>