]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/mir_map.rs
New upstream version 1.16.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 use build;
20 use rustc::dep_graph::DepNode;
21 use rustc::mir::Mir;
22 use rustc::mir::transform::MirSource;
23 use rustc::mir::visit::MutVisitor;
24 use pretty;
25 use hair::cx::Cx;
26
27 use rustc::infer::InferCtxt;
28 use rustc::traits::Reveal;
29 use rustc::ty::{self, Ty, TyCtxt};
30 use rustc::ty::subst::Substs;
31 use rustc::hir;
32 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
33 use syntax::abi::Abi;
34 use syntax::ast;
35 use syntax_pos::Span;
36
37 use std::mem;
38
39 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
40 tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir {
41 tcx: tcx
42 }.as_deep_visitor());
43 }
44
45 /// A pass to lift all the types and substitutions in a Mir
46 /// to the global tcx. Sadly, we don't have a "folder" that
47 /// can change 'tcx so we have to transmute afterwards.
48 struct GlobalizeMir<'a, 'gcx: 'a> {
49 tcx: TyCtxt<'a, 'gcx, 'gcx>,
50 span: Span
51 }
52
53 impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
54 fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
55 if let Some(lifted) = self.tcx.lift(ty) {
56 *ty = lifted;
57 } else {
58 span_bug!(self.span,
59 "found type `{:?}` with inference types/regions in MIR",
60 ty);
61 }
62 }
63
64 fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
65 if let Some(lifted) = self.tcx.lift(substs) {
66 *substs = lifted;
67 } else {
68 span_bug!(self.span,
69 "found substs `{:?}` with inference types/regions in MIR",
70 substs);
71 }
72 }
73 }
74
75 ///////////////////////////////////////////////////////////////////////////
76 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
77
78 struct BuildMir<'a, 'tcx: 'a> {
79 tcx: TyCtxt<'a, 'tcx, 'tcx>
80 }
81
82 fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
83 body_id: hir::BodyId)
84 -> (Mir<'tcx>, MirSource) {
85 let tcx = infcx.tcx.global_tcx();
86
87 let item_id = tcx.hir.body_owner(body_id);
88 let src = MirSource::from_node(tcx, item_id);
89 let cx = Cx::new(infcx, src);
90 if let MirSource::Fn(id) = src {
91 // fetch the fully liberated fn signature (that is, all bound
92 // types/lifetimes replaced)
93 let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
94
95 let ty = tcx.item_type(tcx.hir.local_def_id(id));
96 let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
97 (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
98 } else {
99 (ty.fn_abi(), None)
100 };
101
102 let body = tcx.hir.body(body_id);
103 let explicit_arguments =
104 body.arguments
105 .iter()
106 .enumerate()
107 .map(|(index, arg)| {
108 (fn_sig.inputs()[index], Some(&*arg.pat))
109 });
110
111 let arguments = implicit_argument.into_iter().chain(explicit_arguments);
112 (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
113 } else {
114 (build::construct_const(cx, body_id), src)
115 }
116 }
117
118 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
119 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
120 NestedVisitorMap::None
121 }
122
123 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
124 self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
125 let (mut mir, src) = build(&infcx, body_id);
126
127 // Convert the Mir to global types.
128 let tcx = infcx.tcx.global_tcx();
129 let mut globalizer = GlobalizeMir {
130 tcx: tcx,
131 span: mir.span
132 };
133 globalizer.visit_mir(&mut mir);
134 let mir = unsafe {
135 mem::transmute::<Mir, Mir<'tcx>>(mir)
136 };
137
138 pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
139
140 let mir = tcx.alloc_mir(mir);
141 let def_id = tcx.hir.local_def_id(src.item_id());
142 assert!(tcx.mir_map.borrow_mut().insert(def_id, mir).is_none());
143 });
144
145 let body = self.tcx.hir.body(body_id);
146 self.visit_body(body);
147 }
148 }
149
150 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
151 closure_expr_id: ast::NodeId,
152 body_id: hir::BodyId)
153 -> Ty<'tcx> {
154 let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
155
156 // We're just hard-coding the idea that the signature will be
157 // &self or &mut self and hence will have a bound region with
158 // number 0, hokey.
159 let region = ty::Region::ReFree(ty::FreeRegion {
160 scope: tcx.region_maps.item_extent(body_id.node_id),
161 bound_region: ty::BoundRegion::BrAnon(0),
162 });
163 let region = tcx.mk_region(region);
164
165 match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
166 ty::ClosureKind::Fn =>
167 tcx.mk_ref(region,
168 ty::TypeAndMut { ty: closure_ty,
169 mutbl: hir::MutImmutable }),
170 ty::ClosureKind::FnMut =>
171 tcx.mk_ref(region,
172 ty::TypeAndMut { ty: closure_ty,
173 mutbl: hir::MutMutable }),
174 ty::ClosureKind::FnOnce =>
175 closure_ty
176 }
177 }