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")]`
21 extern crate rustc_front;
30 use self::rustc::middle::infer;
31 use self::rustc::middle::region::CodeExtentData;
32 use self::rustc::middle::ty::{self, Ty};
33 use self::rustc::util::common::ErrorReported;
34 use self::rustc::util::nodemap::NodeMap;
35 use self::rustc_front::hir;
36 use self::rustc_front::intravisit::{self, Visitor};
37 use self::syntax::ast;
38 use self::syntax::attr::AttrMetaMethods;
39 use self::syntax::codemap::Span;
41 pub type MirMap<'tcx> = NodeMap<Mir<'tcx>>;
43 pub fn build_mir_for_crate<'tcx>(tcx: &ty::ctxt<'tcx>) -> MirMap<'tcx> {
44 let mut map = NodeMap();
46 let mut dump = OuterDump {
50 tcx.map.krate().visit_all_items(&mut dump);
55 ///////////////////////////////////////////////////////////////////////////
56 // OuterDump -- walks a crate, looking for fn items and methods to build MIR from
58 struct OuterDump<'a, 'tcx: 'a> {
59 tcx: &'a ty::ctxt<'tcx>,
60 map: &'a mut MirMap<'tcx>,
63 impl<'a, 'tcx> OuterDump<'a, 'tcx> {
64 fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
65 where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>)
67 let mut closure_dump = InnerDump {
72 for attr in attributes {
73 if attr.check_name("rustc_mir") {
74 closure_dump.attr = Some(attr);
77 walk_op(&mut closure_dump);
82 impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> {
83 fn visit_item(&mut self, item: &'tcx hir::Item) {
84 self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item));
85 intravisit::walk_item(self, item);
88 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
89 match trait_item.node {
90 hir::MethodTraitItem(_, Some(_)) => {
91 self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item));
93 hir::MethodTraitItem(_, None) |
94 hir::ConstTraitItem(..) |
95 hir::TypeTraitItem(..) => {}
97 intravisit::walk_trait_item(self, trait_item);
100 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
101 match impl_item.node {
102 hir::ImplItemKind::Method(..) => {
103 self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item));
105 hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {}
107 intravisit::walk_impl_item(self, impl_item);
111 ///////////////////////////////////////////////////////////////////////////
112 // InnerDump -- dumps MIR for a single fn and its contained closures
114 struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
115 tcx: &'a ty::ctxt<'tcx>,
116 map: &'m mut MirMap<'tcx>,
117 attr: Option<&'a ast::Attribute>,
120 impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
121 fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
122 // ignore methods; the outer dump will call us for them independently
125 fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
126 // ignore methods; the outer dump will call us for them independently
129 fn visit_fn(&mut self,
130 fk: intravisit::FnKind<'tcx>,
131 decl: &'tcx hir::FnDecl,
132 body: &'tcx hir::Block,
135 let (prefix, implicit_arg_tys) = match fk {
136 intravisit::FnKind::Closure =>
137 (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
139 (format!(""), vec![]),
142 let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
144 let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), true);
146 match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
148 simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir);
150 let meta_item_list = self.attr
152 .flat_map(|a| a.meta_item_list())
153 .flat_map(|l| l.iter());
154 for item in meta_item_list {
155 if item.check_name("graphviz") {
156 match item.value_str() {
159 File::create(format!("{}{}", prefix, s))
160 .and_then(|ref mut output| dot::render(&mir, output))
164 self.tcx.sess.span_fatal(
166 &format!("Error writing graphviz \
167 results to `{}`: {}",
173 self.tcx.sess.span_err(
175 "graphviz attribute requires a path");
181 let previous = self.map.insert(id, mir);
182 assert!(previous.is_none());
184 Err(ErrorReported) => {}
187 intravisit::walk_fn(self, fk, decl, body, span);
191 fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
192 implicit_arg_tys: Vec<Ty<'tcx>>,
195 decl: &'tcx hir::FnDecl,
196 body: &'tcx hir::Block)
197 -> Result<Mir<'tcx>, ErrorReported> {
198 // fetch the fully liberated fn signature (that is, all bound
199 // types/lifetimes replaced)
200 let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
201 Some(f) => f.clone(),
203 cx.tcx().sess.span_bug(span,
204 &format!("no liberated fn sig for {:?}", fn_id));
212 .map(|(index, arg)| {
213 (fn_sig.inputs[index], &*arg.pat)
217 let parameter_scope =
218 cx.tcx().region_maps.lookup_code_extent(
219 CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
220 Ok(build::construct(cx,
229 fn closure_self_ty<'a, 'tcx>(tcx: &ty::ctxt<'tcx>,
230 closure_expr_id: ast::NodeId,
231 body_id: ast::NodeId)
233 let closure_ty = tcx.node_id_to_type(closure_expr_id);
235 // We're just hard-coding the idea that the signature will be
236 // &self or &mut self and hence will have a bound region with
238 let region = ty::Region::ReFree(ty::FreeRegion {
239 scope: tcx.region_maps.item_extent(body_id),
240 bound_region: ty::BoundRegion::BrAnon(0),
242 let region = tcx.mk_region(region);
244 match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
245 ty::ClosureKind::FnClosureKind =>
247 ty::TypeAndMut { ty: closure_ty,
248 mutbl: hir::MutImmutable }),
249 ty::ClosureKind::FnMutClosureKind =>
251 ty::TypeAndMut { ty: closure_ty,
252 mutbl: hir::MutMutable }),
253 ty::ClosureKind::FnOnceClosureKind =>