]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/mir_map.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / mir_map.rs
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.
4 //
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.
10
11 //! An experimental pass that scources for `#[rustc_mir]` attributes,
12 //! builds the resulting MIR, and dumps it out into a file for inspection.
13 //!
14 //! The attribute formats that are currently accepted are:
15 //!
16 //! - `#[rustc_mir(graphviz="file.gv")]`
17 //! - `#[rustc_mir(pretty="file.mir")]`
18
19 extern crate syntax;
20
21 use build;
22 use rustc::dep_graph::DepNode;
23 use rustc::mir::repr::Mir;
24 use pretty;
25 use hair::cx::Cx;
26
27 use rustc::mir::mir_map::MirMap;
28 use rustc::infer;
29 use rustc::traits::ProjectionMode;
30 use rustc::ty::{self, Ty, TyCtxt};
31 use rustc::util::common::ErrorReported;
32 use rustc::util::nodemap::NodeMap;
33 use rustc::hir;
34 use rustc::hir::intravisit::{self, Visitor};
35 use syntax::abi::Abi;
36 use syntax::ast;
37 use syntax::attr::AttrMetaMethods;
38 use syntax::codemap::Span;
39
40 pub fn build_mir_for_crate<'tcx>(tcx: &TyCtxt<'tcx>) -> MirMap<'tcx> {
41 let mut map = MirMap {
42 map: NodeMap(),
43 };
44 {
45 let mut dump = OuterDump {
46 tcx: tcx,
47 map: &mut map,
48 };
49 tcx.visit_all_items_in_krate(DepNode::MirMapConstruction, &mut dump);
50 }
51 map
52 }
53
54 ///////////////////////////////////////////////////////////////////////////
55 // OuterDump -- walks a crate, looking for fn items and methods to build MIR from
56
57 struct OuterDump<'a, 'tcx: 'a> {
58 tcx: &'a TyCtxt<'tcx>,
59 map: &'a mut MirMap<'tcx>,
60 }
61
62 impl<'a, 'tcx> OuterDump<'a, 'tcx> {
63 fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
64 where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>)
65 {
66 let mut closure_dump = InnerDump {
67 tcx: self.tcx,
68 attr: None,
69 map: &mut *self.map,
70 };
71 for attr in attributes {
72 if attr.check_name("rustc_mir") {
73 closure_dump.attr = Some(attr);
74 }
75 }
76 walk_op(&mut closure_dump);
77 }
78 }
79
80
81 impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> {
82 fn visit_item(&mut self, item: &'tcx hir::Item) {
83 self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item));
84 intravisit::walk_item(self, item);
85 }
86
87 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
88 match trait_item.node {
89 hir::MethodTraitItem(_, Some(_)) => {
90 self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item));
91 }
92 hir::MethodTraitItem(_, None) |
93 hir::ConstTraitItem(..) |
94 hir::TypeTraitItem(..) => {}
95 }
96 intravisit::walk_trait_item(self, trait_item);
97 }
98
99 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
100 match impl_item.node {
101 hir::ImplItemKind::Method(..) => {
102 self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item));
103 }
104 hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {}
105 }
106 intravisit::walk_impl_item(self, impl_item);
107 }
108 }
109
110 ///////////////////////////////////////////////////////////////////////////
111 // InnerDump -- dumps MIR for a single fn and its contained closures
112
113 struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
114 tcx: &'a TyCtxt<'tcx>,
115 map: &'m mut MirMap<'tcx>,
116 attr: Option<&'a ast::Attribute>,
117 }
118
119 impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
120 fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
121 // ignore methods; the outer dump will call us for them independently
122 }
123
124 fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
125 // ignore methods; the outer dump will call us for them independently
126 }
127
128 fn visit_fn(&mut self,
129 fk: intravisit::FnKind<'tcx>,
130 decl: &'tcx hir::FnDecl,
131 body: &'tcx hir::Block,
132 span: Span,
133 id: ast::NodeId) {
134 let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk {
135 vec![closure_self_ty(&self.tcx, id, body.id)]
136 } else {
137 vec![]
138 };
139
140 let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
141 let infcx = infer::new_infer_ctxt(self.tcx,
142 &self.tcx.tables,
143 Some(param_env),
144 ProjectionMode::AnyFinal);
145
146 match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
147 Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
148 Err(ErrorReported) => {}
149 }
150
151 intravisit::walk_fn(self, fk, decl, body, span);
152 }
153 }
154
155 fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
156 implicit_arg_tys: Vec<Ty<'tcx>>,
157 fn_id: ast::NodeId,
158 span: Span,
159 decl: &'tcx hir::FnDecl,
160 body: &'tcx hir::Block)
161 -> Result<Mir<'tcx>, ErrorReported> {
162 // fetch the fully liberated fn signature (that is, all bound
163 // types/lifetimes replaced)
164 let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
165 Some(f) => f.clone(),
166 None => {
167 span_bug!(span, "no liberated fn sig for {:?}", fn_id);
168 }
169 };
170
171 let arguments =
172 decl.inputs
173 .iter()
174 .enumerate()
175 .map(|(index, arg)| {
176 (fn_sig.inputs[index], &*arg.pat)
177 })
178 .collect();
179
180 let (mut mir, scope_auxiliary) =
181 build::construct(cx,
182 span,
183 fn_id,
184 body.id,
185 implicit_arg_tys,
186 arguments,
187 fn_sig.output,
188 body);
189
190 match cx.tcx().node_id_to_type(fn_id).sty {
191 ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
192 // RustCall pseudo-ABI untuples the last argument.
193 if let Some(arg_decl) = mir.arg_decls.last_mut() {
194 arg_decl.spread = true;
195 }
196 }
197 _ => {}
198 }
199
200 pretty::dump_mir(cx.tcx(),
201 "mir_map",
202 &0,
203 fn_id,
204 &mir,
205 Some(&scope_auxiliary));
206
207 Ok(mir)
208 }
209
210 fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
211 closure_expr_id: ast::NodeId,
212 body_id: ast::NodeId)
213 -> Ty<'tcx> {
214 let closure_ty = tcx.node_id_to_type(closure_expr_id);
215
216 // We're just hard-coding the idea that the signature will be
217 // &self or &mut self and hence will have a bound region with
218 // number 0, hokey.
219 let region = ty::Region::ReFree(ty::FreeRegion {
220 scope: tcx.region_maps.item_extent(body_id),
221 bound_region: ty::BoundRegion::BrAnon(0),
222 });
223 let region = tcx.mk_region(region);
224
225 match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
226 ty::ClosureKind::Fn =>
227 tcx.mk_ref(region,
228 ty::TypeAndMut { ty: closure_ty,
229 mutbl: hir::MutImmutable }),
230 ty::ClosureKind::FnMut =>
231 tcx.mk_ref(region,
232 ty::TypeAndMut { ty: closure_ty,
233 mutbl: hir::MutMutable }),
234 ty::ClosureKind::FnOnce =>
235 closure_ty
236 }
237 }