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
)* parent_scope
,
304 if let Some(ref $
($mutability
)* parent_scope
) = *parent_scope
{
305 self.visit_scope_id(parent_scope
);
309 fn super_statement(&mut self,
311 statement
: & $
($mutability
)* Statement
<'tcx
>) {
313 ref $
($mutability
)* span
,
314 ref $
($mutability
)* scope
,
315 ref $
($mutability
)* kind
,
318 self.visit_span(span
);
319 self.visit_scope_id(scope
);
321 StatementKind
::Assign(ref $
($mutability
)* lvalue
,
322 ref $
($mutability
)* rvalue
) => {
323 self.visit_assign(block
, lvalue
, rvalue
);
328 fn super_assign(&mut self,
330 lvalue
: &$
($mutability
)* Lvalue
<'tcx
>,
331 rvalue
: &$
($mutability
)* Rvalue
<'tcx
>) {
332 self.visit_lvalue(lvalue
, LvalueContext
::Store
);
333 self.visit_rvalue(rvalue
);
336 fn super_terminator(&mut self,
338 terminator
: &$
($mutability
)* Terminator
<'tcx
>) {
340 ref $
($mutability
)* span
,
341 ref $
($mutability
)* scope
,
342 ref $
($mutability
)* kind
,
345 self.visit_span(span
);
346 self.visit_scope_id(scope
);
347 self.visit_terminator_kind(block
, kind
);
350 fn super_terminator_kind(&mut self,
352 kind
: & $
($mutability
)* TerminatorKind
<'tcx
>) {
354 TerminatorKind
::Goto { target }
=> {
355 self.visit_branch(block
, target
);
358 TerminatorKind
::If
{ ref $
($mutability
)* cond
,
359 ref $
($mutability
)* targets
} => {
360 self.visit_operand(cond
);
361 for &target
in targets
.as_slice() {
362 self.visit_branch(block
, target
);
366 TerminatorKind
::Switch
{ ref $
($mutability
)* discr
,
369 self.visit_lvalue(discr
, LvalueContext
::Inspect
);
370 for &target
in targets
{
371 self.visit_branch(block
, target
);
375 TerminatorKind
::SwitchInt
{ ref $
($mutability
)* discr
,
376 ref $
($mutability
)* switch_ty
,
377 ref $
($mutability
)* values
,
379 self.visit_lvalue(discr
, LvalueContext
::Inspect
);
380 self.visit_ty(switch_ty
);
381 for value
in values
{
382 self.visit_const_val(value
);
384 for &target
in targets
{
385 self.visit_branch(block
, target
);
389 TerminatorKind
::Resume
|
390 TerminatorKind
::Return
=> {
393 TerminatorKind
::Drop
{ ref $
($mutability
)* value
,
396 self.visit_lvalue(value
, LvalueContext
::Drop
);
397 self.visit_branch(block
, target
);
398 unwind
.map(|t
| self.visit_branch(block
, t
));
401 TerminatorKind
::Call
{ ref $
($mutability
)* func
,
402 ref $
($mutability
)* args
,
403 ref $
($mutability
)* destination
,
405 self.visit_operand(func
);
407 self.visit_operand(arg
);
409 if let Some((ref $
($mutability
)* destination
, target
)) = *destination
{
410 self.visit_lvalue(destination
, LvalueContext
::Call
);
411 self.visit_branch(block
, target
);
413 cleanup
.map(|t
| self.visit_branch(block
, t
));
418 fn super_rvalue(&mut self,
419 rvalue
: & $
($mutability
)* Rvalue
<'tcx
>) {
421 Rvalue
::Use(ref $
($mutability
)* operand
) => {
422 self.visit_operand(operand
);
425 Rvalue
::Repeat(ref $
($mutability
)* value
,
426 ref $
($mutability
)* typed_const_val
) => {
427 self.visit_operand(value
);
428 self.visit_typed_const_val(typed_const_val
);
431 Rvalue
::Ref(r
, bk
, ref $
($mutability
)* path
) => {
432 self.visit_lvalue(path
, LvalueContext
::Borrow
{
438 Rvalue
::Len(ref $
($mutability
)* path
) => {
439 self.visit_lvalue(path
, LvalueContext
::Inspect
);
442 Rvalue
::Cast(_cast_kind
,
443 ref $
($mutability
)* operand
,
444 ref $
($mutability
)* ty
) => {
445 self.visit_operand(operand
);
449 Rvalue
::BinaryOp(_bin_op
,
450 ref $
($mutability
)* lhs
,
451 ref $
($mutability
)* rhs
) => {
452 self.visit_operand(lhs
);
453 self.visit_operand(rhs
);
456 Rvalue
::UnaryOp(_un_op
, ref $
($mutability
)* op
) => {
457 self.visit_operand(op
);
460 Rvalue
::Box(ref $
($mutability
)* ty
) => {
464 Rvalue
::Aggregate(ref $
($mutability
)* kind
,
465 ref $
($mutability
)* operands
) => {
467 AggregateKind
::Vec
=> {
469 AggregateKind
::Tuple
=> {
471 AggregateKind
::Adt(_adt_def
,
473 ref $
($mutability
)* substs
) => {
474 self.visit_substs(substs
);
476 AggregateKind
::Closure(ref $
($mutability
)* def_id
,
477 ref $
($mutability
)* closure_substs
) => {
478 self.visit_def_id(def_id
);
479 self.visit_closure_substs(closure_substs
);
483 for operand
in operands
{
484 self.visit_operand(operand
);
488 Rvalue
::Slice
{ ref $
($mutability
)* input
,
491 self.visit_lvalue(input
, LvalueContext
::Slice
{
492 from_start
: from_start
,
497 Rvalue
::InlineAsm
{ ref $
($mutability
)* outputs
,
498 ref $
($mutability
)* inputs
,
500 for output
in & $
($mutability
)* outputs
[..] {
501 self.visit_lvalue(output
, LvalueContext
::Store
);
503 for input
in & $
($mutability
)* inputs
[..] {
504 self.visit_operand(input
);
510 fn super_operand(&mut self,
511 operand
: & $
($mutability
)* Operand
<'tcx
>) {
513 Operand
::Consume(ref $
($mutability
)* lvalue
) => {
514 self.visit_lvalue(lvalue
, LvalueContext
::Consume
);
516 Operand
::Constant(ref $
($mutability
)* constant
) => {
517 self.visit_constant(constant
);
522 fn super_lvalue(&mut self,
523 lvalue
: & $
($mutability
)* Lvalue
<'tcx
>,
524 context
: LvalueContext
) {
529 Lvalue
::ReturnPointer
=> {
531 Lvalue
::Static(ref $
($mutability
)* def_id
) => {
532 self.visit_def_id(def_id
);
534 Lvalue
::Projection(ref $
($mutability
)* proj
) => {
535 self.visit_projection(proj
, context
);
540 fn super_projection(&mut self,
541 proj
: & $
($mutability
)* LvalueProjection
<'tcx
>,
542 context
: LvalueContext
) {
544 ref $
($mutability
)* base
,
545 ref $
($mutability
)* elem
,
547 self.visit_lvalue(base
, LvalueContext
::Projection
);
548 self.visit_projection_elem(elem
, context
);
551 fn super_projection_elem(&mut self,
552 proj
: & $
($mutability
)* LvalueElem
<'tcx
>,
553 _context
: LvalueContext
) {
555 ProjectionElem
::Deref
=> {
557 ProjectionElem
::Field(_field
, ref $
($mutability
)* ty
) => {
560 ProjectionElem
::Index(ref $
($mutability
)* operand
) => {
561 self.visit_operand(operand
);
563 ProjectionElem
::ConstantIndex
{ offset
: _
,
567 ProjectionElem
::Downcast(_adt_def
, _variant_index
) => {
572 fn super_var_decl(&mut self,
573 var_decl
: & $
($mutability
)* VarDecl
<'tcx
>) {
577 ref $
($mutability
)* ty
,
578 ref $
($mutability
)* scope
,
579 ref $
($mutability
)* span
,
583 self.visit_scope_id(scope
);
584 self.visit_span(span
);
587 fn super_temp_decl(&mut self,
588 temp_decl
: & $
($mutability
)* TempDecl
<'tcx
>) {
590 ref $
($mutability
)* ty
,
596 fn super_arg_decl(&mut self,
597 arg_decl
: & $
($mutability
)* ArgDecl
<'tcx
>) {
599 ref $
($mutability
)* ty
,
606 fn super_scope_id(&mut self,
607 _scope_id
: & $
($mutability
)* ScopeId
) {
610 fn super_branch(&mut self,
612 _target
: BasicBlock
) {
615 fn super_constant(&mut self,
616 constant
: & $
($mutability
)* Constant
<'tcx
>) {
618 ref $
($mutability
)* span
,
619 ref $
($mutability
)* ty
,
620 ref $
($mutability
)* literal
,
623 self.visit_span(span
);
625 self.visit_literal(literal
);
628 fn super_typed_const_val(&mut self,
629 constant
: & $
($mutability
)* TypedConstVal
<'tcx
>) {
631 ref $
($mutability
)* span
,
632 ref $
($mutability
)* ty
,
633 ref $
($mutability
)* value
,
636 self.visit_span(span
);
638 self.visit_const_usize(value
);
641 fn super_literal(&mut self,
642 literal
: & $
($mutability
)* Literal
<'tcx
>) {
644 Literal
::Item
{ ref $
($mutability
)* def_id
,
645 ref $
($mutability
)* substs
} => {
646 self.visit_def_id(def_id
);
647 self.visit_substs(substs
);
649 Literal
::Value { ref $($mutability)* value }
=> {
650 self.visit_const_val(value
);
655 fn super_def_id(&mut self, _def_id
: & $
($mutability
)* DefId
) {
658 fn super_span(&mut self, _span
: & $
($mutability
)* Span
) {
661 fn super_fn_output(&mut self, fn_output
: & $
($mutability
)* FnOutput
<'tcx
>) {
663 FnOutput
::FnConverging(ref $
($mutability
)* ty
) => {
666 FnOutput
::FnDiverging
=> {
671 fn super_ty(&mut self, _ty
: & $
($mutability
)* Ty
<'tcx
>) {
674 fn super_substs(&mut self, _substs
: & $
($mutability
)* &'tcx Substs
<'tcx
>) {
677 fn super_closure_substs(&mut self,
678 _substs
: & $
($mutability
)* &'tcx ClosureSubsts
<'tcx
>) {
681 fn super_const_val(&mut self, _substs
: & $
($mutability
)* ConstVal
) {
684 fn super_const_usize(&mut self, _substs
: & $
($mutability
)* ConstUsize
) {
690 make_mir_visitor
!(Visitor
,);
691 make_mir_visitor
!(MutVisitor
,mut);
693 #[derive(Copy, Clone, Debug)]
694 pub enum LvalueContext
{
695 // Appears as LHS of an assignment
704 // Being inspected in some way, like loading a len
708 Borrow { region: Region, kind: BorrowKind }
,
710 // Being sliced -- this should be same as being borrowed, probably
711 Slice { from_start: usize, from_end: usize }
,
713 // Used as base for another lvalue, e.g. `x` in `x.y`
716 // Consumed as part of an operand