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, Region, Ty};
16 use rustc_const_math::ConstUsize;
17 use rustc_data_structures::tuple_slice::TupleSlice;
18 use rustc_data_structures::indexed_vec::Idx;
25 // There are two visitors, one for immutable and one for mutable references,
26 // but both are generated by the following macro. The code is written according
27 // to the following conventions:
29 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
30 // - `visit_foo`, by default, calls `super_foo`
31 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
33 // This allows you as a user to override `visit_foo` for types are
34 // interested in, and invoke (within that method) call
35 // `self.super_foo` to get the default behavior. Just as in an OO
36 // language, you should never call `super` methods ordinarily except
37 // in that circumstance.
39 // For the most part, we do not destructure things external to the
40 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
41 // avoids duplication with other visitors like `TypeFoldable`.
45 // The code is written in a very deliberate style intended to minimize
46 // the chance of things being overlooked. You'll notice that we always
47 // use pattern matching to reference fields and we ensure that all
48 // matches are exhaustive.
50 // For example, the `super_basic_block_data` method begins like this:
53 // fn super_basic_block_data(&mut self,
55 // data: & $($mutability)* BasicBlockData<'tcx>) {
56 // let BasicBlockData {
57 // ref $($mutability)* statements,
58 // ref $($mutability)* terminator,
62 // for statement in statements {
63 // self.visit_statement(block, statement);
70 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
71 // rather than writing `data.statements` in the body. This is because if one
72 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
73 // and hence one will (hopefully) invoke the correct visit methods (if any).
75 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
76 // That means you never write `..` to skip over fields, nor do you write `_`
77 // to skip over variants in a `match`.
79 // The only place that `_` is acceptable is to match a field (or
80 // variant argument) that does not require visiting, as in
81 // `is_cleanup` above.
83 macro_rules! make_mir_visitor {
84 ($visitor_trait_name:ident, $($mutability:ident)*) => {
85 pub trait $visitor_trait_name<'tcx> {
86 // Override these, and call `self.super_xxx` to revert back to the
89 fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
93 fn visit_basic_block_data(&mut self,
95 data: & $($mutability)* BasicBlockData<'tcx>) {
96 self.super_basic_block_data(block, data);
99 fn visit_visibility_scope_data(&mut self,
100 scope_data: & $($mutability)* VisibilityScopeData) {
101 self.super_visibility_scope_data(scope_data);
104 fn visit_statement(&mut self,
106 statement: & $($mutability)* Statement<'tcx>,
107 location: Location) {
108 self.super_statement(block, statement, location);
111 fn visit_assign(&mut self,
113 lvalue: & $($mutability)* Lvalue<'tcx>,
114 rvalue: & $($mutability)* Rvalue<'tcx>,
115 location: Location) {
116 self.super_assign(block, lvalue, rvalue, location);
119 fn visit_terminator(&mut self,
121 terminator: & $($mutability)* Terminator<'tcx>,
122 location: Location) {
123 self.super_terminator(block, terminator, location);
126 fn visit_terminator_kind(&mut self,
128 kind: & $($mutability)* TerminatorKind<'tcx>,
129 location: Location) {
130 self.super_terminator_kind(block, kind, location);
133 fn visit_assert_message(&mut self,
134 msg: & $($mutability)* AssertMessage<'tcx>,
135 location: Location) {
136 self.super_assert_message(msg, location);
139 fn visit_rvalue(&mut self,
140 rvalue: & $($mutability)* Rvalue<'tcx>,
141 location: Location) {
142 self.super_rvalue(rvalue, location);
145 fn visit_operand(&mut self,
146 operand: & $($mutability)* Operand<'tcx>,
147 location: Location) {
148 self.super_operand(operand, location);
151 fn visit_lvalue(&mut self,
152 lvalue: & $($mutability)* Lvalue<'tcx>,
153 context: LvalueContext<'tcx>,
154 location: Location) {
155 self.super_lvalue(lvalue, context, location);
158 fn visit_projection(&mut self,
159 lvalue: & $($mutability)* LvalueProjection<'tcx>,
160 context: LvalueContext,
161 location: Location) {
162 self.super_projection(lvalue, context, location);
165 fn visit_projection_elem(&mut self,
166 lvalue: & $($mutability)* LvalueElem<'tcx>,
167 context: LvalueContext,
168 location: Location) {
169 self.super_projection_elem(lvalue, context, location);
172 fn visit_branch(&mut self,
174 target: BasicBlock) {
175 self.super_branch(source, target);
178 fn visit_constant(&mut self,
179 constant: & $($mutability)* Constant<'tcx>,
180 location: Location) {
181 self.super_constant(constant, location);
184 fn visit_literal(&mut self,
185 literal: & $($mutability)* Literal<'tcx>,
186 location: Location) {
187 self.super_literal(literal, location);
190 fn visit_def_id(&mut self,
191 def_id: & $($mutability)* DefId,
193 self.super_def_id(def_id);
196 fn visit_span(&mut self,
197 span: & $($mutability)* Span) {
198 self.super_span(span);
201 fn visit_source_info(&mut self,
202 source_info: & $($mutability)* SourceInfo) {
203 self.super_source_info(source_info);
206 fn visit_ty(&mut self,
207 ty: & $($mutability)* Ty<'tcx>) {
211 fn visit_substs(&mut self,
212 substs: & $($mutability)* &'tcx Substs<'tcx>) {
213 self.super_substs(substs);
216 fn visit_closure_substs(&mut self,
217 substs: & $($mutability)* ClosureSubsts<'tcx>) {
218 self.super_closure_substs(substs);
221 fn visit_const_val(&mut self,
222 const_val: & $($mutability)* ConstVal,
224 self.super_const_val(const_val);
227 fn visit_const_usize(&mut self,
228 const_usize: & $($mutability)* ConstUsize,
230 self.super_const_usize(const_usize);
233 fn visit_typed_const_val(&mut self,
234 val: & $($mutability)* TypedConstVal<'tcx>,
235 location: Location) {
236 self.super_typed_const_val(val, location);
239 fn visit_var_decl(&mut self,
240 var_decl: & $($mutability)* VarDecl<'tcx>) {
241 self.super_var_decl(var_decl);
244 fn visit_temp_decl(&mut self,
245 temp_decl: & $($mutability)* TempDecl<'tcx>) {
246 self.super_temp_decl(temp_decl);
249 fn visit_arg_decl(&mut self,
250 arg_decl: & $($mutability)* ArgDecl<'tcx>) {
251 self.super_arg_decl(arg_decl);
254 fn visit_visibility_scope(&mut self,
255 scope: & $($mutability)* VisibilityScope) {
256 self.super_visibility_scope(scope);
259 // The `super_xxx` methods comprise the default behavior and are
260 // not meant to be overridden.
262 fn super_mir(&mut self,
263 mir: & $($mutability)* Mir<'tcx>) {
264 for index in 0..mir.basic_blocks().len() {
265 let block = BasicBlock::new(index);
266 self.visit_basic_block_data(block, &$($mutability)* mir[block]);
269 for scope in &$($mutability)* mir.visibility_scopes {
270 self.visit_visibility_scope_data(scope);
273 self.visit_ty(&$($mutability)* mir.return_ty);
275 for var_decl in &$($mutability)* mir.var_decls {
276 self.visit_var_decl(var_decl);
279 for arg_decl in &$($mutability)* mir.arg_decls {
280 self.visit_arg_decl(arg_decl);
283 for temp_decl in &$($mutability)* mir.temp_decls {
284 self.visit_temp_decl(temp_decl);
287 self.visit_span(&$($mutability)* mir.span);
290 fn super_basic_block_data(&mut self,
292 data: & $($mutability)* BasicBlockData<'tcx>) {
294 ref $($mutability)* statements,
295 ref $($mutability)* terminator,
300 for statement in statements {
301 let location = Location { block: block, statement_index: index };
302 self.visit_statement(block, statement, location);
306 if let Some(ref $($mutability)* terminator) = *terminator {
307 let location = Location { block: block, statement_index: index };
308 self.visit_terminator(block, terminator, location);
312 fn super_visibility_scope_data(&mut self,
313 scope_data: & $($mutability)* VisibilityScopeData) {
314 let VisibilityScopeData {
315 ref $($mutability)* span,
316 ref $($mutability)* parent_scope,
319 self.visit_span(span);
320 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
321 self.visit_visibility_scope(parent_scope);
325 fn super_statement(&mut self,
327 statement: & $($mutability)* Statement<'tcx>,
328 location: Location) {
330 ref $($mutability)* source_info,
331 ref $($mutability)* kind,
334 self.visit_source_info(source_info);
336 StatementKind::Assign(ref $($mutability)* lvalue,
337 ref $($mutability)* rvalue) => {
338 self.visit_assign(block, lvalue, rvalue, location);
340 StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
341 self.visit_lvalue(lvalue, LvalueContext::Store, location);
343 StatementKind::StorageLive(ref $($mutability)* lvalue) => {
344 self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
346 StatementKind::StorageDead(ref $($mutability)* lvalue) => {
347 self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
349 StatementKind::Nop => {}
353 fn super_assign(&mut self,
355 lvalue: &$($mutability)* Lvalue<'tcx>,
356 rvalue: &$($mutability)* Rvalue<'tcx>,
357 location: Location) {
358 self.visit_lvalue(lvalue, LvalueContext::Store, location);
359 self.visit_rvalue(rvalue, location);
362 fn super_terminator(&mut self,
364 terminator: &$($mutability)* Terminator<'tcx>,
365 location: Location) {
367 ref $($mutability)* source_info,
368 ref $($mutability)* kind,
371 self.visit_source_info(source_info);
372 self.visit_terminator_kind(block, kind, location);
375 fn super_terminator_kind(&mut self,
377 kind: & $($mutability)* TerminatorKind<'tcx>,
378 source_location: Location) {
380 TerminatorKind::Goto { target } => {
381 self.visit_branch(block, target);
384 TerminatorKind::If { ref $($mutability)* cond,
385 ref $($mutability)* targets } => {
386 self.visit_operand(cond, source_location);
387 for &target in targets.as_slice() {
388 self.visit_branch(block, target);
392 TerminatorKind::Switch { ref $($mutability)* discr,
395 self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
396 for &target in targets {
397 self.visit_branch(block, target);
401 TerminatorKind::SwitchInt { ref $($mutability)* discr,
402 ref $($mutability)* switch_ty,
403 ref $($mutability)* values,
405 self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
406 self.visit_ty(switch_ty);
407 for value in values {
408 self.visit_const_val(value, source_location);
410 for &target in targets {
411 self.visit_branch(block, target);
415 TerminatorKind::Resume |
416 TerminatorKind::Return |
417 TerminatorKind::Unreachable => {
420 TerminatorKind::Drop { ref $($mutability)* location,
423 self.visit_lvalue(location, LvalueContext::Drop, source_location);
424 self.visit_branch(block, target);
425 unwind.map(|t| self.visit_branch(block, t));
428 TerminatorKind::DropAndReplace { ref $($mutability)* location,
429 ref $($mutability)* value,
432 self.visit_lvalue(location, LvalueContext::Drop, source_location);
433 self.visit_operand(value, source_location);
434 self.visit_branch(block, target);
435 unwind.map(|t| self.visit_branch(block, t));
438 TerminatorKind::Call { ref $($mutability)* func,
439 ref $($mutability)* args,
440 ref $($mutability)* destination,
442 self.visit_operand(func, source_location);
444 self.visit_operand(arg, source_location);
446 if let Some((ref $($mutability)* destination, target)) = *destination {
447 self.visit_lvalue(destination, LvalueContext::Call, source_location);
448 self.visit_branch(block, target);
450 cleanup.map(|t| self.visit_branch(block, t));
453 TerminatorKind::Assert { ref $($mutability)* cond,
455 ref $($mutability)* msg,
458 self.visit_operand(cond, source_location);
459 self.visit_assert_message(msg, source_location);
460 self.visit_branch(block, target);
461 cleanup.map(|t| self.visit_branch(block, t));
466 fn super_assert_message(&mut self,
467 msg: & $($mutability)* AssertMessage<'tcx>,
468 location: Location) {
470 AssertMessage::BoundsCheck {
471 ref $($mutability)* len,
472 ref $($mutability)* index
474 self.visit_operand(len, location);
475 self.visit_operand(index, location);
477 AssertMessage::Math(_) => {}
481 fn super_rvalue(&mut self,
482 rvalue: & $($mutability)* Rvalue<'tcx>,
483 location: Location) {
485 Rvalue::Use(ref $($mutability)* operand) => {
486 self.visit_operand(operand, location);
489 Rvalue::Repeat(ref $($mutability)* value,
490 ref $($mutability)* typed_const_val) => {
491 self.visit_operand(value, location);
492 self.visit_typed_const_val(typed_const_val, location);
495 Rvalue::Ref(r, bk, ref $($mutability)* path) => {
496 self.visit_lvalue(path, LvalueContext::Borrow {
502 Rvalue::Len(ref $($mutability)* path) => {
503 self.visit_lvalue(path, LvalueContext::Inspect, location);
506 Rvalue::Cast(_cast_kind,
507 ref $($mutability)* operand,
508 ref $($mutability)* ty) => {
509 self.visit_operand(operand, location);
513 Rvalue::BinaryOp(_bin_op,
514 ref $($mutability)* lhs,
515 ref $($mutability)* rhs) |
516 Rvalue::CheckedBinaryOp(_bin_op,
517 ref $($mutability)* lhs,
518 ref $($mutability)* rhs) => {
519 self.visit_operand(lhs, location);
520 self.visit_operand(rhs, location);
523 Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
524 self.visit_operand(op, location);
527 Rvalue::Box(ref $($mutability)* ty) => {
531 Rvalue::Aggregate(ref $($mutability)* kind,
532 ref $($mutability)* operands) => {
534 AggregateKind::Vec => {
536 AggregateKind::Tuple => {
538 AggregateKind::Adt(_adt_def,
540 ref $($mutability)* substs,
541 _active_field_index) => {
542 self.visit_substs(substs);
544 AggregateKind::Closure(ref $($mutability)* def_id,
545 ref $($mutability)* closure_substs) => {
546 self.visit_def_id(def_id, location);
547 self.visit_closure_substs(closure_substs);
551 for operand in operands {
552 self.visit_operand(operand, location);
556 Rvalue::InlineAsm { ref $($mutability)* outputs,
557 ref $($mutability)* inputs,
559 for output in & $($mutability)* outputs[..] {
560 self.visit_lvalue(output, LvalueContext::Store, location);
562 for input in & $($mutability)* inputs[..] {
563 self.visit_operand(input, location);
569 fn super_operand(&mut self,
570 operand: & $($mutability)* Operand<'tcx>,
571 location: Location) {
573 Operand::Consume(ref $($mutability)* lvalue) => {
574 self.visit_lvalue(lvalue, LvalueContext::Consume, location);
576 Operand::Constant(ref $($mutability)* constant) => {
577 self.visit_constant(constant, location);
582 fn super_lvalue(&mut self,
583 lvalue: & $($mutability)* Lvalue<'tcx>,
584 context: LvalueContext<'tcx>,
585 location: Location) {
590 Lvalue::ReturnPointer => {
592 Lvalue::Static(ref $($mutability)* def_id) => {
593 self.visit_def_id(def_id, location);
595 Lvalue::Projection(ref $($mutability)* proj) => {
596 self.visit_projection(proj, context, location);
601 fn super_projection(&mut self,
602 proj: & $($mutability)* LvalueProjection<'tcx>,
603 context: LvalueContext,
604 location: Location) {
606 ref $($mutability)* base,
607 ref $($mutability)* elem,
609 let context = if context.is_mutating_use() {
610 LvalueContext::Projection(Mutability::Mut)
612 LvalueContext::Projection(Mutability::Not)
614 self.visit_lvalue(base, context, location);
615 self.visit_projection_elem(elem, context, location);
618 fn super_projection_elem(&mut self,
619 proj: & $($mutability)* LvalueElem<'tcx>,
620 _context: LvalueContext,
621 location: Location) {
623 ProjectionElem::Deref => {
625 ProjectionElem::Subslice { from: _, to: _ } => {
627 ProjectionElem::Field(_field, ref $($mutability)* ty) => {
630 ProjectionElem::Index(ref $($mutability)* operand) => {
631 self.visit_operand(operand, location);
633 ProjectionElem::ConstantIndex { offset: _,
637 ProjectionElem::Downcast(_adt_def, _variant_index) => {
642 fn super_var_decl(&mut self,
643 var_decl: & $($mutability)* VarDecl<'tcx>) {
647 ref $($mutability)* ty,
648 ref $($mutability)* source_info,
652 self.visit_source_info(source_info);
655 fn super_temp_decl(&mut self,
656 temp_decl: & $($mutability)* TempDecl<'tcx>) {
658 ref $($mutability)* ty,
664 fn super_arg_decl(&mut self,
665 arg_decl: & $($mutability)* ArgDecl<'tcx>) {
667 ref $($mutability)* ty,
675 fn super_visibility_scope(&mut self,
676 _scope: & $($mutability)* VisibilityScope) {
679 fn super_branch(&mut self,
681 _target: BasicBlock) {
684 fn super_constant(&mut self,
685 constant: & $($mutability)* Constant<'tcx>,
686 location: Location) {
688 ref $($mutability)* span,
689 ref $($mutability)* ty,
690 ref $($mutability)* literal,
693 self.visit_span(span);
695 self.visit_literal(literal, location);
698 fn super_typed_const_val(&mut self,
699 constant: & $($mutability)* TypedConstVal<'tcx>,
700 location: Location) {
702 ref $($mutability)* span,
703 ref $($mutability)* ty,
704 ref $($mutability)* value,
707 self.visit_span(span);
709 self.visit_const_usize(value, location);
712 fn super_literal(&mut self,
713 literal: & $($mutability)* Literal<'tcx>,
714 location: Location) {
716 Literal::Item { ref $($mutability)* def_id,
717 ref $($mutability)* substs } => {
718 self.visit_def_id(def_id, location);
719 self.visit_substs(substs);
721 Literal::Value { ref $($mutability)* value } => {
722 self.visit_const_val(value, location);
724 Literal::Promoted { index: _ } => {}
728 fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
731 fn super_span(&mut self, _span: & $($mutability)* Span) {
734 fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
736 ref $($mutability)* span,
737 ref $($mutability)* scope,
740 self.visit_span(span);
741 self.visit_visibility_scope(scope);
744 fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
747 fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
750 fn super_closure_substs(&mut self,
751 _substs: & $($mutability)* ClosureSubsts<'tcx>) {
754 fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
757 fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
760 // Convenience methods
762 fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
763 let basic_block = & $($mutability)* mir[location.block];
764 if basic_block.statements.len() == location.statement_index {
765 if let Some(ref $($mutability)* terminator) = basic_block.terminator {
766 self.visit_terminator(location.block, terminator, location)
769 let statement = & $($mutability)*
770 basic_block.statements[location.statement_index];
771 self.visit_statement(location.block, statement, location)
778 make_mir_visitor!(Visitor,);
779 make_mir_visitor!(MutVisitor,mut);
781 #[derive(Copy, Clone, Debug)]
782 pub enum LvalueContext<'tcx> {
783 // Appears as LHS of an assignment
792 // Being inspected in some way, like loading a len
796 Borrow { region: &'tcx Region, kind: BorrowKind },
798 // Used as base for another lvalue, e.g. `x` in `x.y`.
800 // The `Mutability` argument specifies whether the projection is being performed in order to
801 // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
807 // But not in these cases:
811 Projection(Mutability),
813 // Consumed as part of an operand
816 // Starting and ending a storage live range
821 impl<'tcx> LvalueContext<'tcx> {
822 /// Returns true if this lvalue context represents a drop.
823 pub fn is_drop(&self) -> bool {
825 LvalueContext::Drop => true,
830 /// Returns true if this lvalue context represents a storage live or storage dead marker.
831 pub fn is_storage_marker(&self) -> bool {
833 LvalueContext::StorageLive | LvalueContext::StorageDead => true,
838 /// Returns true if this lvalue context represents a storage live marker.
839 pub fn is_storage_live_marker(&self) -> bool {
841 LvalueContext::StorageLive => true,
846 /// Returns true if this lvalue context represents a storage dead marker.
847 pub fn is_storage_dead_marker(&self) -> bool {
849 LvalueContext::StorageDead => true,
854 /// Returns true if this lvalue context represents a use that potentially changes the value.
855 pub fn is_mutating_use(&self) -> bool {
857 LvalueContext::Store | LvalueContext::Call |
858 LvalueContext::Borrow { kind: BorrowKind::Mut, .. } |
859 LvalueContext::Projection(Mutability::Mut) |
860 LvalueContext::Drop => true,
861 LvalueContext::Inspect |
862 LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
863 LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
864 LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
865 LvalueContext::StorageLive | LvalueContext::StorageDead => false,
869 /// Returns true if this lvalue context represents a use that does not change the value.
870 pub fn is_nonmutating_use(&self) -> bool {
872 LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
873 LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
874 LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
875 LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
876 LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
877 LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false,
881 pub fn is_use(&self) -> bool {
882 self.is_mutating_use() || self.is_nonmutating_use()