]>
git.proxmox.com Git - rustc.git/blob - 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.
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")]`
22 use rustc
::dep_graph
::DepNode
;
23 use rustc
::mir
::repr
::Mir
;
27 use rustc
::mir
::mir_map
::MirMap
;
29 use rustc
::traits
::ProjectionMode
;
30 use rustc
::ty
::{self, Ty, TyCtxt}
;
31 use rustc
::util
::common
::ErrorReported
;
32 use rustc
::util
::nodemap
::NodeMap
;
34 use rustc
::hir
::intravisit
::{self, Visitor}
;
37 use syntax
::attr
::AttrMetaMethods
;
38 use syntax
::codemap
::Span
;
40 pub fn build_mir_for_crate
<'tcx
>(tcx
: &TyCtxt
<'tcx
>) -> MirMap
<'tcx
> {
41 let mut map
= MirMap
{
45 let mut dump
= OuterDump
{
49 tcx
.visit_all_items_in_krate(DepNode
::MirMapConstruction
, &mut dump
);
54 ///////////////////////////////////////////////////////////////////////////
55 // OuterDump -- walks a crate, looking for fn items and methods to build MIR from
57 struct OuterDump
<'a
, 'tcx
: 'a
> {
58 tcx
: &'a TyCtxt
<'tcx
>,
59 map
: &'a
mut MirMap
<'tcx
>,
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
>)
66 let mut closure_dump
= InnerDump
{
71 for attr
in attributes
{
72 if attr
.check_name("rustc_mir") {
73 closure_dump
.attr
= Some(attr
);
76 walk_op(&mut closure_dump
);
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
);
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
));
92 hir
::MethodTraitItem(_
, None
) |
93 hir
::ConstTraitItem(..) |
94 hir
::TypeTraitItem(..) => {}
96 intravisit
::walk_trait_item(self, trait_item
);
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
));
104 hir
::ImplItemKind
::Const(..) | hir
::ImplItemKind
::Type(..) => {}
106 intravisit
::walk_impl_item(self, impl_item
);
110 ///////////////////////////////////////////////////////////////////////////
111 // InnerDump -- dumps MIR for a single fn and its contained closures
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
>,
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
124 fn visit_impl_item(&mut self, _
: &'tcx hir
::ImplItem
) {
125 // ignore methods; the outer dump will call us for them independently
128 fn visit_fn(&mut self,
129 fk
: intravisit
::FnKind
<'tcx
>,
130 decl
: &'tcx hir
::FnDecl
,
131 body
: &'tcx hir
::Block
,
134 let implicit_arg_tys
= if let intravisit
::FnKind
::Closure(..) = fk
{
135 vec
![closure_self_ty(&self.tcx
, id
, body
.id
)]
140 let param_env
= ty
::ParameterEnvironment
::for_item(self.tcx
, id
);
141 let infcx
= infer
::new_infer_ctxt(self.tcx
,
144 ProjectionMode
::AnyFinal
);
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
) => {}
151 intravisit
::walk_fn(self, fk
, decl
, body
, span
);
155 fn build_mir
<'a
,'tcx
:'a
>(cx
: Cx
<'a
,'tcx
>,
156 implicit_arg_tys
: Vec
<Ty
<'tcx
>>,
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(),
167 span_bug
!(span
, "no liberated fn sig for {:?}", fn_id
);
175 .map(|(index
, arg
)| {
176 (fn_sig
.inputs
[index
], &*arg
.pat
)
180 let (mut mir
, scope_auxiliary
) =
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;
200 pretty
::dump_mir(cx
.tcx(),
205 Some(&scope_auxiliary
));
210 fn closure_self_ty
<'a
, 'tcx
>(tcx
: &TyCtxt
<'tcx
>,
211 closure_expr_id
: ast
::NodeId
,
212 body_id
: ast
::NodeId
)
214 let closure_ty
= tcx
.node_id_to_type(closure_expr_id
);
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
219 let region
= ty
::Region
::ReFree(ty
::FreeRegion
{
220 scope
: tcx
.region_maps
.item_extent(body_id
),
221 bound_region
: ty
::BoundRegion
::BrAnon(0),
223 let region
= tcx
.mk_region(region
);
225 match tcx
.closure_kind(tcx
.map
.local_def_id(closure_expr_id
)) {
226 ty
::ClosureKind
::Fn
=>
228 ty
::TypeAndMut
{ ty
: closure_ty
,
229 mutbl
: hir
::MutImmutable
}),
230 ty
::ClosureKind
::FnMut
=>
232 ty
::TypeAndMut
{ ty
: closure_ty
,
233 mutbl
: hir
::MutMutable
}),
234 ty
::ClosureKind
::FnOnce
=>