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