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