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