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