]> git.lizzy.rs Git - rust.git/commitdiff
Factor mir::[Mut]Visitor implementations into a common macro.
authorMichael Woerister <michaelwoerister@posteo.net>
Thu, 7 Jan 2016 10:49:46 +0000 (05:49 -0500)
committerMichael Woerister <michaelwoerister@posteo.net>
Thu, 7 Jan 2016 10:49:46 +0000 (05:49 -0500)
src/librustc/mir/repr.rs
src/librustc/mir/visit.rs

index b97d5939cf3b05857fd39c9c660cd4f6aac4fdb4..2bdaa22269aacc317e397a663106fbb7240b584c 100644 (file)
@@ -20,6 +20,7 @@
 use std::borrow::{Cow, IntoCow};
 use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
+use std::ops::{Index, IndexMut};
 
 /// Lowered representation of a single function.
 #[derive(RustcEncodable, RustcDecodable)]
@@ -67,6 +68,22 @@ pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'t
     }
 }
 
+impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
+    type Output = BasicBlockData<'tcx>;
+
+    #[inline]
+    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
+        self.basic_block_data(index)
+    }
+}
+
+impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
+    #[inline]
+    fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
+        self.basic_block_data_mut(index)
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Mutability and borrow kinds
 
index c05e4c83cd4f0fa42959887eaea7a921afa99077..7c8ea22de8e922a315d42de9bb875ccfb5c6535d 100644 (file)
 use rustc_data_structures::tuple_slice::TupleSlice;
 use syntax::codemap::Span;
 
-pub trait Visitor<'tcx> {
-    // Override these, and call `self.super_xxx` to revert back to the
-    // default behavior.
+macro_rules! make_mir_visitor {
+    ($visitor_trait_name:ident, $($mutability:ident)*) => {
+        pub trait $visitor_trait_name<'tcx> {
+            // Override these, and call `self.super_xxx` to revert back to the
+            // default behavior.
 
-    fn visit_mir(&mut self, mir: &Mir<'tcx>) {
-        self.super_mir(mir);
-    }
-
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
-        self.super_basic_block_data(block, data);
-    }
-
-    fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
-        self.super_statement(block, statement);
-    }
-
-    fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
-        self.super_assign(block, lvalue, rvalue);
-    }
-
-    fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
-        self.super_terminator(block, terminator);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
-        self.super_rvalue(rvalue);
-    }
-
-    fn visit_operand(&mut self, operand: &Operand<'tcx>) {
-        self.super_operand(operand);
-    }
-
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
-        self.super_lvalue(lvalue, context);
-    }
-
-    fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
-        self.super_branch(source, target);
-    }
-
-    fn visit_constant(&mut self, constant: &Constant<'tcx>) {
-        self.super_constant(constant);
-    }
-
-    fn visit_literal(&mut self, literal: &Literal<'tcx>) {
-        self.super_literal(literal);
-    }
-
-    fn visit_def_id(&mut self, def_id: DefId) {
-        self.super_def_id(def_id);
-    }
-
-    fn visit_span(&mut self, span: Span) {
-        self.super_span(span);
-    }
-
-    // The `super_xxx` methods comprise the default behavior and are
-    // not meant to be overidden.
-
-    fn super_mir(&mut self, mir: &Mir<'tcx>) {
-        for block in mir.all_basic_blocks() {
-            let data = mir.basic_block_data(block);
-            self.visit_basic_block_data(block, data);
-        }
-    }
-
-    fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
-        for statement in &data.statements {
-            self.visit_statement(block, statement);
-        }
-        data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
-    }
-
-    fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
-        self.visit_span(statement.span);
-
-        match statement.kind {
-            StatementKind::Assign(ref lvalue, ref rvalue) => {
-                self.visit_assign(block, lvalue, rvalue);
+            fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
+                self.super_mir(mir);
             }
-            StatementKind::Drop(_, ref lvalue) => {
-                self.visit_lvalue(lvalue, LvalueContext::Drop);
-            }
-        }
-    }
 
