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:
parent
0769865f7f
commit
ed7c30b888
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue