about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-03-24 06:12:19 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-03-24 06:23:59 -0400
commited7c30b8885afb7e0bf26072dcb7e39658baade0 (patch)
treec4d2c1c9b1cfc4e5532e3535547bc493555e3edd
parent0769865f7f42d0c52b35552fe8d17e651d32772a (diff)
downloadrust-ed7c30b8885afb7e0bf26072dcb7e39658baade0.tar.gz
rust-ed7c30b8885afb7e0bf26072dcb7e39658baade0.zip
rework MIR visitor
We now visit more things (e.g., types) and also follow a deliberate
style designed to reduce omissions.
-rw-r--r--src/librustc/mir/repr.rs15
-rw-r--r--src/librustc/mir/visit.rs393
2 files changed, 382 insertions, 26 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 4022d762aec..47d923cbce3 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -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,
 }
 
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index c7e4b825d58..5be2e068414 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -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);
-
-                match statement.kind {
+                let Statement {
+                    ref $($mutability)* span,
+                    ref $($mutability)* scope,
+                    ref $($mutability)* kind,
+                } = *statement;
+
+                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, _) => {
+                            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) {
+            }
         }
     }
 }