1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use middle::def_id::DefId;
12 use middle::ty::Region;
14 use rustc_data_structures::tuple_slice::TupleSlice;
15 use syntax::codemap::Span;
17 macro_rules! make_mir_visitor {
18 ($visitor_trait_name:ident, $($mutability:ident)*) => {
19 pub trait $visitor_trait_name<'tcx> {
20 // Override these, and call `self.super_xxx` to revert back to the
23 fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
27 fn visit_basic_block_data(&mut self,
29 data: & $($mutability)* BasicBlockData<'tcx>) {
30 self.super_basic_block_data(block, data);
33 fn visit_statement(&mut self,
35 statement: & $($mutability)* Statement<'tcx>) {
36 self.super_statement(block, statement);
39 fn visit_assign(&mut self,
41 lvalue: & $($mutability)* Lvalue<'tcx>,
42 rvalue: & $($mutability)* Rvalue<'tcx>) {
43 self.super_assign(block, lvalue, rvalue);
46 fn visit_terminator(&mut self,
48 terminator: & $($mutability)* Terminator<'tcx>) {
49 self.super_terminator(block, terminator);
52 fn visit_rvalue(&mut self,
53 rvalue: & $($mutability)* Rvalue<'tcx>) {
54 self.super_rvalue(rvalue);
57 fn visit_operand(&mut self,
58 operand: & $($mutability)* Operand<'tcx>) {
59 self.super_operand(operand);
62 fn visit_lvalue(&mut self,
63 lvalue: & $($mutability)* Lvalue<'tcx>,
64 context: LvalueContext) {
65 self.super_lvalue(lvalue, context);
68 fn visit_branch(&mut self,
71 self.super_branch(source, target);
74 fn visit_constant(&mut self,
75 constant: & $($mutability)* Constant<'tcx>) {
76 self.super_constant(constant);
79 fn visit_literal(&mut self,
80 literal: & $($mutability)* Literal<'tcx>) {
81 self.super_literal(literal);
84 fn visit_def_id(&mut self,
85 def_id: & $($mutability)* DefId) {
86 self.super_def_id(def_id);
89 fn visit_span(&mut self,
90 span: & $($mutability)* Span) {
91 self.super_span(span);
94 // The `super_xxx` methods comprise the default behavior and are
95 // not meant to be overidden.
97 fn super_mir(&mut self,
98 mir: & $($mutability)* Mir<'tcx>) {
99 for block in mir.all_basic_blocks() {
100 let data = & $($mutability)* mir[block];
101 self.visit_basic_block_data(block, data);
105 fn super_basic_block_data(&mut self,
107 data: & $($mutability)* BasicBlockData<'tcx>) {
108 for statement in & $($mutability)* data.statements {
109 self.visit_statement(block, statement);
112 if let Some(ref $($mutability)* terminator) = data.terminator {
113 self.visit_terminator(block, terminator);
117 fn super_statement(&mut self,
119 statement: & $($mutability)* Statement<'tcx>) {
120 self.visit_span(& $($mutability)* statement.span);
122 match statement.kind {
123 StatementKind::Assign(ref $($mutability)* lvalue,
124 ref $($mutability)* rvalue) => {
125 self.visit_assign(block, lvalue, rvalue);
127 StatementKind::Drop(ref $($mutability)* lvalue) => {
128 self.visit_lvalue(lvalue, LvalueContext::Drop);
133 fn super_assign(&mut self,
135 lvalue: &$($mutability)* Lvalue<'tcx>,
136 rvalue: &$($mutability)* Rvalue<'tcx>) {
137 self.visit_lvalue(lvalue, LvalueContext::Store);
138 self.visit_rvalue(rvalue);
141 fn super_terminator(&mut self,
143 terminator: &$($mutability)* Terminator<'tcx>) {
145 Terminator::Goto { target } => {
146 self.visit_branch(block, target);
149 Terminator::If { ref $($mutability)* cond,
150 ref $($mutability)* targets } => {
151 self.visit_operand(cond);
152 for &target in targets.as_slice() {
153 self.visit_branch(block, target);
157 Terminator::Switch { ref $($mutability)* discr,
160 self.visit_lvalue(discr, LvalueContext::Inspect);
161 for &target in targets {
162 self.visit_branch(block, target);
166 Terminator::SwitchInt { ref $($mutability)* discr,
170 self.visit_lvalue(discr, LvalueContext::Inspect);
171 for &target in targets {
172 self.visit_branch(block, target);
177 Terminator::Return => {
180 Terminator::Call { ref $($mutability)* func,
181 ref $($mutability)* args,
182 ref $($mutability)* kind } => {
183 self.visit_operand(func);
185 self.visit_operand(arg);
188 CallKind::Converging {
189 ref $($mutability)* destination,
192 CallKind::ConvergingCleanup {
193 ref $($mutability)* destination,
196 self.visit_lvalue(destination, LvalueContext::Store);
198 CallKind::Diverging |
199 CallKind::DivergingCleanup(_) => {}
201 for &target in kind.successors() {
202 self.visit_branch(block, target);
208 fn super_rvalue(&mut self,
209 rvalue: & $($mutability)* Rvalue<'tcx>) {
211 Rvalue::Use(ref $($mutability)* operand) => {
212 self.visit_operand(operand);
215 Rvalue::Repeat(ref $($mutability)* value,
217 self.visit_operand(value);
220 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
221 self.visit_lvalue(path, LvalueContext::Borrow {
227 Rvalue::Len(ref $($mutability)* path) => {
228 self.visit_lvalue(path, LvalueContext::Inspect);
231 Rvalue::Cast(_, ref $($mutability)* operand, _) => {
232 self.visit_operand(operand);
236 ref $($mutability)* lhs,
237 ref $($mutability)* rhs) => {
238 self.visit_operand(lhs);
239 self.visit_operand(rhs);
242 Rvalue::UnaryOp(_, ref $($mutability)* op) => {
243 self.visit_operand(op);
249 Rvalue::Aggregate(ref $($mutability)* kind,
250 ref $($mutability)* operands) => {
252 AggregateKind::Closure(ref $($mutability)* def_id, _) => {
253 self.visit_def_id(def_id);
255 _ => { /* nothing to do */ }
258 for operand in & $($mutability)* operands[..] {
259 self.visit_operand(operand);
263 Rvalue::Slice { ref $($mutability)* input,
266 self.visit_lvalue(input, LvalueContext::Slice {
267 from_start: from_start,
272 Rvalue::InlineAsm(_) => {
277 fn super_operand(&mut self,
278 operand: & $($mutability)* Operand<'tcx>) {
280 Operand::Consume(ref $($mutability)* lvalue) => {
281 self.visit_lvalue(lvalue, LvalueContext::Consume);
283 Operand::Constant(ref $($mutability)* constant) => {
284 self.visit_constant(constant);
289 fn super_lvalue(&mut self,
290 lvalue: & $($mutability)* Lvalue<'tcx>,
291 _context: LvalueContext) {
296 Lvalue::ReturnPointer => {
298 Lvalue::Static(ref $($mutability)* def_id) => {
299 self.visit_def_id(def_id);
301 Lvalue::Projection(ref $($mutability)* proj) => {
302 self.visit_lvalue(& $($mutability)* proj.base,
303 LvalueContext::Projection);
308 fn super_branch(&mut self,
310 _target: BasicBlock) {
313 fn super_constant(&mut self,
314 constant: & $($mutability)* Constant<'tcx>) {
315 self.visit_span(& $($mutability)* constant.span);
316 self.visit_literal(& $($mutability)* constant.literal);
319 fn super_literal(&mut self,
320 literal: & $($mutability)* Literal<'tcx>) {
322 Literal::Item { ref $($mutability)* def_id, .. } => {
323 self.visit_def_id(def_id);
325 Literal::Value { .. } => {
331 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
334 fn super_span(&mut self, _span: & $($mutability)* Span) {
340 make_mir_visitor!(Visitor,);
341 make_mir_visitor!(MutVisitor,mut);
343 #[derive(Copy, Clone, Debug)]
344 pub enum LvalueContext {
345 // Appears as LHS of an assignment or as dest of a call
351 // Being inspected in some way, like loading a len
355 Borrow { region: Region, kind: BorrowKind },
357 // Being sliced -- this should be same as being borrowed, probably
358 Slice { from_start: usize, from_end: usize },
360 // Used as base for another lvalue, e.g. `x` in `x.y`
363 // Consumed as part of an operand