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