rust/src/librustc_mir/mir_map.rs

243 lines
8.1 KiB
Rust
Raw Normal View History

2015-08-18 17:59:21 -04:00
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! An experimental pass that scources for `#[rustc_mir]` attributes,
//! builds the resulting MIR, and dumps it out into a file for inspection.
//!
//! The attribute formats that are currently accepted are:
//!
//! - `#[rustc_mir(graphviz="file.gv")]`
//! - `#[rustc_mir(pretty="file.mir")]`
extern crate syntax;
extern crate rustc_front;
use build::{self, MirAndScopeAuxiliary};
use rustc::dep_graph::DepNode;
use rustc::mir::repr::Mir;
use pretty;
use hair::cx::Cx;
2015-08-18 17:59:21 -04:00
use rustc::mir::mir_map::MirMap;
use rustc::middle::infer;
use rustc::middle::region::CodeExtentData;
use rustc::middle::traits::ProjectionMode;
2016-03-08 16:09:39 -08:00
use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
2016-03-08 14:24:44 +02:00
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
2016-02-29 23:36:51 +00:00
pub fn build_mir_for_crate<'tcx>(tcx: &TyCtxt<'tcx>) -> MirMap<'tcx> {
let mut map = MirMap {
map: NodeMap(),
};
{
let mut dump = OuterDump {
tcx: tcx,
map: &mut map,
};
tcx.visit_all_items_in_krate(DepNode::MirMapConstruction, &mut dump);
}
map
2015-08-18 17:59:21 -04:00
}
///////////////////////////////////////////////////////////////////////////
// OuterDump -- walks a crate, looking for fn items and methods to build MIR from
struct OuterDump<'a, 'tcx: 'a> {
2016-02-29 23:36:51 +00:00
tcx: &'a TyCtxt<'tcx>,
map: &'a mut MirMap<'tcx>,
2015-08-18 17:59:21 -04:00
}
impl<'a, 'tcx> OuterDump<'a, 'tcx> {
fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>)
2015-08-18 17:59:21 -04:00
{
let mut closure_dump = InnerDump {
tcx: self.tcx,
attr: None,
map: &mut *self.map,
};
2015-08-18 17:59:21 -04:00
for attr in attributes {
if attr.check_name("rustc_mir") {
closure_dump.attr = Some(attr);
2015-08-18 17:59:21 -04:00
}
}
walk_op(&mut closure_dump);
2015-08-18 17:59:21 -04:00
}
}
impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> {
2015-08-18 17:59:21 -04:00
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item));
intravisit::walk_item(self, item);
2015-08-18 17:59:21 -04:00
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
hir::MethodTraitItem(_, Some(_)) => {
self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item));
2015-08-18 17:59:21 -04:00
}
hir::MethodTraitItem(_, None) |
hir::ConstTraitItem(..) |
hir::TypeTraitItem(..) => {}
2015-08-18 17:59:21 -04:00
}
intravisit::walk_trait_item(self, trait_item);
2015-08-18 17:59:21 -04:00
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
2015-11-12 15:57:51 +01:00
hir::ImplItemKind::Method(..) => {
self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item));
}
2015-11-12 15:57:51 +01:00
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {}
}
intravisit::walk_impl_item(self, impl_item);
}
2015-08-18 17:59:21 -04:00
}
///////////////////////////////////////////////////////////////////////////
// InnerDump -- dumps MIR for a single fn and its contained closures
struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
2016-02-29 23:36:51 +00:00
tcx: &'a TyCtxt<'tcx>,
map: &'m mut MirMap<'tcx>,
attr: Option<&'a ast::Attribute>,
2015-08-18 17:59:21 -04:00
}
impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
// ignore methods; the outer dump will call us for them independently
}
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
// ignore methods; the outer dump will call us for them independently
}
2015-08-18 17:59:21 -04:00
fn visit_fn(&mut self,
fk: intravisit::FnKind<'tcx>,
2015-08-18 17:59:21 -04:00
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block,
span: Span,
id: ast::NodeId) {
let implicit_arg_tys = if let intravisit::FnKind::Closure(..) = fk {
2016-02-26 18:05:50 +02:00
vec![closure_self_ty(&self.tcx, id, body.id)]
} else {
vec![]
2015-08-18 17:59:21 -04:00
};
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
2015-08-18 17:59:21 -04:00
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
2016-02-26 18:05:50 +02:00
Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
Err(ErrorReported) => {}
2015-08-18 17:59:21 -04:00
}
intravisit::walk_fn(self, fk, decl, body, span);
2015-08-18 17:59:21 -04:00
}
}
fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
implicit_arg_tys: Vec<Ty<'tcx>>,
fn_id: ast::NodeId,
span: Span,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block)
-> Result<Mir<'tcx>, ErrorReported> {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) {
Some(f) => f.clone(),
None => {
cx.tcx().sess.span_bug(span,
&format!("no liberated fn sig for {:?}", fn_id));
}
};
let arguments =
decl.inputs
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs[index], &*arg.pat)
})
.collect();
let parameter_scope =
cx.tcx().region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
let MirAndScopeAuxiliary { mut mir, scope_auxiliary } =
2016-03-09 11:04:26 -05:00
build::construct(cx,
span,
implicit_arg_tys,
arguments,
parameter_scope,
fn_sig.output,
body);
2016-03-08 14:24:44 +02:00
match cx.tcx().node_id_to_type(fn_id).sty {
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
// RustCall pseudo-ABI untuples the last argument.
if let Some(arg_decl) = mir.arg_decls.last_mut() {
arg_decl.spread = true;
}
}
_ => {}
}
pretty::dump_mir(cx.tcx(),
"mir_map",
&0,
fn_id,
&mir,
Some(&scope_auxiliary));
2016-03-08 14:24:44 +02:00
Ok(mir)
2015-08-18 17:59:21 -04:00
}
2016-02-29 23:36:51 +00:00
fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
closure_expr_id: ast::NodeId,
body_id: ast::NodeId)
-> Ty<'tcx> {
2015-08-18 17:59:21 -04:00
let closure_ty = tcx.node_id_to_type(closure_expr_id);
// We're just hard-coding the idea that the signature will be
// &self or &mut self and hence will have a bound region with
// number 0, hokey.
let region = ty::Region::ReFree(ty::FreeRegion {
scope: tcx.region_maps.item_extent(body_id),
bound_region: ty::BoundRegion::BrAnon(0),
});
let region = tcx.mk_region(region);
2015-08-18 17:59:21 -04:00
match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
ty::ClosureKind::Fn =>
2015-08-18 17:59:21 -04:00
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutImmutable }),
ty::ClosureKind::FnMut =>
2015-08-18 17:59:21 -04:00
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,
mutbl: hir::MutMutable }),
ty::ClosureKind::FnOnce =>
2015-08-18 17:59:21 -04:00
closure_ty
}
}