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::dep_graph::DepNode;
21 use rustc::hir::def_id::DefId;
22 use rustc::mir::repr::Mir;
23 use rustc::mir::transform::MirSource;
24 use rustc::mir::visit::MutVisitor;
28 use rustc::mir::mir_map::MirMap;
29 use rustc::infer::InferCtxtBuilder;
30 use rustc::traits::Reveal;
31 use rustc::ty::{self, Ty, TyCtxt};
32 use rustc::ty::subst::Substs;
34 use rustc::hir::intravisit::{self, FnKind, Visitor};
40 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> {
41 let mut map = MirMap::new(tcx.dep_graph.clone());
43 let mut dump = BuildMir {
47 tcx.visit_all_items_in_krate(DepNode::Mir, &mut dump);
52 /// A pass to lift all the types and substitutions in a Mir
53 /// to the global tcx. Sadly, we don't have a "folder" that
54 /// can change 'tcx so we have to transmute afterwards.
55 struct GlobalizeMir<'a, 'gcx: 'a> {
56 tcx: TyCtxt<'a, 'gcx, 'gcx>,
60 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
61 fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
62 if let Some(lifted) = self.tcx.lift(ty) {
66 "found type `{:?}` with inference types/regions in MIR",
71 fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
72 if let Some(lifted) = self.tcx.lift(substs) {
76 "found substs `{:?}` with inference types/regions in MIR",
82 ///////////////////////////////////////////////////////////////////////////
83 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
85 struct BuildMir<'a, 'tcx: 'a> {
86 tcx: TyCtxt<'a, 'tcx, 'tcx>,
87 map: &'a mut MirMap<'tcx>,
90 /// Helper type of a temporary returned by BuildMir::cx(...).
91 /// Necessary because we can't write the following bound:
92 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
93 struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
96 infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>,
97 map: &'a mut MirMap<'gcx>,
100 impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
101 fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
102 let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
103 let def_id = self.tcx.map.local_def_id(src.item_id());
106 infcx: self.tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable),
113 impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
114 fn build<F>(&'tcx mut self, f: F)
115 where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
118 let mir = self.infcx.enter(|infcx| {
119 let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src));
121 // Convert the Mir to global types.
122 let mut globalizer = GlobalizeMir {
123 tcx: infcx.tcx.global_tcx(),
126 globalizer.visit_mir(&mut mir);
128 mem::transmute::<Mir, Mir<'gcx>>(mir)
131 pretty::dump_mir(infcx.tcx.global_tcx(), "mir_map", &0,
132 src, &mir, Some(&scope_auxiliary));
137 assert!(self.map.map.insert(self.def_id, mir).is_none())
141 impl<'a, 'gcx> BuildMir<'a, 'gcx> {
142 fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
143 // FIXME(eddyb) Closures should have separate
144 // function definition IDs and expression IDs.
145 // Type-checking should not let closures get
146 // this far in an integer constant position.
147 if let hir::ExprClosure(..) = expr.node {
150 self.cx(MirSource::Const(expr.id)).build(|cx| {
151 build::construct_const(cx, expr.id, expr)
156 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
157 // Const and static items.
158 fn visit_item(&mut self, item: &'tcx hir::Item) {
160 hir::ItemConst(_, ref expr) => {
161 self.cx(MirSource::Const(item.id)).build(|cx| {
162 build::construct_const(cx, item.id, expr)
165 hir::ItemStatic(_, m, ref expr) => {
166 self.cx(MirSource::Static(item.id, m)).build(|cx| {
167 build::construct_const(cx, item.id, expr)
172 intravisit::walk_item(self, item);
175 // Trait associated const defaults.
176 fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
177 if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
178 self.cx(MirSource::Const(item.id)).build(|cx| {
179 build::construct_const(cx, item.id, expr)
182 intravisit::walk_trait_item(self, item);
185 // Impl associated const.
186 fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
187 if let hir::ImplItemKind::Const(_, ref expr) = item.node {
188 self.cx(MirSource::Const(item.id)).build(|cx| {
189 build::construct_const(cx, item.id, expr)
192 intravisit::walk_impl_item(self, item);
195 // Repeat counts, i.e. [expr; constant].
196 fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
197 if let hir::ExprRepeat(_, ref count) = expr.node {
198 self.build_const_integer(count);
200 intravisit::walk_expr(self, expr);
203 // Array lengths, i.e. [T; constant].
204 fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
205 if let hir::TyFixedLengthVec(_, ref length) = ty.node {
206 self.build_const_integer(length);
208 intravisit::walk_ty(self, ty);
211 // Enum variant discriminant values.
212 fn visit_variant(&mut self, v: &'tcx hir::Variant,
213 g: &'tcx hir::Generics, item_id: ast::NodeId) {
214 if let Some(ref expr) = v.node.disr_expr {
215 self.build_const_integer(expr);
217 intravisit::walk_variant(self, v, g, item_id);
220 fn visit_fn(&mut self,
222 decl: &'tcx hir::FnDecl,
223 body: &'tcx hir::Block,
226 // fetch the fully liberated fn signature (that is, all bound
227 // types/lifetimes replaced)
228 let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) {
229 Some(f) => f.clone(),
231 span_bug!(span, "no liberated fn sig for {:?}", id);
235 let implicit_argument = if let FnKind::Closure(..) = fk {
236 Some((closure_self_ty(self.tcx, id, body.id), None))
241 let explicit_arguments =
245 .map(|(index, arg)| {
246 (fn_sig.inputs[index], Some(&*arg.pat))
249 let arguments = implicit_argument.into_iter().chain(explicit_arguments);
250 self.cx(MirSource::Fn(id)).build(|cx| {
251 build::construct_fn(cx, id, arguments, fn_sig.output, body)
254 intravisit::walk_fn(self, fk, decl, body, span, id);
258 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
259 closure_expr_id: ast::NodeId,
260 body_id: ast::NodeId)
262 let closure_ty = tcx.node_id_to_type(closure_expr_id);
264 // We're just hard-coding the idea that the signature will be
265 // &self or &mut self and hence will have a bound region with
267 let region = ty::Region::ReFree(ty::FreeRegion {
268 scope: tcx.region_maps.item_extent(body_id),
269 bound_region: ty::BoundRegion::BrAnon(0),
271 let region = tcx.mk_region(region);
273 match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
274 ty::ClosureKind::Fn =>
276 ty::TypeAndMut { ty: closure_ty,
277 mutbl: hir::MutImmutable }),
278 ty::ClosureKind::FnMut =>
280 ty::TypeAndMut { ty: closure_ty,
281 mutbl: hir::MutMutable }),
282 ty::ClosureKind::FnOnce =>