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