rework MIR visitor

We now visit more things (e.g., types) and also follow a deliberate
style designed to reduce omissions.
This commit is contained in:
Niko Matsakis 2016-03-24 06:12:19 -04:00
parent 0769865f7f
commit ed7c30b888
2 changed files with 382 additions and 26 deletions

View File

@ -233,8 +233,23 @@ impl Debug for BasicBlock {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
/// List of statements in this block.
pub statements: Vec<Statement<'tcx>>,
/// Terminator for this block.
///
/// NB. This should generally ONLY be `None` during construction.
/// Therefore, you should generally access it via the
/// `terminator()` or `terminator_mut()` methods. The only
/// exception is that certain passes, such as `simplify_cfg`, swap
/// out the terminator temporarily with `None` while they continue
/// to recurse over the set of basic blocks.
pub terminator: Option<Terminator<'tcx>>,
/// If true, this block lies on an unwind path. This is used
/// during trans where distinct kinds of basic blocks may be
/// generated (particularly for MSVC cleanup). Unwind blocks must
/// only branch to other unwind blocks.
pub is_cleanup: bool,
}

View File

@ -8,12 +8,79 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::const_eval::ConstVal;
use middle::def_id::DefId;
use middle::ty::Region;
use middle::subst::Substs;
use middle::ty::{ClosureSubsts, FnOutput, Region, Ty};
use mir::repr::*;
use rustc_const_eval::ConstUsize;
use rustc_data_structures::tuple_slice::TupleSlice;
use syntax::codemap::Span;
// # The MIR Visitor
//
// ## Overview
//
// There are two visitors, one for immutable and one for mutable references,
// but both are generated by the following macro. The code is written according
// to the following conventions:
//
// - introduce a `visit_foo` and a `super_foo` method for every MIR type
// - `visit_foo`, by default, calls `super_foo`
// - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
//
// This allows you as a user to override `visit_foo` for types are
// interested in, and invoke (within that method) call
// `self.super_foo` to get the default behavior. Just as in an OO
// language, you should never call `super` methods ordinarily except
// in that circumstance.
//
// For the most part, we do not destructure things external to the
// MIR, e.g. types, spans, etc, but simply visit them and stop. This
// avoids duplication with other visitors like `TypeFoldable`. But
// there is one exception: we do destructure the `FnOutput` to reach
// the type within. Just because.
//
// ## Updating
//
// The code is written in a very deliberate style intended to minimize
// the chance of things being overlooked. You'll notice that we always
// use pattern matching to reference fields and we ensure that all
// matches are exhaustive.
//
// For example, the `super_basic_block_data` method begins like this:
//
// ```rust
// fn super_basic_block_data(&mut self,
// block: BasicBlock,
// data: & $($mutability)* BasicBlockData<'tcx>) {
// let BasicBlockData {
// ref $($mutability)* statements,
// ref $($mutability)* terminator,
// is_cleanup: _
// } = *data;
//
// for statement in statements {
// self.visit_statement(block, statement);
// }
//
// ...
// }
// ```
//
// Here we used `let BasicBlockData { <fields> } = *data` deliberately,
// rather than writing `data.statements` in the body. This is because if one
// adds a new field to `BasicBlockData`, one will be forced to revise this code,
// and hence one will (hopefully) invoke the correct visit methods (if any).
//
// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
// That means you never write `..` to skip over fields, nor do you write `_`
// to skip over variants in a `match`.
//
// The only place that `_` is acceptable is to match a field (or
// variant argument) that does not require visiting, as in
// `is_cleanup` above.
macro_rules! make_mir_visitor {
($visitor_trait_name:ident, $($mutability:ident)*) => {
pub trait $visitor_trait_name<'tcx> {
@ -30,6 +97,11 @@ macro_rules! make_mir_visitor {
self.super_basic_block_data(block, data);
}
fn visit_scope_data(&mut self,
scope_data: & $($mutability)* ScopeData) {
self.super_scope_data(scope_data);
}
fn visit_statement(&mut self,
block: BasicBlock,
statement: & $($mutability)* Statement<'tcx>) {
@ -49,6 +121,12 @@ macro_rules! make_mir_visitor {
self.super_terminator(block, terminator);
}
fn visit_terminator_kind(&mut self,
block: BasicBlock,
kind: & $($mutability)* TerminatorKind<'tcx>) {
self.super_terminator_kind(block, kind);
}
fn visit_rvalue(&mut self,
rvalue: & $($mutability)* Rvalue<'tcx>) {
self.super_rvalue(rvalue);
@ -65,6 +143,18 @@ macro_rules! make_mir_visitor {
self.super_lvalue(lvalue, context);
}
fn visit_projection(&mut self,
lvalue: & $($mutability)* LvalueProjection<'tcx>,
context: LvalueContext) {
self.super_projection(lvalue, context);
}
fn visit_projection_elem(&mut self,
lvalue: & $($mutability)* LvalueElem<'tcx>,
context: LvalueContext) {
self.super_projection_elem(lvalue, context);
}
fn visit_branch(&mut self,
source: BasicBlock,
target: BasicBlock) {
@ -91,35 +181,143 @@ macro_rules! make_mir_visitor {
self.super_span(span);
}
fn visit_fn_output(&mut self,
fn_output: & $($mutability)* FnOutput<'tcx>) {
self.super_fn_output(fn_output);
}
fn visit_ty(&mut self,
ty: & $($mutability)* Ty<'tcx>) {
self.super_ty(ty);
}
fn visit_substs(&mut self,
substs: & $($mutability)* &'tcx Substs<'tcx>) {
self.super_substs(substs);
}
fn visit_closure_substs(&mut self,
substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
self.super_closure_substs(substs);
}
fn visit_const_val(&mut self,
const_val: & $($mutability)* ConstVal) {
self.super_const_val(const_val);
}
fn visit_const_usize(&mut self,
const_usize: & $($mutability)* ConstUsize) {
self.super_const_usize(const_usize);
}
fn visit_typed_const_val(&mut self,
val: & $($mutability)* TypedConstVal<'tcx>) {
self.super_typed_const_val(val);
}
fn visit_var_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) {
self.super_var_decl(var_decl);
}
fn visit_temp_decl(&mut self,
temp_decl: & $($mutability)* TempDecl<'tcx>) {
self.super_temp_decl(temp_decl);
}
fn visit_arg_decl(&mut self,
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
self.super_arg_decl(arg_decl);
}
fn visit_scope_id(&mut self,
scope_id: & $($mutability)* ScopeId) {
self.super_scope_id(scope_id);
}
// The `super_xxx` methods comprise the default behavior and are
// not meant to be overridden.
fn super_mir(&mut self,
mir: & $($mutability)* Mir<'tcx>) {
for block in mir.all_basic_blocks() {
let data = & $($mutability)* mir[block];
let Mir {
ref $($mutability)* basic_blocks,
ref $($mutability)* scopes,
ref $($mutability)* return_ty,
ref $($mutability)* var_decls,
ref $($mutability)* arg_decls,
ref $($mutability)* temp_decls,
ref $($mutability)* span,
} = *mir;
for (index, data) in basic_blocks.into_iter().enumerate() {
let block = BasicBlock::new(index);
self.visit_basic_block_data(block, data);
}
for scope in scopes {
self.visit_scope_data(scope);
}
self.visit_fn_output(return_ty);
for var_decl in var_decls {
self.visit_var_decl(var_decl);
}
for arg_decl in arg_decls {
self.visit_arg_decl(arg_decl);
}
for temp_decl in temp_decls {
self.visit_temp_decl(temp_decl);
}
self.visit_span(span);
}
fn super_basic_block_data(&mut self,
block: BasicBlock,
data: & $($mutability)* BasicBlockData<'tcx>) {
for statement in & $($mutability)* data.statements {
let BasicBlockData {
ref $($mutability)* statements,
ref $($mutability)* terminator,
is_cleanup: _
} = *data;
for statement in statements {
self.visit_statement(block, statement);
}
if let Some(ref $($mutability)* terminator) = data.terminator {
if let Some(ref $($mutability)* terminator) = *terminator {
self.visit_terminator(block, terminator);
}
}
fn super_scope_data(&mut self,
scope_data: & $($mutability)* ScopeData) {
let ScopeData {
ref $($mutability)* parent_scope,
} = *scope_data;
if let Some(ref $($mutability)* parent_scope) = *parent_scope {
self.visit_scope_id(parent_scope);
}
}
fn super_statement(&mut self,
block: BasicBlock,
statement: & $($mutability)* Statement<'tcx>) {
self.visit_span(& $($mutability)* statement.span);
let Statement {
ref $($mutability)* span,
ref $($mutability)* scope,
ref $($mutability)* kind,
} = *statement;
match statement.kind {
self.visit_span(span);
self.visit_scope_id(scope);
match *kind {
StatementKind::Assign(ref $($mutability)* lvalue,
ref $($mutability)* rvalue) => {
self.visit_assign(block, lvalue, rvalue);
@ -138,7 +336,21 @@ macro_rules! make_mir_visitor {
fn super_terminator(&mut self,
block: BasicBlock,
terminator: &$($mutability)* Terminator<'tcx>) {
match terminator.kind {
let Terminator {
ref $($mutability)* span,
ref $($mutability)* scope,
ref $($mutability)* kind,
} = *terminator;
self.visit_span(span);
self.visit_scope_id(scope);
self.visit_terminator_kind(block, kind);
}
fn super_terminator_kind(&mut self,
block: BasicBlock,
kind: & $($mutability)* TerminatorKind<'tcx>) {
match *kind {
TerminatorKind::Goto { target } => {
self.visit_branch(block, target);
}
@ -161,10 +373,14 @@ macro_rules! make_mir_visitor {
}
TerminatorKind::SwitchInt { ref $($mutability)* discr,
switch_ty: _,
values: _,
ref $($mutability)* switch_ty,
ref $($mutability)* values,
ref targets } => {
self.visit_lvalue(discr, LvalueContext::Inspect);
self.visit_ty(switch_ty);
for value in values {
self.visit_const_val(value);
}
for &target in targets {
self.visit_branch(block, target);
}
@ -207,8 +423,9 @@ macro_rules! make_mir_visitor {
}
Rvalue::Repeat(ref $($mutability)* value,
_) => {
ref $($mutability)* typed_const_val) => {
self.visit_operand(value);
self.visit_typed_const_val(typed_const_val);
}
Rvalue::Ref(r, bk, ref $($mutability)* path) => {
@ -222,34 +439,48 @@ macro_rules! make_mir_visitor {
self.visit_lvalue(path, LvalueContext::Inspect);
}
Rvalue::Cast(_, ref $($mutability)* operand, _) => {
Rvalue::Cast(_cast_kind,
ref $($mutability)* operand,
ref $($mutability)* ty) => {
self.visit_operand(operand);
self.visit_ty(ty);
}
Rvalue::BinaryOp(_,
Rvalue::BinaryOp(_bin_op,
ref $($mutability)* lhs,
ref $($mutability)* rhs) => {
self.visit_operand(lhs);
self.visit_operand(rhs);
}
Rvalue::UnaryOp(_, ref $($mutability)* op) => {
Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
self.visit_operand(op);
}
Rvalue::Box(_) => {
Rvalue::Box(ref $($mutability)* ty) => {
self.visit_ty(ty);
}
Rvalue::Aggregate(ref $($mutability)* kind,
ref $($mutability)* operands) => {
match *kind {
AggregateKind::Closure(ref $($mutability)* def_id, _) => {
self.visit_def_id(def_id);
AggregateKind::Vec => {
}
AggregateKind::Tuple => {
}
AggregateKind::Adt(_adt_def,
_variant_index,
ref $($mutability)* substs) => {
self.visit_substs(substs);
}
AggregateKind::Closure(ref $($mutability)* def_id,
ref $($mutability)* closure_substs) => {
self.visit_def_id(def_id);
self.visit_closure_substs(closure_substs);
}
_ => { /* nothing to do */ }
}
for operand in & $($mutability)* operands[..] {
for operand in operands {
self.visit_operand(operand);
}
}
@ -264,7 +495,8 @@ macro_rules! make_mir_visitor {
}
Rvalue::InlineAsm { ref $($mutability)* outputs,
ref $($mutability)* inputs, .. } => {
ref $($mutability)* inputs,
asm: _ } => {
for output in & $($mutability)* outputs[..] {
self.visit_lvalue(output, LvalueContext::Store);
}
@ -289,7 +521,7 @@ macro_rules! make_mir_visitor {
fn super_lvalue(&mut self,
lvalue: & $($mutability)* Lvalue<'tcx>,
_context: LvalueContext) {
context: LvalueContext) {
match *lvalue {
Lvalue::Var(_) |
Lvalue::Temp(_) |
@ -300,12 +532,81 @@ macro_rules! make_mir_visitor {
self.visit_def_id(def_id);
}
Lvalue::Projection(ref $($mutability)* proj) => {
self.visit_lvalue(& $($mutability)* proj.base,
LvalueContext::Projection);
self.visit_projection(proj, context);
}
}
}
fn super_projection(&mut self,
proj: & $($mutability)* LvalueProjection<'tcx>,
context: LvalueContext) {
let Projection {
ref $($mutability)* base,
ref $($mutability)* elem,
} = *proj;
self.visit_lvalue(base, LvalueContext::Projection);
self.visit_projection_elem(elem, context);
}
fn super_projection_elem(&mut self,
proj: & $($mutability)* LvalueElem<'tcx>,
_context: LvalueContext) {
match *proj {
ProjectionElem::Deref => {
}
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
self.visit_ty(ty);
}
ProjectionElem::Index(ref $($mutability)* operand) => {
self.visit_operand(operand);
}
ProjectionElem::ConstantIndex { offset: _,
min_length: _,
from_end: _ } => {
}
ProjectionElem::Downcast(_adt_def, _variant_index) => {
}
}
}
fn super_var_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) {
let VarDecl {
mutability: _,
name: _,
ref $($mutability)* ty,
ref $($mutability)* scope,
ref $($mutability)* span,
} = *var_decl;
self.visit_ty(ty);
self.visit_scope_id(scope);
self.visit_span(span);
}
fn super_temp_decl(&mut self,
temp_decl: & $($mutability)* TempDecl<'tcx>) {
let TempDecl {
ref $($mutability)* ty,
} = *temp_decl;
self.visit_ty(ty);
}
fn super_arg_decl(&mut self,
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
let ArgDecl {
ref $($mutability)* ty,
spread: _
} = *arg_decl;
self.visit_ty(ty);
}
fn super_scope_id(&mut self,
_scope_id: & $($mutability)* ScopeId) {
}
fn super_branch(&mut self,
_source: BasicBlock,
_target: BasicBlock) {
@ -314,17 +615,32 @@ macro_rules! make_mir_visitor {
fn super_constant(&mut self,
constant: & $($mutability)* Constant<'tcx>) {
self.visit_span(& $($mutability)* constant.span);
self.visit_ty(& $($mutability)* constant.ty);
self.visit_literal(& $($mutability)* constant.literal);
}
fn super_typed_const_val(&mut self,
constant: & $($mutability)* TypedConstVal<'tcx>) {
let TypedConstVal {
ref $($mutability)* span,
ref $($mutability)* ty,
ref $($mutability)* value,
} = *constant;
self.visit_span(span);
self.visit_ty(ty);
self.visit_const_usize(value);
}
fn super_literal(&mut self,
literal: & $($mutability)* Literal<'tcx>) {
match *literal {
Literal::Item { ref $($mutability)* def_id, .. } => {
Literal::Item { ref $($mutability)* def_id,
ref $($mutability)* substs } => {
self.visit_def_id(def_id);
self.visit_substs(substs);
},
Literal::Value { .. } => {
// Nothing to do
Literal::Value { ref $($mutability)* value } => {
self.visit_const_val(value);
}
}
}
@ -334,6 +650,31 @@ macro_rules! make_mir_visitor {
fn super_span(&mut self, _span: & $($mutability)* Span) {
}
fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
match *fn_output {
FnOutput::FnConverging(ref $($mutability)* ty) => {
self.visit_ty(ty);
}
FnOutput::FnDiverging => {
}
}
}
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
}
fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
}
fn super_closure_substs(&mut self, _substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
}
fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
}
fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
}
}
}
}