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 overridden.
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);
130 fn super_assign(&mut self,
132 lvalue: &$($mutability)* Lvalue<'tcx>,
133 rvalue: &$($mutability)* Rvalue<'tcx>) {
134 self.visit_lvalue(lvalue, LvalueContext::Store);
135 self.visit_rvalue(rvalue);
138 fn super_terminator(&mut self,
140 terminator: &$($mutability)* Terminator<'tcx>) {
142 Terminator::Goto { target } => {
143 self.visit_branch(block, target);
146 Terminator::If { ref $($mutability)* cond,
147 ref $($mutability)* targets } => {
148 self.visit_operand(cond);
149 for &target in targets.as_slice() {
150 self.visit_branch(block, target);
154 Terminator::Switch { ref $($mutability)* discr,
157 self.visit_lvalue(discr, LvalueContext::Inspect);
158 for &target in targets {
159 self.visit_branch(block, target);
163 Terminator::SwitchInt { ref $($mutability)* discr,
167 self.visit_lvalue(discr, LvalueContext::Inspect);
168 for &target in targets {
169 self.visit_branch(block, target);
174 Terminator::Return => {
177 Terminator::Drop { ref $($mutability)* value, target, unwind } => {
178 self.visit_lvalue(value, LvalueContext::Drop);
179 self.visit_branch(block, target);
180 unwind.map(|t| self.visit_branch(block, t));
183 Terminator::Call { ref $($mutability)* func,
184 ref $($mutability)* args,
185 ref $($mutability)* destination,
187 self.visit_operand(func);
189 self.visit_operand(arg);
191 if let Some((ref $($mutability)* destination, target)) = *destination {
192 self.visit_lvalue(destination, LvalueContext::Store);
193 self.visit_branch(block, target);
195 cleanup.map(|t| self.visit_branch(block, t));
200 fn super_rvalue(&mut self,
201 rvalue: & $($mutability)* Rvalue<'tcx>) {
203 Rvalue::Use(ref $($mutability)* operand) => {
204 self.visit_operand(operand);
207 Rvalue::Repeat(ref $($mutability)* value,
209 self.visit_operand(value);
212 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
213 self.visit_lvalue(path, LvalueContext::Borrow {
219 Rvalue::Len(ref $($mutability)* path) => {
220 self.visit_lvalue(path, LvalueContext::Inspect);
223 Rvalue::Cast(_, ref $($mutability)* operand, _) => {
224 self.visit_operand(operand);
228 ref $($mutability)* lhs,
229 ref $($mutability)* rhs) => {
230 self.visit_operand(lhs);
231 self.visit_operand(rhs);
234 Rvalue::UnaryOp(_, ref $($mutability)* op) => {
235 self.visit_operand(op);
241 Rvalue::Aggregate(ref $($mutability)* kind,
242 ref $($mutability)* operands) => {
244 AggregateKind::Closure(ref $($mutability)* def_id, _) => {
245 self.visit_def_id(def_id);
247 _ => { /* nothing to do */ }
250 for operand in & $($mutability)* operands[..] {
251 self.visit_operand(operand);
255 Rvalue::Slice { ref $($mutability)* input,
258 self.visit_lvalue(input, LvalueContext::Slice {
259 from_start: from_start,
264 Rvalue::InlineAsm(_) => {
269 fn super_operand(&mut self,
270 operand: & $($mutability)* Operand<'tcx>) {
272 Operand::Consume(ref $($mutability)* lvalue) => {
273 self.visit_lvalue(lvalue, LvalueContext::Consume);
275 Operand::Constant(ref $($mutability)* constant) => {
276 self.visit_constant(constant);
281 fn super_lvalue(&mut self,
282 lvalue: & $($mutability)* Lvalue<'tcx>,
283 _context: LvalueContext) {
288 Lvalue::ReturnPointer => {
290 Lvalue::Static(ref $($mutability)* def_id) => {
291 self.visit_def_id(def_id);
293 Lvalue::Projection(ref $($mutability)* proj) => {
294 self.visit_lvalue(& $($mutability)* proj.base,
295 LvalueContext::Projection);
300 fn super_branch(&mut self,
302 _target: BasicBlock) {
305 fn super_constant(&mut self,
306 constant: & $($mutability)* Constant<'tcx>) {
307 self.visit_span(& $($mutability)* constant.span);
308 self.visit_literal(& $($mutability)* constant.literal);
311 fn super_literal(&mut self,
312 literal: & $($mutability)* Literal<'tcx>) {
314 Literal::Item { ref $($mutability)* def_id, .. } => {
315 self.visit_def_id(def_id);
317 Literal::Value { .. } => {
323 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
326 fn super_span(&mut self, _span: & $($mutability)* Span) {
332 make_mir_visitor!(Visitor,);
333 make_mir_visitor!(MutVisitor,mut);
335 #[derive(Copy, Clone, Debug)]
336 pub enum LvalueContext {
337 // Appears as LHS of an assignment or as dest of a call
343 // Being inspected in some way, like loading a len
347 Borrow { region: Region, kind: BorrowKind },
349 // Being sliced -- this should be same as being borrowed, probably
350 Slice { from_start: usize, from_end: usize },
352 // Used as base for another lvalue, e.g. `x` in `x.y`
355 // Consumed as part of an operand