]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
0e6c14af1ecfabfaf13eb7e0969214a2a642fbe5
[rust.git] / src / librustc / mir / visit.rs
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.
4 //
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.
10
11 use hir::def_id::DefId;
12 use ty::subst::Substs;
13 use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
14 use mir::*;
15 use rustc_const_math::ConstUsize;
16 use syntax_pos::Span;
17
18 // # The MIR Visitor
19 //
20 // ## Overview
21 //
22 // There are two visitors, one for immutable and one for mutable references,
23 // but both are generated by the following macro. The code is written according
24 // to the following conventions:
25 //
26 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
27 // - `visit_foo`, by default, calls `super_foo`
28 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
29 //
30 // This allows you as a user to override `visit_foo` for types are
31 // interested in, and invoke (within that method) call
32 // `self.super_foo` to get the default behavior. Just as in an OO
33 // language, you should never call `super` methods ordinarily except
34 // in that circumstance.
35 //
36 // For the most part, we do not destructure things external to the
37 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
38 // avoids duplication with other visitors like `TypeFoldable`.
39 //
40 // ## Updating
41 //
42 // The code is written in a very deliberate style intended to minimize
43 // the chance of things being overlooked. You'll notice that we always
44 // use pattern matching to reference fields and we ensure that all
45 // matches are exhaustive.
46 //
47 // For example, the `super_basic_block_data` method begins like this:
48 //
49 // ```rust
50 // fn super_basic_block_data(&mut self,
51 //                           block: BasicBlock,
52 //                           data: & $($mutability)* BasicBlockData<'tcx>) {
53 //     let BasicBlockData {
54 //         ref $($mutability)* statements,
55 //         ref $($mutability)* terminator,
56 //         is_cleanup: _
57 //     } = *data;
58 //
59 //     for statement in statements {
60 //         self.visit_statement(block, statement);
61 //     }
62 //
63 //     ...
64 // }
65 // ```
66 //
67 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
68 // rather than writing `data.statements` in the body. This is because if one
69 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
70 // and hence one will (hopefully) invoke the correct visit methods (if any).
71 //
72 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
73 // That means you never write `..` to skip over fields, nor do you write `_`
74 // to skip over variants in a `match`.
75 //
76 // The only place that `_` is acceptable is to match a field (or
77 // variant argument) that does not require visiting, as in
78 // `is_cleanup` above.
79
80 macro_rules! make_mir_visitor {
81     ($visitor_trait_name:ident, $($mutability:ident)*) => {
82         pub trait $visitor_trait_name<'tcx> {
83             // Override these, and call `self.super_xxx` to revert back to the
84             // default behavior.
85
86             fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
87                 self.super_mir(mir);
88             }
89
90             fn visit_basic_block_data(&mut self,
91                                       block: BasicBlock,
92                                       data: & $($mutability)* BasicBlockData<'tcx>) {
93                 self.super_basic_block_data(block, data);
94             }
95
96             fn visit_visibility_scope_data(&mut self,
97                                            scope_data: & $($mutability)* VisibilityScopeData) {
98                 self.super_visibility_scope_data(scope_data);
99             }
100
101             fn visit_statement(&mut self,
102                                block: BasicBlock,
103                                statement: & $($mutability)* Statement<'tcx>,
104                                location: Location) {
105                 self.super_statement(block, statement, location);
106             }
107
108             fn visit_assign(&mut self,
109                             block: BasicBlock,
110                             place: & $($mutability)* Place<'tcx>,
111                             rvalue: & $($mutability)* Rvalue<'tcx>,
112                             location: Location) {
113                 self.super_assign(block, place, rvalue, location);
114             }
115
116             fn visit_terminator(&mut self,
117                                 block: BasicBlock,
118                                 terminator: & $($mutability)* Terminator<'tcx>,
119                                 location: Location) {
120                 self.super_terminator(block, terminator, location);
121             }
122
123             fn visit_terminator_kind(&mut self,
124                                      block: BasicBlock,
125                                      kind: & $($mutability)* TerminatorKind<'tcx>,
126                                      location: Location) {
127                 self.super_terminator_kind(block, kind, location);
128             }
129
130             fn visit_assert_message(&mut self,
131                                     msg: & $($mutability)* AssertMessage<'tcx>,
132                                     location: Location) {
133                 self.super_assert_message(msg, location);
134             }
135
136             fn visit_rvalue(&mut self,
137                             rvalue: & $($mutability)* Rvalue<'tcx>,
138                             location: Location) {
139                 self.super_rvalue(rvalue, location);
140             }
141
142             fn visit_operand(&mut self,
143                              operand: & $($mutability)* Operand<'tcx>,
144                              location: Location) {
145                 self.super_operand(operand, location);
146             }
147
148             fn visit_place(&mut self,
149                             place: & $($mutability)* Place<'tcx>,
150                             context: PlaceContext<'tcx>,
151                             location: Location) {
152                 self.super_place(place, context, location);
153             }
154
155             fn visit_static(&mut self,
156                             static_: & $($mutability)* Static<'tcx>,
157                             context: PlaceContext<'tcx>,
158                             location: Location) {
159                 self.super_static(static_, context, location);
160             }
161
162             fn visit_projection(&mut self,
163                                 place: & $($mutability)* PlaceProjection<'tcx>,
164                                 context: PlaceContext<'tcx>,
165                                 location: Location) {
166                 self.super_projection(place, context, location);
167             }
168
169             fn visit_projection_elem(&mut self,
170                                      place: & $($mutability)* PlaceElem<'tcx>,
171                                      context: PlaceContext<'tcx>,
172                                      location: Location) {
173                 self.super_projection_elem(place, context, location);
174             }
175
176             fn visit_branch(&mut self,
177                             source: BasicBlock,
178                             target: BasicBlock) {
179                 self.super_branch(source, target);
180             }
181
182             fn visit_constant(&mut self,
183                               constant: & $($mutability)* Constant<'tcx>,
184                               location: Location) {
185                 self.super_constant(constant, location);
186             }
187
188             fn visit_literal(&mut self,
189                              literal: & $($mutability)* Literal<'tcx>,
190                              location: Location) {
191                 self.super_literal(literal, location);
192             }
193
194             fn visit_def_id(&mut self,
195                             def_id: & $($mutability)* DefId,
196                             _: Location) {
197                 self.super_def_id(def_id);
198             }
199
200             fn visit_span(&mut self,
201                           span: & $($mutability)* Span) {
202                 self.super_span(span);
203             }
204
205             fn visit_source_info(&mut self,
206                                  source_info: & $($mutability)* SourceInfo) {
207                 self.super_source_info(source_info);
208             }
209
210             fn visit_ty(&mut self,
211                         ty: & $($mutability)* Ty<'tcx>,
212                         _: TyContext) {
213                 self.super_ty(ty);
214             }
215
216             fn visit_region(&mut self,
217                             region: & $($mutability)* ty::Region<'tcx>,
218                             _: Location) {
219                 self.super_region(region);
220             }
221
222             fn visit_const(&mut self,
223                            constant: & $($mutability)* &'tcx ty::Const<'tcx>,
224                            _: Location) {
225                 self.super_const(constant);
226             }
227
228             fn visit_substs(&mut self,
229                             substs: & $($mutability)* &'tcx Substs<'tcx>,
230                             _: Location) {
231                 self.super_substs(substs);
232             }
233
234             fn visit_closure_substs(&mut self,
235                                     substs: & $($mutability)* ClosureSubsts<'tcx>,
236                                     _: Location) {
237                 self.super_closure_substs(substs);
238             }
239
240             fn visit_generator_interior(&mut self,
241                                     interior: & $($mutability)* GeneratorInterior<'tcx>,
242                                     _: Location) {
243                 self.super_generator_interior(interior);
244             }
245
246             fn visit_const_int(&mut self,
247                                const_int: &ConstInt,
248                                _: Location) {
249                 self.super_const_int(const_int);
250             }
251
252             fn visit_const_usize(&mut self,
253                                  const_usize: & $($mutability)* ConstUsize,
254                                  _: Location) {
255                 self.super_const_usize(const_usize);
256             }
257
258             fn visit_local_decl(&mut self,
259                                 local: Local,
260                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
261                 self.super_local_decl(local, local_decl);
262             }
263
264             fn visit_local(&mut self,
265                             _local: & $($mutability)* Local,
266                             _context: PlaceContext<'tcx>,
267                             _location: Location) {
268             }
269
270             fn visit_visibility_scope(&mut self,
271                                       scope: & $($mutability)* VisibilityScope) {
272                 self.super_visibility_scope(scope);
273             }
274
275             // The `super_xxx` methods comprise the default behavior and are
276             // not meant to be overridden.
277
278             fn super_mir(&mut self,
279                          mir: & $($mutability)* Mir<'tcx>) {
280                 // for best performance, we want to use an iterator rather
281                 // than a for-loop, to avoid calling Mir::invalidate for
282                 // each basic block.
283                 macro_rules! basic_blocks {
284                     (mut) => (mir.basic_blocks_mut().iter_enumerated_mut());
285                     () => (mir.basic_blocks().iter_enumerated());
286                 };
287                 for (bb, data) in basic_blocks!($($mutability)*) {
288                     self.visit_basic_block_data(bb, data);
289                 }
290
291                 for scope in &$($mutability)* mir.visibility_scopes {
292                     self.visit_visibility_scope_data(scope);
293                 }
294
295                 self.visit_ty(&$($mutability)* mir.return_ty(), TyContext::ReturnTy(SourceInfo {
296                     span: mir.span,
297                     scope: ARGUMENT_VISIBILITY_SCOPE,
298                 }));
299
300                 for local in mir.local_decls.indices() {
301                     self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
302                 }
303
304                 self.visit_span(&$($mutability)* mir.span);
305             }
306
307             fn super_basic_block_data(&mut self,
308                                       block: BasicBlock,
309                                       data: & $($mutability)* BasicBlockData<'tcx>) {
310                 let BasicBlockData {
311                     ref $($mutability)* statements,
312                     ref $($mutability)* terminator,
313                     is_cleanup: _
314                 } = *data;
315
316                 let mut index = 0;
317                 for statement in statements {
318                     let location = Location { block: block, statement_index: index };
319                     self.visit_statement(block, statement, location);
320                     index += 1;
321                 }
322
323                 if let Some(ref $($mutability)* terminator) = *terminator {
324                     let location = Location { block: block, statement_index: index };
325                     self.visit_terminator(block, terminator, location);
326                 }
327             }
328
329             fn super_visibility_scope_data(&mut self,
330                                            scope_data: & $($mutability)* VisibilityScopeData) {
331                 let VisibilityScopeData {
332                     ref $($mutability)* span,
333                     ref $($mutability)* parent_scope,
334                 } = *scope_data;
335
336                 self.visit_span(span);
337                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
338                     self.visit_visibility_scope(parent_scope);
339                 }
340             }
341
342             fn super_statement(&mut self,
343                                block: BasicBlock,
344                                statement: & $($mutability)* Statement<'tcx>,
345                                location: Location) {
346                 let Statement {
347                     ref $($mutability)* source_info,
348                     ref $($mutability)* kind,
349                 } = *statement;
350
351                 self.visit_source_info(source_info);
352                 match *kind {
353                     StatementKind::Assign(ref $($mutability)* place,
354                                           ref $($mutability)* rvalue) => {
355                         self.visit_assign(block, place, rvalue, location);
356                     }
357                     StatementKind::EndRegion(_) => {}
358                     StatementKind::Validate(_, ref $($mutability)* places) => {
359                         for operand in places {
360                             self.visit_place(& $($mutability)* operand.place,
361                                               PlaceContext::Validate, location);
362                             self.visit_ty(& $($mutability)* operand.ty,
363                                           TyContext::Location(location));
364                         }
365                     }
366                     StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
367                         self.visit_place(place, PlaceContext::Store, location);
368                     }
369                     StatementKind::StorageLive(ref $($mutability)* local) => {
370                         self.visit_local(local, PlaceContext::StorageLive, location);
371                     }
372                     StatementKind::StorageDead(ref $($mutability)* local) => {
373                         self.visit_local(local, PlaceContext::StorageDead, location);
374                     }
375                     StatementKind::InlineAsm { ref $($mutability)* outputs,
376                                                ref $($mutability)* inputs,
377                                                asm: _ } => {
378                         for output in & $($mutability)* outputs[..] {
379                             self.visit_place(output, PlaceContext::AsmOutput, location);
380                         }
381                         for input in & $($mutability)* inputs[..] {
382                             self.visit_operand(input, location);
383                         }
384                     }
385                     StatementKind::Nop => {}
386                 }
387             }
388
389             fn super_assign(&mut self,
390                             _block: BasicBlock,
391                             place: &$($mutability)* Place<'tcx>,
392                             rvalue: &$($mutability)* Rvalue<'tcx>,
393                             location: Location) {
394                 self.visit_place(place, PlaceContext::Store, location);
395                 self.visit_rvalue(rvalue, location);
396             }
397
398             fn super_terminator(&mut self,
399                                 block: BasicBlock,
400                                 terminator: &$($mutability)* Terminator<'tcx>,
401                                 location: Location) {
402                 let Terminator {
403                     ref $($mutability)* source_info,
404                     ref $($mutability)* kind,
405                 } = *terminator;
406
407                 self.visit_source_info(source_info);
408                 self.visit_terminator_kind(block, kind, location);
409             }
410
411             fn super_terminator_kind(&mut self,
412                                      block: BasicBlock,
413                                      kind: & $($mutability)* TerminatorKind<'tcx>,
414                                      source_location: Location) {
415                 match *kind {
416                     TerminatorKind::Goto { target } => {
417                         self.visit_branch(block, target);
418                     }
419
420                     TerminatorKind::SwitchInt { ref $($mutability)* discr,
421                                                 ref $($mutability)* switch_ty,
422                                                 ref values,
423                                                 ref targets } => {
424                         self.visit_operand(discr, source_location);
425                         self.visit_ty(switch_ty, TyContext::Location(source_location));
426                         for value in &values[..] {
427                             self.visit_const_int(value, source_location);
428                         }
429                         for &target in targets {
430                             self.visit_branch(block, target);
431                         }
432                     }
433
434                     TerminatorKind::Resume |
435                     TerminatorKind::Return |
436                     TerminatorKind::GeneratorDrop |
437                     TerminatorKind::Unreachable => {
438                     }
439
440                     TerminatorKind::Drop { ref $($mutability)* location,
441                                            target,
442                                            unwind } => {
443                         self.visit_place(location, PlaceContext::Drop, source_location);
444                         self.visit_branch(block, target);
445                         unwind.map(|t| self.visit_branch(block, t));
446                     }
447
448                     TerminatorKind::DropAndReplace { ref $($mutability)* location,
449                                                      ref $($mutability)* value,
450                                                      target,
451                                                      unwind } => {
452                         self.visit_place(location, PlaceContext::Drop, source_location);
453                         self.visit_operand(value, source_location);
454                         self.visit_branch(block, target);
455                         unwind.map(|t| self.visit_branch(block, t));
456                     }
457
458                     TerminatorKind::Call { ref $($mutability)* func,
459                                            ref $($mutability)* args,
460                                            ref $($mutability)* destination,
461                                            cleanup } => {
462                         self.visit_operand(func, source_location);
463                         for arg in args {
464                             self.visit_operand(arg, source_location);
465                         }
466                         if let Some((ref $($mutability)* destination, target)) = *destination {
467                             self.visit_place(destination, PlaceContext::Call, source_location);
468                             self.visit_branch(block, target);
469                         }
470                         cleanup.map(|t| self.visit_branch(block, t));
471                     }
472
473                     TerminatorKind::Assert { ref $($mutability)* cond,
474                                              expected: _,
475                                              ref $($mutability)* msg,
476                                              target,
477                                              cleanup } => {
478                         self.visit_operand(cond, source_location);
479                         self.visit_assert_message(msg, source_location);
480                         self.visit_branch(block, target);
481                         cleanup.map(|t| self.visit_branch(block, t));
482                     }
483
484                     TerminatorKind::Yield { ref $($mutability)* value,
485                                               resume,
486                                               drop } => {
487                         self.visit_operand(value, source_location);
488                         self.visit_branch(block, resume);
489                         drop.map(|t| self.visit_branch(block, t));
490
491                     }
492
493                     TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
494                         self.visit_branch(block, real_target);
495                         for target in imaginary_targets {
496                             self.visit_branch(block, *target);
497                         }
498                     }
499                 }
500             }
501
502             fn super_assert_message(&mut self,
503                                     msg: & $($mutability)* AssertMessage<'tcx>,
504                                     location: Location) {
505                 match *msg {
506                     AssertMessage::BoundsCheck {
507                         ref $($mutability)* len,
508                         ref $($mutability)* index
509                     } => {
510                         self.visit_operand(len, location);
511                         self.visit_operand(index, location);
512                     }
513                     AssertMessage::Math(_) => {},
514                     AssertMessage::GeneratorResumedAfterReturn => {},
515                     AssertMessage::GeneratorResumedAfterPanic => {},
516                 }
517             }
518
519             fn super_rvalue(&mut self,
520                             rvalue: & $($mutability)* Rvalue<'tcx>,
521                             location: Location) {
522                 match *rvalue {
523                     Rvalue::Use(ref $($mutability)* operand) => {
524                         self.visit_operand(operand, location);
525                     }
526
527                     Rvalue::Repeat(ref $($mutability)* value,
528                                    ref $($mutability)* length) => {
529                         self.visit_operand(value, location);
530                         self.visit_const_usize(length, location);
531                     }
532
533                     Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
534                         self.visit_region(r, location);
535                         self.visit_place(path, PlaceContext::Borrow {
536                             region: *r,
537                             kind: bk
538                         }, location);
539                     }
540
541                     Rvalue::Len(ref $($mutability)* path) => {
542                         self.visit_place(path, PlaceContext::Inspect, location);
543                     }
544
545                     Rvalue::Cast(_cast_kind,
546                                  ref $($mutability)* operand,
547                                  ref $($mutability)* ty) => {
548                         self.visit_operand(operand, location);
549                         self.visit_ty(ty, TyContext::Location(location));
550                     }
551
552                     Rvalue::BinaryOp(_bin_op,
553                                      ref $($mutability)* lhs,
554                                      ref $($mutability)* rhs) |
555                     Rvalue::CheckedBinaryOp(_bin_op,
556                                      ref $($mutability)* lhs,
557                                      ref $($mutability)* rhs) => {
558                         self.visit_operand(lhs, location);
559                         self.visit_operand(rhs, location);
560                     }
561
562                     Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
563                         self.visit_operand(op, location);
564                     }
565
566                     Rvalue::Discriminant(ref $($mutability)* place) => {
567                         self.visit_place(place, PlaceContext::Inspect, location);
568                     }
569
570                     Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
571                         self.visit_ty(ty, TyContext::Location(location));
572                     }
573
574                     Rvalue::Aggregate(ref $($mutability)* kind,
575                                       ref $($mutability)* operands) => {
576                         let kind = &$($mutability)* **kind;
577                         match *kind {
578                             AggregateKind::Array(ref $($mutability)* ty) => {
579                                 self.visit_ty(ty, TyContext::Location(location));
580                             }
581                             AggregateKind::Tuple => {
582                             }
583                             AggregateKind::Adt(_adt_def,
584                                                _variant_index,
585                                                ref $($mutability)* substs,
586                                                _active_field_index) => {
587                                 self.visit_substs(substs, location);
588                             }
589                             AggregateKind::Closure(ref $($mutability)* def_id,
590                                                    ref $($mutability)* closure_substs) => {
591                                 self.visit_def_id(def_id, location);
592                                 self.visit_closure_substs(closure_substs, location);
593                             }
594                             AggregateKind::Generator(ref $($mutability)* def_id,
595                                                    ref $($mutability)* closure_substs,
596                                                    ref $($mutability)* interior) => {
597                                 self.visit_def_id(def_id, location);
598                                 self.visit_closure_substs(closure_substs, location);
599                                 self.visit_generator_interior(interior, location);
600                             }
601                         }
602
603                         for operand in operands {
604                             self.visit_operand(operand, location);
605                         }
606                     }
607                 }
608             }
609
610             fn super_operand(&mut self,
611                              operand: & $($mutability)* Operand<'tcx>,
612                              location: Location) {
613                 match *operand {
614                     Operand::Copy(ref $($mutability)* place) => {
615                         self.visit_place(place, PlaceContext::Copy, location);
616                     }
617                     Operand::Move(ref $($mutability)* place) => {
618                         self.visit_place(place, PlaceContext::Move, location);
619                     }
620                     Operand::Constant(ref $($mutability)* constant) => {
621                         self.visit_constant(constant, location);
622                     }
623                 }
624             }
625
626             fn super_place(&mut self,
627                             place: & $($mutability)* Place<'tcx>,
628                             context: PlaceContext<'tcx>,
629                             location: Location) {
630                 match *place {
631                     Place::Local(ref $($mutability)* local) => {
632                         self.visit_local(local, context, location);
633                     }
634                     Place::Static(ref $($mutability)* static_) => {
635                         self.visit_static(static_, context, location);
636                     }
637                     Place::Projection(ref $($mutability)* proj) => {
638                         self.visit_projection(proj, context, location);
639                     }
640                 }
641             }
642
643             fn super_static(&mut self,
644                             static_: & $($mutability)* Static<'tcx>,
645                             _context: PlaceContext<'tcx>,
646                             location: Location) {
647                 let Static {
648                     ref $($mutability)* def_id,
649                     ref $($mutability)* ty,
650                 } = *static_;
651                 self.visit_def_id(def_id, location);
652                 self.visit_ty(ty, TyContext::Location(location));
653             }
654
655             fn super_projection(&mut self,
656                                 proj: & $($mutability)* PlaceProjection<'tcx>,
657                                 context: PlaceContext<'tcx>,
658                                 location: Location) {
659                 let Projection {
660                     ref $($mutability)* base,
661                     ref $($mutability)* elem,
662                 } = *proj;
663                 let context = if context.is_mutating_use() {
664                     PlaceContext::Projection(Mutability::Mut)
665                 } else {
666                     PlaceContext::Projection(Mutability::Not)
667                 };
668                 self.visit_place(base, context, location);
669                 self.visit_projection_elem(elem, context, location);
670             }
671
672             fn super_projection_elem(&mut self,
673                                      proj: & $($mutability)* PlaceElem<'tcx>,
674                                      _context: PlaceContext<'tcx>,
675                                      location: Location) {
676                 match *proj {
677                     ProjectionElem::Deref => {
678                     }
679                     ProjectionElem::Subslice { from: _, to: _ } => {
680                     }
681                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
682                         self.visit_ty(ty, TyContext::Location(location));
683                     }
684                     ProjectionElem::Index(ref $($mutability)* local) => {
685                         self.visit_local(local, PlaceContext::Copy, location);
686                     }
687                     ProjectionElem::ConstantIndex { offset: _,
688                                                     min_length: _,
689                                                     from_end: _ } => {
690                     }
691                     ProjectionElem::Downcast(_adt_def, _variant_index) => {
692                     }
693                 }
694             }
695
696             fn super_local_decl(&mut self,
697                                 local: Local,
698                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
699                 let LocalDecl {
700                     mutability: _,
701                     ref $($mutability)* ty,
702                     name: _,
703                     ref $($mutability)* source_info,
704                     internal: _,
705                     ref $($mutability)* lexical_scope,
706                     is_user_variable: _,
707                 } = *local_decl;
708
709                 self.visit_ty(ty, TyContext::LocalDecl {
710                     local,
711                     source_info: *source_info,
712                 });
713                 self.visit_source_info(source_info);
714                 self.visit_visibility_scope(lexical_scope);
715             }
716
717             fn super_visibility_scope(&mut self,
718                                       _scope: & $($mutability)* VisibilityScope) {
719             }
720
721             fn super_branch(&mut self,
722                             _source: BasicBlock,
723                             _target: BasicBlock) {
724             }
725
726             fn super_constant(&mut self,
727                               constant: & $($mutability)* Constant<'tcx>,
728                               location: Location) {
729                 let Constant {
730                     ref $($mutability)* span,
731                     ref $($mutability)* ty,
732                     ref $($mutability)* literal,
733                 } = *constant;
734
735                 self.visit_span(span);
736                 self.visit_ty(ty, TyContext::Location(location));
737                 self.visit_literal(literal, location);
738             }
739
740             fn super_literal(&mut self,
741                              literal: & $($mutability)* Literal<'tcx>,
742                              location: Location) {
743                 match *literal {
744                     Literal::Value { ref $($mutability)* value } => {
745                         self.visit_const(value, location);
746                     }
747                     Literal::Promoted { index: _ } => {}
748                 }
749             }
750
751             fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
752             }
753
754             fn super_span(&mut self, _span: & $($mutability)* Span) {
755             }
756
757             fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
758                 let SourceInfo {
759                     ref $($mutability)* span,
760                     ref $($mutability)* scope,
761                 } = *source_info;
762
763                 self.visit_span(span);
764                 self.visit_visibility_scope(scope);
765             }
766
767             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
768             }
769
770             fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) {
771             }
772
773             fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) {
774             }
775
776             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
777             }
778
779             fn super_generator_interior(&mut self,
780                                     _interior: & $($mutability)* GeneratorInterior<'tcx>) {
781             }
782
783             fn super_closure_substs(&mut self,
784                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
785             }
786
787             fn super_const_int(&mut self, _const_int: &ConstInt) {
788             }
789
790             fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
791             }
792
793             // Convenience methods
794
795             fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
796                 let basic_block = & $($mutability)* mir[location.block];
797                 if basic_block.statements.len() == location.statement_index {
798                     if let Some(ref $($mutability)* terminator) = basic_block.terminator {
799                         self.visit_terminator(location.block, terminator, location)
800                     }
801                 } else {
802                     let statement = & $($mutability)*
803                         basic_block.statements[location.statement_index];
804                     self.visit_statement(location.block, statement, location)
805                 }
806             }
807         }
808     }
809 }
810
811 make_mir_visitor!(Visitor,);
812 make_mir_visitor!(MutVisitor,mut);
813
814 pub trait MirVisitable<'tcx> {
815     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
816 }
817
818 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
819     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
820     {
821         visitor.visit_statement(location.block, self, location)
822     }
823 }
824
825 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
826     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
827     {
828         visitor.visit_terminator(location.block, self, location)
829     }
830 }
831
832 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
833     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
834     {
835         visitor.visit_terminator(location.block, self.as_ref().unwrap(), location)
836     }
837 }
838
839 /// Extra information passed to `visit_ty` and friends to give context
840 /// about where the type etc appears.
841 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
842 pub enum TyContext {
843     LocalDecl {
844         /// The index of the local variable we are visiting.
845         local: Local,
846
847         /// The source location where this local variable was declared.
848         source_info: SourceInfo,
849     },
850
851     /// The return type of the function.
852     ReturnTy(SourceInfo),
853
854     /// A type found at some location.
855     Location(Location),
856 }
857
858 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
859 pub enum PlaceContext<'tcx> {
860     // Appears as LHS of an assignment
861     Store,
862
863     // Can often be treated as a Store, but needs to be separate because
864     // ASM is allowed to read outputs as well, so a Store-AsmOutput sequence
865     // cannot be simplified the way a Store-Store can be.
866     AsmOutput,
867
868     // Dest of a call
869     Call,
870
871     // Being dropped
872     Drop,
873
874     // Being inspected in some way, like loading a len
875     Inspect,
876
877     // Being borrowed
878     Borrow { region: Region<'tcx>, kind: BorrowKind },
879
880     // Used as base for another place, e.g. `x` in `x.y`.
881     //
882     // The `Mutability` argument specifies whether the projection is being performed in order to
883     // (potentially) mutate the place. For example, the projection `x.y` is marked as a mutation
884     // in these cases:
885     //
886     //     x.y = ...;
887     //     f(&mut x.y);
888     //
889     // But not in these cases:
890     //
891     //     z = x.y;
892     //     f(&x.y);
893     Projection(Mutability),
894
895     // Consumed as part of an operand
896     Copy,
897     Move,
898
899     // Starting and ending a storage live range
900     StorageLive,
901     StorageDead,
902
903     // Validation command
904     Validate,
905 }
906
907 impl<'tcx> PlaceContext<'tcx> {
908     /// Returns true if this place context represents a drop.
909     pub fn is_drop(&self) -> bool {
910         match *self {
911             PlaceContext::Drop => true,
912             _ => false,
913         }
914     }
915
916     /// Returns true if this place context represents a storage live or storage dead marker.
917     pub fn is_storage_marker(&self) -> bool {
918         match *self {
919             PlaceContext::StorageLive | PlaceContext::StorageDead => true,
920             _ => false,
921         }
922     }
923
924     /// Returns true if this place context represents a storage live marker.
925     pub fn is_storage_live_marker(&self) -> bool {
926         match *self {
927             PlaceContext::StorageLive => true,
928             _ => false,
929         }
930     }
931
932     /// Returns true if this place context represents a storage dead marker.
933     pub fn is_storage_dead_marker(&self) -> bool {
934         match *self {
935             PlaceContext::StorageDead => true,
936             _ => false,
937         }
938     }
939
940     /// Returns true if this place context represents a use that potentially changes the value.
941     pub fn is_mutating_use(&self) -> bool {
942         match *self {
943             PlaceContext::Store | PlaceContext::AsmOutput | PlaceContext::Call |
944             PlaceContext::Borrow { kind: BorrowKind::Mut, .. } |
945             PlaceContext::Projection(Mutability::Mut) |
946             PlaceContext::Drop => true,
947             PlaceContext::Inspect |
948             PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
949             PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
950             PlaceContext::Projection(Mutability::Not) |
951             PlaceContext::Copy | PlaceContext::Move |
952             PlaceContext::StorageLive | PlaceContext::StorageDead |
953             PlaceContext::Validate => false,
954         }
955     }
956
957     /// Returns true if this place context represents a use that does not change the value.
958     pub fn is_nonmutating_use(&self) -> bool {
959         match *self {
960             PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
961             PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
962             PlaceContext::Projection(Mutability::Not) |
963             PlaceContext::Copy | PlaceContext::Move => true,
964             PlaceContext::Borrow { kind: BorrowKind::Mut, .. } | PlaceContext::Store |
965             PlaceContext::AsmOutput |
966             PlaceContext::Call | PlaceContext::Projection(Mutability::Mut) |
967             PlaceContext::Drop | PlaceContext::StorageLive | PlaceContext::StorageDead |
968             PlaceContext::Validate => false,
969         }
970     }
971
972     pub fn is_use(&self) -> bool {
973         self.is_mutating_use() || self.is_nonmutating_use()
974     }
975 }