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
;
22 use rustc
::mir
::transform
::MirSource
;
23 use rustc
::mir
::visit
::MutVisitor
;
27 use rustc
::infer
::InferCtxt
;
28 use rustc
::traits
::Reveal
;
29 use rustc
::ty
::{self, Ty, TyCtxt}
;
30 use rustc
::ty
::subst
::Substs
;
32 use rustc
::hir
::intravisit
::{Visitor, NestedVisitorMap}
;
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
{
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
>,
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
) {
59 "found type `{:?}` with inference types/regions in MIR",
64 fn visit_substs(&mut self, substs
: &mut &'tcx Substs
<'tcx
>) {
65 if let Some(lifted
) = self.tcx
.lift(substs
) {
69 "found substs `{:?}` with inference types/regions in MIR",
75 ///////////////////////////////////////////////////////////////////////////
76 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
78 struct BuildMir
<'a
, 'tcx
: 'a
> {
79 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>
82 fn build
<'a
, 'gcx
, 'tcx
>(infcx
: &InferCtxt
<'a
, 'gcx
, 'tcx
>,
84 -> (Mir
<'tcx
>, MirSource
) {
85 let tcx
= infcx
.tcx
.global_tcx();
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();
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
)))
102 let body
= tcx
.hir
.body(body_id
);
103 let explicit_arguments
=
107 .map(|(index
, arg
)| {
108 (fn_sig
.inputs()[index
], Some(&*arg
.pat
))
111 let arguments
= implicit_argument
.into_iter().chain(explicit_arguments
);
112 (build
::construct_fn(cx
, id
, arguments
, abi
, fn_sig
.output(), body
), src
)
114 (build
::construct_const(cx
, body_id
), src
)
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
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
);
127 // Convert the Mir to global types.
128 let tcx
= infcx
.tcx
.global_tcx();
129 let mut globalizer
= GlobalizeMir
{
133 globalizer
.visit_mir(&mut mir
);
135 mem
::transmute
::<Mir
, Mir
<'tcx
>>(mir
)
138 pretty
::dump_mir(tcx
, "mir_map", &0, src
, &mir
);
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());
145 let body
= self.tcx
.hir
.body(body_id
);
146 self.visit_body(body
);
150 fn closure_self_ty
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
151 closure_expr_id
: ast
::NodeId
,
152 body_id
: hir
::BodyId
)
154 let closure_ty
= tcx
.body_tables(body_id
).node_id_to_type(closure_expr_id
);
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
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),
163 let region
= tcx
.mk_region(region
);
165 match tcx
.closure_kind(tcx
.hir
.local_def_id(closure_expr_id
)) {
166 ty
::ClosureKind
::Fn
=>
168 ty
::TypeAndMut
{ ty
: closure_ty
,
169 mutbl
: hir
::MutImmutable
}),
170 ty
::ClosureKind
::FnMut
=>
172 ty
::TypeAndMut
{ ty
: closure_ty
,
173 mutbl
: hir
::MutMutable
}),
174 ty
::ClosureKind
::FnOnce
=>