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::const_val::ConstVal;
12 use hir::def_id::DefId;
13 use ty::subst::Substs;
14 use ty::{ClosureSubsts, FnOutput, Region, Ty};
16 use rustc_const_math::ConstUsize;
17 use rustc_data_structures::tuple_slice::TupleSlice;
18 use syntax::codemap::Span;
24 // There are two visitors, one for immutable and one for mutable references,
25 // but both are generated by the following macro. The code is written according
26 // to the following conventions:
28 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
29 // - `visit_foo`, by default, calls `super_foo`
30 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
32 // This allows you as a user to override `visit_foo` for types are
33 // interested in, and invoke (within that method) call
34 // `self.super_foo` to get the default behavior. Just as in an OO
35 // language, you should never call `super` methods ordinarily except
36 // in that circumstance.
38 // For the most part, we do not destructure things external to the
39 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
40 // avoids duplication with other visitors like `TypeFoldable`. But
41 // there is one exception: we do destructure the `FnOutput` to reach
42 // the type within. Just because.
46 // The code is written in a very deliberate style intended to minimize
47 // the chance of things being overlooked. You'll notice that we always
48 // use pattern matching to reference fields and we ensure that all
49 // matches are exhaustive.
51 // For example, the `super_basic_block_data` method begins like this:
54 // fn super_basic_block_data(&mut self,
56 // data: & $($mutability)* BasicBlockData<'tcx>) {
57 // let BasicBlockData {
58 // ref $($mutability)* statements,
59 // ref $($mutability)* terminator,
63 // for statement in statements {
64 // self.visit_statement(block, statement);
71 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
72 // rather than writing `data.statements` in the body. This is because if one
73 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
74 // and hence one will (hopefully) invoke the correct visit methods (if any).
76 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
77 // That means you never write `..` to skip over fields, nor do you write `_`
78 // to skip over variants in a `match`.
80 // The only place that `_` is acceptable is to match a field (or
81 // variant argument) that does not require visiting, as in
82 // `is_cleanup` above.
84 macro_rules! make_mir_visitor {
85 ($visitor_trait_name:ident, $($mutability:ident)*) => {
86 pub trait $visitor_trait_name<'tcx> {
87 // Override these, and call `self.super_xxx` to revert back to the
90 fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
94 fn visit_basic_block_data(&mut self,
96 data: & $($mutability)* BasicBlockData<'tcx>) {
97 self.super_basic_block_data(block, data);
100 fn visit_scope_data(&mut self,
101 scope_data: & $($mutability)* ScopeData) {
102 self.super_scope_data(scope_data);
105 fn visit_statement(&mut self,
107 statement: & $($mutability)* Statement<'tcx>) {
108 self.super_statement(block, statement);
111 fn visit_assign(&mut self,
113 lvalue: & $($mutability)* Lvalue<'tcx>,
114 rvalue: & $($mutability)* Rvalue<'tcx>) {
115 self.super_assign(block, lvalue, rvalue);
118 fn visit_terminator(&mut self,
120 terminator: & $($mutability)* Terminator<'tcx>) {
121 self.super_terminator(block, terminator);
124 fn visit_terminator_kind(&mut self,
126 kind: & $($mutability)* TerminatorKind<'tcx>) {
127 self.super_terminator_kind(block, kind);
130 fn visit_rvalue(&mut self,
131 rvalue: & $($mutability)* Rvalue<'tcx>) {
132 self.super_rvalue(rvalue);
135 fn visit_operand(&mut self,
136 operand: & $($mutability)* Operand<'tcx>) {
137 self.super_operand(operand);
140 fn visit_lvalue(&mut self,
141 lvalue: & $($mutability)* Lvalue<'tcx>,
142 context: LvalueContext) {
143 self.super_lvalue(lvalue, context);
146 fn visit_projection(&mut self,
147 lvalue: & $($mutability)* LvalueProjection<'tcx>,
148 context: LvalueContext) {
149 self.super_projection(lvalue, context);
152 fn visit_projection_elem(&mut self,
153 lvalue: & $($mutability)* LvalueElem<'tcx>,
154 context: LvalueContext) {
155 self.super_projection_elem(lvalue, context);
158 fn visit_branch(&mut self,
160 target: BasicBlock) {
161 self.super_branch(source, target);
164 fn visit_constant(&mut self,
165 constant: & $($mutability)* Constant<'tcx>) {
166 self.super_constant(constant);
169 fn visit_literal(&mut self,
170 literal: & $($mutability)* Literal<'tcx>) {
171 self.super_literal(literal);
174 fn visit_def_id(&mut self,
175 def_id: & $($mutability)* DefId) {
176 self.super_def_id(def_id);
179 fn visit_span(&mut self,
180 span: & $($mutability)* Span) {
181 self.super_span(span);
184 fn visit_fn_output(&mut self,
185 fn_output: & $($mutability)* FnOutput<'tcx>) {
186 self.super_fn_output(fn_output);
189 fn visit_ty(&mut self,
190 ty: & $($mutability)* Ty<'tcx>) {
194 fn visit_substs(&mut self,
195 substs: & $($mutability)* &'tcx Substs<'tcx>) {
196 self.super_substs(substs);
199 fn visit_closure_substs(&mut self,
200 substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
201 self.super_closure_substs(substs);
204 fn visit_const_val(&mut self,
205 const_val: & $($mutability)* ConstVal) {
206 self.super_const_val(const_val);
209 fn visit_const_usize(&mut self,
210 const_usize: & $($mutability)* ConstUsize) {
211 self.super_const_usize(const_usize);
214 fn visit_typed_const_val(&mut self,
215 val: & $($mutability)* TypedConstVal<'tcx>) {
216 self.super_typed_const_val(val);
219 fn visit_var_decl(&mut self,
220 var_decl: & $($mutability)* VarDecl<'tcx>) {
221 self.super_var_decl(var_decl);
224 fn visit_temp_decl(&mut self,
225 temp_decl: & $($mutability)* TempDecl<'tcx>) {
226 self.super_temp_decl(temp_decl);
229 fn visit_arg_decl(&mut self,
230 arg_decl: & $($mutability)* ArgDecl<'tcx>) {
231 self.super_arg_decl(arg_decl);
234 fn visit_scope_id(&mut self,
235 scope_id: & $($mutability)* ScopeId) {
236 self.super_scope_id(scope_id);
239 // The `super_xxx` methods comprise the default behavior and are
240 // not meant to be overridden.
242 fn super_mir(&mut self,
243 mir: & $($mutability)* Mir<'tcx>) {
245 ref $($mutability)* basic_blocks,
246 ref $($mutability)* scopes,
247 ref $($mutability)* return_ty,
248 ref $($mutability)* var_decls,
249 ref $($mutability)* arg_decls,
250 ref $($mutability)* temp_decls,
251 ref $($mutability)* span,
254 for (index, data) in basic_blocks.into_iter().enumerate() {
255 let block = BasicBlock::new(index);
256 self.visit_basic_block_data(block, data);
259 for scope in scopes {
260 self.visit_scope_data(scope);
263 self.visit_fn_output(return_ty);
265 for var_decl in var_decls {
266 self.visit_var_decl(var_decl);
269 for arg_decl in arg_decls {
270 self.visit_arg_decl(arg_decl);
273 for temp_decl in temp_decls {
274 self.visit_temp_decl(temp_decl);
277 self.visit_span(span);
280 fn super_basic_block_data(&mut self,
282 data: & $($mutability)* BasicBlockData<'tcx>) {
284 ref $($mutability)* statements,
285 ref $($mutability)* terminator,
289 for statement in statements {
290 self.visit_statement(block, statement);
293 if let Some(ref $($mutability)* terminator) = *terminator {
294 self.visit_terminator(block, terminator);
298 fn super_scope_data(&mut self,
299 scope_data: & $($mutability)* ScopeData) {
301 ref $($mutability)* span,
302 ref $($mutability)* parent_scope,
305 self.visit_span(span);
306 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
307 self.visit_scope_id(parent_scope);
311 fn super_statement(&mut self,
313 statement: & $($mutability)* Statement<'tcx>) {
315 ref $($mutability)* span,
316 ref $($mutability)* scope,
317 ref $($mutability)* kind,
320 self.visit_span(span);
321 self.visit_scope_id(scope);
323 StatementKind::Assign(ref $($mutability)* lvalue,
324 ref $($mutability)* rvalue) => {
325 self.visit_assign(block, lvalue, rvalue);
330 fn super_assign(&mut self,
332 lvalue: &$($mutability)* Lvalue<'tcx>,
333 rvalue: &$($mutability)* Rvalue<'tcx>) {
334 self.visit_lvalue(lvalue, LvalueContext::Store);
335 self.visit_rvalue(rvalue);
338 fn super_terminator(&mut self,
340 terminator: &$($mutability)* Terminator<'tcx>) {
342 ref $($mutability)* span,
343 ref $($mutability)* scope,
344 ref $($mutability)* kind,
347 self.visit_span(span);
348 self.visit_scope_id(scope);
349 self.visit_terminator_kind(block, kind);
352 fn super_terminator_kind(&mut self,
354 kind: & $($mutability)* TerminatorKind<'tcx>) {
356 TerminatorKind::Goto { target } => {
357 self.visit_branch(block, target);
360 TerminatorKind::If { ref $($mutability)* cond,
361 ref $($mutability)* targets } => {
362 self.visit_operand(cond);
363 for &target in targets.as_slice() {
364 self.visit_branch(block, target);
368 TerminatorKind::Switch { ref $($mutability)* discr,
371 self.visit_lvalue(discr, LvalueContext::Inspect);
372 for &target in targets {
373 self.visit_branch(block, target);
377 TerminatorKind::SwitchInt { ref $($mutability)* discr,
378 ref $($mutability)* switch_ty,
379 ref $($mutability)* values,
381 self.visit_lvalue(discr, LvalueContext::Inspect);
382 self.visit_ty(switch_ty);
383 for value in values {
384 self.visit_const_val(value);
386 for &target in targets {
387 self.visit_branch(block, target);
391 TerminatorKind::Resume |
392 TerminatorKind::Return => {
395 TerminatorKind::Drop { ref $($mutability)* value,
398 self.visit_lvalue(value, LvalueContext::Drop);
399 self.visit_branch(block, target);
400 unwind.map(|t| self.visit_branch(block, t));
403 TerminatorKind::Call { ref $($mutability)* func,
404 ref $($mutability)* args,
405 ref $($mutability)* destination,
407 self.visit_operand(func);
409 self.visit_operand(arg);
411 if let Some((ref $($mutability)* destination, target)) = *destination {
412 self.visit_lvalue(destination, LvalueContext::Call);
413 self.visit_branch(block, target);
415 cleanup.map(|t| self.visit_branch(block, t));
420 fn super_rvalue(&mut self,
421 rvalue: & $($mutability)* Rvalue<'tcx>) {
423 Rvalue::Use(ref $($mutability)* operand) => {
424 self.visit_operand(operand);
427 Rvalue::Repeat(ref $($mutability)* value,
428 ref $($mutability)* typed_const_val) => {
429 self.visit_operand(value);
430 self.visit_typed_const_val(typed_const_val);
433 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
434 self.visit_lvalue(path, LvalueContext::Borrow {
440 Rvalue::Len(ref $($mutability)* path) => {
441 self.visit_lvalue(path, LvalueContext::Inspect);
444 Rvalue::Cast(_cast_kind,
445 ref $($mutability)* operand,
446 ref $($mutability)* ty) => {
447 self.visit_operand(operand);
451 Rvalue::BinaryOp(_bin_op,
452 ref $($mutability)* lhs,
453 ref $($mutability)* rhs) => {
454 self.visit_operand(lhs);
455 self.visit_operand(rhs);
458 Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
459 self.visit_operand(op);
462 Rvalue::Box(ref $($mutability)* ty) => {
466 Rvalue::Aggregate(ref $($mutability)* kind,
467 ref $($mutability)* operands) => {
469 AggregateKind::Vec => {
471 AggregateKind::Tuple => {
473 AggregateKind::Adt(_adt_def,
475 ref $($mutability)* substs) => {
476 self.visit_substs(substs);
478 AggregateKind::Closure(ref $($mutability)* def_id,
479 ref $($mutability)* closure_substs) => {
480 self.visit_def_id(def_id);
481 self.visit_closure_substs(closure_substs);
485 for operand in operands {
486 self.visit_operand(operand);
490 Rvalue::Slice { ref $($mutability)* input,
493 self.visit_lvalue(input, LvalueContext::Slice {
494 from_start: from_start,
499 Rvalue::InlineAsm { ref $($mutability)* outputs,
500 ref $($mutability)* inputs,
502 for output in & $($mutability)* outputs[..] {
503 self.visit_lvalue(output, LvalueContext::Store);
505 for input in & $($mutability)* inputs[..] {
506 self.visit_operand(input);
512 fn super_operand(&mut self,
513 operand: & $($mutability)* Operand<'tcx>) {
515 Operand::Consume(ref $($mutability)* lvalue) => {
516 self.visit_lvalue(lvalue, LvalueContext::Consume);
518 Operand::Constant(ref $($mutability)* constant) => {
519 self.visit_constant(constant);
524 fn super_lvalue(&mut self,
525 lvalue: & $($mutability)* Lvalue<'tcx>,
526 context: LvalueContext) {
531 Lvalue::ReturnPointer => {
533 Lvalue::Static(ref $($mutability)* def_id) => {
534 self.visit_def_id(def_id);
536 Lvalue::Projection(ref $($mutability)* proj) => {
537 self.visit_projection(proj, context);
542 fn super_projection(&mut self,
543 proj: & $($mutability)* LvalueProjection<'tcx>,
544 context: LvalueContext) {
546 ref $($mutability)* base,
547 ref $($mutability)* elem,
549 self.visit_lvalue(base, LvalueContext::Projection);
550 self.visit_projection_elem(elem, context);
553 fn super_projection_elem(&mut self,
554 proj: & $($mutability)* LvalueElem<'tcx>,
555 _context: LvalueContext) {
557 ProjectionElem::Deref => {
559 ProjectionElem::Field(_field, ref $($mutability)* ty) => {
562 ProjectionElem::Index(ref $($mutability)* operand) => {
563 self.visit_operand(operand);
565 ProjectionElem::ConstantIndex { offset: _,
569 ProjectionElem::Downcast(_adt_def, _variant_index) => {
574 fn super_var_decl(&mut self,
575 var_decl: & $($mutability)* VarDecl<'tcx>) {
579 ref $($mutability)* ty,
580 ref $($mutability)* scope,
581 ref $($mutability)* span,
585 self.visit_scope_id(scope);
586 self.visit_span(span);
589 fn super_temp_decl(&mut self,
590 temp_decl: & $($mutability)* TempDecl<'tcx>) {
592 ref $($mutability)* ty,
598 fn super_arg_decl(&mut self,
599 arg_decl: & $($mutability)* ArgDecl<'tcx>) {
601 ref $($mutability)* ty,
608 fn super_scope_id(&mut self,
609 _scope_id: & $($mutability)* ScopeId) {
612 fn super_branch(&mut self,
614 _target: BasicBlock) {
617 fn super_constant(&mut self,
618 constant: & $($mutability)* Constant<'tcx>) {
620 ref $($mutability)* span,
621 ref $($mutability)* ty,
622 ref $($mutability)* literal,
625 self.visit_span(span);
627 self.visit_literal(literal);
630 fn super_typed_const_val(&mut self,
631 constant: & $($mutability)* TypedConstVal<'tcx>) {
633 ref $($mutability)* span,
634 ref $($mutability)* ty,
635 ref $($mutability)* value,
638 self.visit_span(span);
640 self.visit_const_usize(value);
643 fn super_literal(&mut self,
644 literal: & $($mutability)* Literal<'tcx>) {
646 Literal::Item { ref $($mutability)* def_id,
647 ref $($mutability)* substs } => {
648 self.visit_def_id(def_id);
649 self.visit_substs(substs);
651 Literal::Value { ref $($mutability)* value } => {
652 self.visit_const_val(value);
657 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
660 fn super_span(&mut self, _span: & $($mutability)* Span) {
663 fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
665 FnOutput::FnConverging(ref $($mutability)* ty) => {
668 FnOutput::FnDiverging => {
673 fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
676 fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
679 fn super_closure_substs(&mut self,
680 _substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
683 fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
686 fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
692 make_mir_visitor!(Visitor,);
693 make_mir_visitor!(MutVisitor,mut);
695 #[derive(Copy, Clone, Debug)]
696 pub enum LvalueContext {
697 // Appears as LHS of an assignment
706 // Being inspected in some way, like loading a len
710 Borrow { region: Region, kind: BorrowKind },
712 // Being sliced -- this should be same as being borrowed, probably
713 Slice { from_start: usize, from_end: usize },
715 // Used as base for another lvalue, e.g. `x` in `x.y`
718 // Consumed as part of an operand