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,
216 ref $($mutability)* len) => {
217 self.visit_operand(value);
218 self.visit_constant(len);
221 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
222 self.visit_lvalue(path, LvalueContext::Borrow {
228 Rvalue::Len(ref $($mutability)* path) => {
229 self.visit_lvalue(path, LvalueContext::Inspect);
232 Rvalue::Cast(_, ref $($mutability)* operand, _) => {
233 self.visit_operand(operand);
237 ref $($mutability)* lhs,
238 ref $($mutability)* rhs) => {
239 self.visit_operand(lhs);
240 self.visit_operand(rhs);
243 Rvalue::UnaryOp(_, ref $($mutability)* op) => {
244 self.visit_operand(op);
250 Rvalue::Aggregate(ref $($mutability)* kind,
251 ref $($mutability)* operands) => {
253 AggregateKind::Closure(ref $($mutability)* def_id, _) => {
254 self.visit_def_id(def_id);
256 _ => { /* nothing to do */ }
259 for operand in & $($mutability)* operands[..] {
260 self.visit_operand(operand);
264 Rvalue::Slice { ref $($mutability)* input,
267 self.visit_lvalue(input, LvalueContext::Slice {
268 from_start: from_start,
273 Rvalue::InlineAsm(_) => {
278 fn super_operand(&mut self,
279 operand: & $($mutability)* Operand<'tcx>) {
281 Operand::Consume(ref $($mutability)* lvalue) => {
282 self.visit_lvalue(lvalue, LvalueContext::Consume);
284 Operand::Constant(ref $($mutability)* constant) => {
285 self.visit_constant(constant);
290 fn super_lvalue(&mut self,
291 lvalue: & $($mutability)* Lvalue<'tcx>,
292 _context: LvalueContext) {
297 Lvalue::ReturnPointer => {
299 Lvalue::Static(ref $($mutability)* def_id) => {
300 self.visit_def_id(def_id);
302 Lvalue::Projection(ref $($mutability)* proj) => {
303 self.visit_lvalue(& $($mutability)* proj.base,
304 LvalueContext::Projection);
309 fn super_branch(&mut self,
311 _target: BasicBlock) {
314 fn super_constant(&mut self,
315 constant: & $($mutability)* Constant<'tcx>) {
316 self.visit_span(& $($mutability)* constant.span);
317 self.visit_literal(& $($mutability)* constant.literal);
320 fn super_literal(&mut self,
321 literal: & $($mutability)* Literal<'tcx>) {
323 Literal::Item { ref $($mutability)* def_id, .. } => {
324 self.visit_def_id(def_id);
326 Literal::Value { .. } => {
332 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
335 fn super_span(&mut self, _span: & $($mutability)* Span) {
341 make_mir_visitor!(Visitor,);
342 make_mir_visitor!(MutVisitor,mut);
344 #[derive(Copy, Clone, Debug)]
345 pub enum LvalueContext {
346 // Appears as LHS of an assignment or as dest of a call
352 // Being inspected in some way, like loading a len
356 Borrow { region: Region, kind: BorrowKind },
358 // Being sliced -- this should be same as being borrowed, probably
359 Slice { from_start: usize, from_end: usize },
361 // Used as base for another lvalue, e.g. `x` in `x.y`
364 // Consumed as part of an operand