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