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