-    fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
-        self.visit_lvalue(lvalue, LvalueContext::Store);
-        self.visit_rvalue(rvalue);
-    }
-
-    fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
-        match *terminator {
-            Terminator::Goto { target } => {
-                self.visit_branch(block, target);
+            fn visit_basic_block_data(&mut self,
+                                      block: BasicBlock,
+                                      data: & $($mutability)* BasicBlockData<'tcx>) {
+                self.super_basic_block_data(block, data);
             }
 
-            Terminator::If { ref cond, ref targets } => {
-                self.visit_operand(cond);
-                for &target in targets.as_slice() {
-                    self.visit_branch(block, target);
-                }
+            fn visit_statement(&mut self,
+                               block: BasicBlock,
+                               statement: & $($mutability)* Statement<'tcx>) {
+                self.super_statement(block, statement);
             }
 
-            Terminator::Switch { ref discr, adt_def: _, ref targets } => {
-                self.visit_lvalue(discr, LvalueContext::Inspect);
-                for &target in targets {
-                    self.visit_branch(block, target);
-                }
+            fn visit_assign(&mut self,
+                            block: BasicBlock,
+                            lvalue: & $($mutability)* Lvalue<'tcx>,
+                            rvalue: & $($mutability)* Rvalue<'tcx>) {
+                self.super_assign(block, lvalue, rvalue);
             }
 
-            Terminator::SwitchInt { ref discr, switch_ty: _, values: _, ref targets } => {
-                self.visit_lvalue(discr, LvalueContext::Inspect);
-                for &target in targets {
-                    self.visit_branch(block, target);
-                }
+            fn visit_terminator(&mut self,
+                                block: BasicBlock,
+                                terminator: & $($mutability)* Terminator<'tcx>) {
+                self.super_terminator(block, terminator);
             }
 
-            Terminator::Resume |
-            Terminator::Return => {
+            fn visit_rvalue(&mut self,
+                            rvalue: & $($mutability)* Rvalue<'tcx>) {
+                self.super_rvalue(rvalue);
             }
 
-            Terminator::Call { ref func, ref args, ref kind } => {
-                if let Some(ref destination) = kind.destination() {
-                    self.visit_lvalue(destination, LvalueContext::Store);
-                }
-                self.visit_operand(func);
-                for arg in args {
-                    self.visit_operand(arg);
-                }
-                for &target in kind.successors() {
-                    self.visit_branch(block, target);
-                }
+            fn visit_operand(&mut self,
+                             operand: & $($mutability)* Operand<'tcx>) {
+                self.super_operand(operand);
             }
-        }
-    }
 
-    fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
-        match *rvalue {
-            Rvalue::Use(ref operand) => {
-                self.visit_operand(operand);
+            fn visit_lvalue(&mut self,
+                            lvalue: & $($mutability)* Lvalue<'tcx>,
+                            context: LvalueContext) {
+                self.super_lvalue(lvalue, context);
             }
 
-            Rvalue::Repeat(ref value, ref len) => {
-                self.visit_operand(value);
-                self.visit_constant(len);
+            fn visit_branch(&mut self,
+                            source: BasicBlock,
+                            target: BasicBlock) {
+                self.super_branch(source, target);
             }
 
-            Rvalue::Ref(r, bk, ref path) => {
-                self.visit_lvalue(path, LvalueContext::Borrow {
-                    region: r,
-                    kind: bk
-                });
+            fn visit_constant(&mut self,
+                              constant: & $($mutability)* Constant<'tcx>) {
+                self.super_constant(constant);
             }
 
-            Rvalue::Len(ref path) => {
-                self.visit_lvalue(path, LvalueContext::Inspect);
+            fn visit_literal(&mut self,
+                             literal: & $($mutability)* Literal<'tcx>) {
+                self.super_literal(literal);
             }
 
-            Rvalue::Cast(_, ref operand, _) => {
-                self.visit_operand(operand);
+            fn visit_def_id(&mut self,
+                            def_id: & $($mutability)* DefId) {
+                self.super_def_id(def_id);
             }
 
-            Rvalue::BinaryOp(_, ref lhs, ref rhs) => {
-                self.visit_operand(lhs);
-                self.visit_operand(rhs);
+            fn visit_span(&mut self,
+                          span: & $($mutability)* Span) {
+                self.super_span(span);
             }
 
-            Rvalue::UnaryOp(_, ref op) => {
-                self.visit_operand(op);
-            }
+            // The `super_xxx` methods comprise the default behavior and are
+            // not meant to be overidden.
 
-            Rvalue::Box(_) => {
+            fn super_mir(&mut self,
+                         mir: & $($mutability)* Mir<'tcx>) {
+                for block in mir.all_basic_blocks() {
+                    let data = & $($mutability)* mir[block];
+                    self.visit_basic_block_data(block, data);
+                }
             }
 
-            Rvalue::Aggregate(_, ref operands) => {
-                for operand in operands {
-                    self.visit_operand(operand);
+            fn super_basic_block_data(&mut self,
+                                      block: BasicBlock,
+                                      data: & $($mutability)* BasicBlockData<'tcx>) {
+                for statement in & $($mutability)* data.statements {
+                    self.visit_statement(block, statement);
                 }
-            }
 
-            Rvalue::Slice { ref input, from_start, from_end } => {
-                self.visit_lvalue(input, LvalueContext::Slice {
-                    from_start: from_start,
-                    from_end: from_end,
-                });
+                if let Some(ref $($mutability)* terminator) = data.terminator {
+                    self.visit_terminator(block, terminator);
+                }
             }
 
-            Rvalue::InlineAsm(_) => {
-            }
-        }
-    }
+            fn super_statement(&mut self,
+                               block: BasicBlock,
+                               statement: & $($mutability)* Statement<'tcx>) {
+                self.visit_span(& $($mutability)* statement.span);
 
-    fn super_operand(&mut self, operand: &Operand<'tcx>) {
-        match *operand {
-            Operand::Consume(ref lvalue) => {
-                self.visit_lvalue(lvalue, LvalueContext::Consume);
-            }
-            Operand::Constant(ref constant) => {
-                self.visit_constant(constant);
-            }
-        }
-    }
-
-    fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) {
-        match *lvalue {
-            Lvalue::Var(_) |
-            Lvalue::Temp(_) |
-            Lvalue::Arg(_) |
-            Lvalue::Static(_) |
-            Lvalue::ReturnPointer => {
-            }
-            Lvalue::Projection(ref proj) => {
-                self.visit_lvalue(&proj.base, LvalueContext::Projection);
+                match statement.kind {
+                    StatementKind::Assign(ref $($mutability)* lvalue,
+                                          ref $($mutability)* rvalue) => {
+                        self.visit_assign(block, lvalue, rvalue);
+                    }
+                    StatementKind::Drop(_, ref $($mutability)* lvalue) => {
+                        self.visit_lvalue(lvalue, LvalueContext::Drop);
+                    }
+                }
             }
-        }
-    }
-
-    fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
-    }
-
-    fn super_constant(&mut self, constant: &Constant<'tcx>) {
-        self.visit_span(constant.span);
-        self.visit_literal(&constant.literal);
-    }
 
-    fn super_literal(&mut self, literal: &Literal<'tcx>) {
-        match *literal {
-            Literal::Item { def_id, .. } => {
-                self.visit_def_id(def_id);
-            },
-            Literal::Value { .. } => {
-                // Nothing to do
+            fn super_assign(&mut self,
+                            _block: BasicBlock,
+                            lvalue: &$($mutability)* Lvalue<'tcx>,
+                            rvalue: &$($mutability)* Rvalue<'tcx>) {
+                self.visit_lvalue(lvalue, LvalueContext::Store);
+                self.visit_rvalue(rvalue);
             }
-        }
-    }
-
-    fn super_def_id(&mut self, _def_id: DefId) {
-    }
-
-    fn super_span(&mut self, _span: Span) {
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum LvalueContext {
-    // Appears as LHS of an assignment or as dest of a call
-    Store,
-
-    // Being dropped
-    Drop,
-
-    // Being inspected in some way, like loading a len
-    Inspect,
-
-    // Being borrowed
-    Borrow { region: Region, kind: BorrowKind },
-
-    // Being sliced -- this should be same as being borrowed, probably
-    Slice { from_start: usize, from_end: usize },
-
-    // Used as base for another lvalue, e.g. `x` in `x.y`
-    Projection,
-
-    // Consumed as part of an operand
-    Consume,
-}
-
-pub trait MutVisitor<'tcx> {
-    // Override these, and call `self.super_xxx` to revert back to the
-    // default behavior.
-
-    fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
-        self.super_mir(mir);
-    }
-
-    fn visit_basic_block_data(&mut self,
-                              block: BasicBlock,
-                              data: &mut BasicBlockData<'tcx>) {
-        self.super_basic_block_data(block, data);
-    }
 
-    fn visit_statement(&mut self,
-                       block: BasicBlock,
-                       statement: &mut Statement<'tcx>) {
-        self.super_statement(block, statement);
-    }
-
-    fn visit_assign(&mut self,
-                    block: BasicBlock,
-                    lvalue: &mut Lvalue<'tcx>,
-                    rvalue: &mut Rvalue<'tcx>) {
-        self.super_assign(block, lvalue, rvalue);
-    }
-
-    fn visit_terminator(&mut self,
-                        block: BasicBlock,
-                        terminator: &mut Terminator<'tcx>) {
-        self.super_terminator(block, terminator);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
-        self.super_rvalue(rvalue);
-    }
+            fn super_terminator(&mut self,
+                                block: BasicBlock,
+                                terminator: &$($mutability)* Terminator<'tcx>) {
+                match *terminator {
+                    Terminator::Goto { target } => {
+                        self.visit_branch(block, target);
+                    }
 
-    fn visit_operand(&mut self, operand: &mut Operand<'tcx>) {
-        self.super_operand(operand);
-    }
+                    Terminator::If { ref $($mutability)* cond,
+                                     ref $($mutability)* targets } => {
+                        self.visit_operand(cond);
+                        for &target in targets.as_slice() {
+                            self.visit_branch(block, target);
+                        }
+                    }
 
-    fn visit_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
-                    context: LvalueContext) {
-        self.super_lvalue(lvalue, context);
-    }
+                    Terminator::Switch { ref $($mutability)* discr,
+                                         adt_def: _,
+                                         ref targets } => {
+                        self.visit_lvalue(discr, LvalueContext::Inspect);
+                        for &target in targets {
+                            self.visit_branch(block, target);
+                        }
+                    }
 
-    fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
-        self.super_branch(source, target);
-    }
+                    Terminator::SwitchInt { ref $($mutability)* discr,
+                                            switch_ty: _,
+                                            values: _,
+                                            ref targets } => {
+                        self.visit_lvalue(discr, LvalueContext::Inspect);
+                        for &target in targets {
+                            self.visit_branch(block, target);
+                        }
+                    }
 
-    fn visit_constant(&mut self, constant: &mut Constant<'tcx>) {
-        self.super_constant(constant);
-    }
+                    Terminator::Resume |
+                    Terminator::Return => {
+                    }
 
-    fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
-        self.super_literal(literal);
-    }
+                    Terminator::Call { ref $($mutability)* func,
+                                       ref $($mutability)* args,
+                                       ref $($mutability)* kind } => {
+                        self.visit_operand(func);
+                        for arg in args {
+                            self.visit_operand(arg);
+                        }
+                        match *kind {
+                            CallKind::Converging {
+                                ref $($mutability)* destination,
+                                ..
+                            }        |
+                            CallKind::ConvergingCleanup {
+                                ref $($mutability)* destination,
+                                ..
+                            } => {
+                                self.visit_lvalue(destination, LvalueContext::Store);
+                            }
+                            CallKind::Diverging           |
+                            CallKind::DivergingCleanup(_) => {}
+                        }
+                        for &target in kind.successors() {
+                            self.visit_branch(block, target);
+                        }
+                    }
+                }
+            }
 
-    fn visit_def_id(&mut self, def_id: &mut DefId) {
-        self.super_def_id(def_id);
-    }
+            fn super_rvalue(&mut self,
+                            rvalue: & $($mutability)* Rvalue<'tcx>) {
+                match *rvalue {
+                    Rvalue::Use(ref $($mutability)* operand) => {
+                        self.visit_operand(operand);
+                    }
 
-    fn visit_span(&mut self, span: &mut Span) {
-        self.super_span(span);
-    }
+                    Rvalue::Repeat(ref $($mutability)* value,
+                                   ref $($mutability)* len) => {
+                        self.visit_operand(value);
+                        self.visit_constant(len);
+                    }
 
-    // The `super_xxx` methods comprise the default behavior and are
-    // not meant to be overidden.
+                    Rvalue::Ref(r, bk, ref $($mutability)* path) => {
+                        self.visit_lvalue(path, LvalueContext::Borrow {
+                            region: r,
+                            kind: bk
+                        });
+                    }
 
-    fn super_mir(&mut self, mir: &mut Mir<'tcx>) {
-        for block in mir.all_basic_blocks() {
-            let data = mir.basic_block_data_mut(block);
-            self.visit_basic_block_data(block, data);
-        }
-    }
+                    Rvalue::Len(ref $($mutability)* path) => {
+                        self.visit_lvalue(path, LvalueContext::Inspect);
+                    }
 
-    fn super_basic_block_data(&mut self,
-                              block: BasicBlock,
-                              data: &mut BasicBlockData<'tcx>) {
-        for statement in &mut data.statements {
-            self.visit_statement(block, statement);
-        }
-        data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
-    }
+                    Rvalue::Cast(_, ref $($mutability)* operand, _) => {
+                        self.visit_operand(operand);
+                    }
 
-    fn super_statement(&mut self,
-                       block: BasicBlock,
-                       statement: &mut Statement<'tcx>) {
-        self.visit_span(&mut statement.span);
+                    Rvalue::BinaryOp(_,
+                                     ref $($mutability)* lhs,
+                                     ref $($mutability)* rhs) => {
+                        self.visit_operand(lhs);
+                        self.visit_operand(rhs);
+                    }
 
-        match statement.kind {
-            StatementKind::Assign(ref mut lvalue, ref mut rvalue) => {
-                self.visit_assign(block, lvalue, rvalue);
-            }
-            StatementKind::Drop(_, ref mut lvalue) => {
-                self.visit_lvalue(lvalue, LvalueContext::Drop);
-            }
-        }
-    }
+                    Rvalue::UnaryOp(_, ref $($mutability)* op) => {
+                        self.visit_operand(op);
+                    }
 
-    fn super_assign(&mut self,
-                    _block: BasicBlock,
-                    lvalue: &mut Lvalue<'tcx>,
-                    rvalue: &mut Rvalue<'tcx>) {
-        self.visit_lvalue(lvalue, LvalueContext::Store);
-        self.visit_rvalue(rvalue);
-    }
+                    Rvalue::Box(_) => {
+                    }
 
-    fn super_terminator(&mut self,
-                        block: BasicBlock,
-                        terminator: &mut Terminator<'tcx>) {
-        match *terminator {
-            Terminator::Goto { target } => {
-                self.visit_branch(block, target);
-            }
+                    Rvalue::Aggregate(ref $($mutability)* kind,
+                                      ref $($mutability)* operands) => {
+                        match *kind {
+                            AggregateKind::Closure(ref $($mutability)* def_id, _) => {
+                                self.visit_def_id(def_id);
+                            }
+                            _ => { /* nothing to do */ }
+                        }
+
+                        for operand in & $($mutability)* operands[..] {
+                            self.visit_operand(operand);
+                        }
+                    }
 
-            Terminator::If { ref mut cond, ref mut targets } => {
-                self.visit_operand(cond);
-                for &target in targets.as_slice() {
-                    self.visit_branch(block, target);
-                }
-            }
+                    Rvalue::Slice { ref $($mutability)* input,
+                                    from_start,
+                                    from_end } => {
+                        self.visit_lvalue(input, LvalueContext::Slice {
+                            from_start: from_start,
+                            from_end: from_end,
+                        });
+                    }
 
-            Terminator::Switch { ref mut discr, adt_def: _, ref targets } => {
-                self.visit_lvalue(discr, LvalueContext::Inspect);
-                for &target in targets {
-                    self.visit_branch(block, target);
+                    Rvalue::InlineAsm(_) => {
+                    }
                 }
             }
 
-            Terminator::SwitchInt { ref mut discr, switch_ty: _, values: _, ref targets } => {
-                self.visit_lvalue(discr, LvalueContext::Inspect);
-                for &target in targets {
-                    self.visit_branch(block, target);
+            fn super_operand(&mut self,
+                             operand: & $($mutability)* Operand<'tcx>) {
+                match *operand {
+                    Operand::Consume(ref $($mutability)* lvalue) => {
+                        self.visit_lvalue(lvalue, LvalueContext::Consume);
+                    }
+                    Operand::Constant(ref $($mutability)* constant) => {
+                        self.visit_constant(constant);
+                    }
                 }
             }
 
-            Terminator::Resume |
-            Terminator::Return => {
-            }
-
-            Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
-                if let Some(ref mut destination) = kind.destination() {
-                    self.visit_lvalue(destination, LvalueContext::Store);
-                }
-                self.visit_operand(func);
-                for arg in args {
-                    self.visit_operand(arg);
-                }
-                for &target in kind.successors() {
-                    self.visit_branch(block, target);
+            fn super_lvalue(&mut self,
+                            lvalue: & $($mutability)* Lvalue<'tcx>,
+                            _context: LvalueContext) {
+                match *lvalue {
+                    Lvalue::Var(_) |
+                    Lvalue::Temp(_) |
+                    Lvalue::Arg(_) |
+                    Lvalue::ReturnPointer => {
+                    }
+                    Lvalue::Static(ref $($mutability)* def_id) => {
+                        self.visit_def_id(def_id);
+                    }
+                    Lvalue::Projection(ref $($mutability)* proj) => {
+                        self.visit_lvalue(& $($mutability)* proj.base,
+                                          LvalueContext::Projection);
+                    }
                 }
             }
-        }
-    }
-
-    fn super_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
-        match *rvalue {
-            Rvalue::Use(ref mut operand) => {
-                self.visit_operand(operand);
-            }
-
-            Rvalue::Repeat(ref mut value, ref mut len) => {
-                self.visit_operand(value);
-                self.visit_constant(len);
-            }
-
-            Rvalue::Ref(r, bk, ref mut path) => {
-                self.visit_lvalue(path, LvalueContext::Borrow {
-                    region: r,
-                    kind: bk
-                });
-            }
-
-            Rvalue::Len(ref mut path) => {
-                self.visit_lvalue(path, LvalueContext::Inspect);
-            }
-
-            Rvalue::Cast(_, ref mut operand, _) => {
-                self.visit_operand(operand);
-            }
-
-            Rvalue::BinaryOp(_, ref mut lhs, ref mut rhs) => {
-                self.visit_operand(lhs);
-                self.visit_operand(rhs);
-            }
 
-            Rvalue::UnaryOp(_, ref mut op) => {
-                self.visit_operand(op);
+            fn super_branch(&mut self,
+                            _source: BasicBlock,
+                            _target: BasicBlock) {
             }
 
-            Rvalue::Box(_) => {
+            fn super_constant(&mut self,
+                              constant: & $($mutability)* Constant<'tcx>) {
+                self.visit_span(& $($mutability)* constant.span);
+                self.visit_literal(& $($mutability)* constant.literal);
             }
 
-            Rvalue::Aggregate(ref mut kind, ref mut operands) => {
-                match *kind {
-                    AggregateKind::Closure(ref mut def_id, _) => {
+            fn super_literal(&mut self,
+                             literal: & $($mutability)* Literal<'tcx>) {
+                match *literal {
+                    Literal::Item { ref $($mutability)* def_id, .. } => {
                         self.visit_def_id(def_id);
+                    },
+                    Literal::Value { .. } => {
+                        // Nothing to do
                     }
-                    _ => { /* nothing to do */ }
-                }
-
-                for operand in &mut operands[..] {
-                    self.visit_operand(operand);
                 }
             }
 
-            Rvalue::Slice { ref mut input, from_start, from_end } => {
-                self.visit_lvalue(input, LvalueContext::Slice {
-                    from_start: from_start,
-                    from_end: from_end,
-                });
+            fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
             }
 
-            Rvalue::InlineAsm(_) => {
+            fn super_span(&mut self, _span: & $($mutability)* Span) {
             }
         }
     }
+}
 
-    fn super_operand(&mut self, operand: &mut Operand<'tcx>) {
-        match *operand {
-            Operand::Consume(ref mut lvalue) => {
-                self.visit_lvalue(lvalue, LvalueContext::Consume);
-            }
-            Operand::Constant(ref mut constant) => {
-                self.visit_constant(constant);
-            }
-        }
-    }
+make_mir_visitor!(Visitor,);
+make_mir_visitor!(MutVisitor,mut);
 
-    fn super_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
-                    _context: LvalueContext) {
-        match *lvalue {
-            Lvalue::Var(_) |
-            Lvalue::Temp(_) |
-            Lvalue::Arg(_) |
-            Lvalue::ReturnPointer => {
-            }
-            Lvalue::Static(ref mut def_id) => {
-                self.visit_def_id(def_id);
-            }
-            Lvalue::Projection(ref mut proj) => {
-                self.visit_lvalue(&mut proj.base, LvalueContext::Projection);
-            }
-        }
-    }
+#[derive(Copy, Clone, Debug)]
+pub enum LvalueContext {
+    // Appears as LHS of an assignment or as dest of a call
+    Store,
 
-    fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
-    }
+    // Being dropped
+    Drop,
 
-    fn super_constant(&mut self, constant: &mut Constant<'tcx>) {
-        self.visit_span(&mut constant.span);
-        self.visit_literal(&mut constant.literal);
-    }
+    // Being inspected in some way, like loading a len
+    Inspect,
 
-    fn super_literal(&mut self, literal: &mut Literal<'tcx>) {
-        match *literal {
-            Literal::Item { ref mut def_id, .. } => {
-                self.visit_def_id(def_id);
-            },
-            Literal::Value { .. } => {
-                // Nothing to do
-            }
-        }
-    }
+    // Being borrowed
+    Borrow { region: Region, kind: BorrowKind },
 
-    fn super_def_id(&mut self, _def_id: &mut DefId) {
-    }
+    // Being sliced -- this should be same as being borrowed, probably
+    Slice { from_start: usize, from_end: usize },
 
-    fn super_span(&mut self, _span: &mut Span) {
-    }
+    // Used as base for another lvalue, e.g. `x` in `x.y`
+    Projection,
+
+    // Consumed as part of an operand
+    Consume,
 }