]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/visit.rs
Rollup merge of #99154 - rosehuds:master, r=cjgillot
[rust.git] / compiler / rustc_middle / src / mir / visit.rs
1 //! # The MIR Visitor
2 //!
3 //! ## Overview
4 //!
5 //! There are two visitors, one for immutable and one for mutable references,
6 //! but both are generated by the following macro. The code is written according
7 //! to the following conventions:
8 //!
9 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
10 //! - `visit_foo`, by default, calls `super_foo`
11 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
12 //!
13 //! This allows you as a user to override `visit_foo` for types are
14 //! interested in, and invoke (within that method) call
15 //! `self.super_foo` to get the default behavior. Just as in an OO
16 //! language, you should never call `super` methods ordinarily except
17 //! in that circumstance.
18 //!
19 //! For the most part, we do not destructure things external to the
20 //! MIR, e.g., types, spans, etc, but simply visit them and stop. This
21 //! avoids duplication with other visitors like `TypeFoldable`.
22 //!
23 //! ## Updating
24 //!
25 //! The code is written in a very deliberate style intended to minimize
26 //! the chance of things being overlooked. You'll notice that we always
27 //! use pattern matching to reference fields and we ensure that all
28 //! matches are exhaustive.
29 //!
30 //! For example, the `super_basic_block_data` method begins like this:
31 //!
32 //! ```ignore (pseudo-rust)
33 //! fn super_basic_block_data(
34 //!     &mut self,
35 //!     block: BasicBlock,
36 //!     data: & $($mutability)? BasicBlockData<'tcx>
37 //! ) {
38 //!     let BasicBlockData {
39 //!         statements,
40 //!         terminator,
41 //!         is_cleanup: _
42 //!     } = *data;
43 //!
44 //!     for statement in statements {
45 //!         self.visit_statement(block, statement);
46 //!     }
47 //!
48 //!     ...
49 //! }
50 //! ```
51 //!
52 //! Here we used `let BasicBlockData { <fields> } = *data` deliberately,
53 //! rather than writing `data.statements` in the body. This is because if one
54 //! adds a new field to `BasicBlockData`, one will be forced to revise this code,
55 //! and hence one will (hopefully) invoke the correct visit methods (if any).
56 //!
57 //! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
58 //! That means you never write `..` to skip over fields, nor do you write `_`
59 //! to skip over variants in a `match`.
60 //!
61 //! The only place that `_` is acceptable is to match a field (or
62 //! variant argument) that does not require visiting, as in
63 //! `is_cleanup` above.
64
65 use crate::mir::*;
66 use crate::ty::subst::SubstsRef;
67 use crate::ty::{CanonicalUserTypeAnnotation, Ty};
68 use rustc_span::Span;
69
70 macro_rules! make_mir_visitor {
71     ($visitor_trait_name:ident, $($mutability:ident)?) => {
72         pub trait $visitor_trait_name<'tcx> {
73             // Override these, and call `self.super_xxx` to revert back to the
74             // default behavior.
75
76             fn visit_body(
77                 &mut self,
78                 body: &$($mutability)? Body<'tcx>,
79             ) {
80                 self.super_body(body);
81             }
82
83             fn visit_basic_block_data(
84                 &mut self,
85                 block: BasicBlock,
86                 data: & $($mutability)? BasicBlockData<'tcx>,
87             ) {
88                 self.super_basic_block_data(block, data);
89             }
90
91             fn visit_source_scope_data(
92                 &mut self,
93                 scope_data: & $($mutability)? SourceScopeData<'tcx>,
94             ) {
95                 self.super_source_scope_data(scope_data);
96             }
97
98             fn visit_statement(
99                 &mut self,
100                 statement: & $($mutability)? Statement<'tcx>,
101                 location: Location,
102             ) {
103                 self.super_statement(statement, location);
104             }
105
106             fn visit_assign(
107                 &mut self,
108                 place: & $($mutability)? Place<'tcx>,
109                 rvalue: & $($mutability)? Rvalue<'tcx>,
110                 location: Location,
111             ) {
112                 self.super_assign(place, rvalue, location);
113             }
114
115             fn visit_terminator(
116                 &mut self,
117                 terminator: & $($mutability)? Terminator<'tcx>,
118                 location: Location,
119             ) {
120                 self.super_terminator(terminator, location);
121             }
122
123             fn visit_assert_message(
124                 &mut self,
125                 msg: & $($mutability)? AssertMessage<'tcx>,
126                 location: Location,
127             ) {
128                 self.super_assert_message(msg, location);
129             }
130
131             fn visit_rvalue(
132                 &mut self,
133                 rvalue: & $($mutability)? Rvalue<'tcx>,
134                 location: Location,
135             ) {
136                 self.super_rvalue(rvalue, location);
137             }
138
139             fn visit_operand(
140                 &mut self,
141                 operand: & $($mutability)? Operand<'tcx>,
142                 location: Location,
143             ) {
144                 self.super_operand(operand, location);
145             }
146
147             fn visit_ascribe_user_ty(
148                 &mut self,
149                 place: & $($mutability)? Place<'tcx>,
150                 variance: $(& $mutability)? ty::Variance,
151                 user_ty: & $($mutability)? UserTypeProjection,
152                 location: Location,
153             ) {
154                 self.super_ascribe_user_ty(place, variance, user_ty, location);
155             }
156
157             fn visit_coverage(
158                 &mut self,
159                 coverage: & $($mutability)? Coverage,
160                 location: Location,
161             ) {
162                 self.super_coverage(coverage, location);
163             }
164
165             fn visit_retag(
166                 &mut self,
167                 kind: $(& $mutability)? RetagKind,
168                 place: & $($mutability)? Place<'tcx>,
169                 location: Location,
170             ) {
171                 self.super_retag(kind, place, location);
172             }
173
174             fn visit_place(
175                 &mut self,
176                 place: & $($mutability)? Place<'tcx>,
177                 context: PlaceContext,
178                 location: Location,
179             ) {
180                 self.super_place(place, context, location);
181             }
182
183             visit_place_fns!($($mutability)?);
184
185             fn visit_constant(
186                 &mut self,
187                 constant: & $($mutability)? Constant<'tcx>,
188                 location: Location,
189             ) {
190                 self.super_constant(constant, location);
191             }
192
193             fn visit_span(
194                 &mut self,
195                 span: $(& $mutability)? Span,
196             ) {
197                 self.super_span(span);
198             }
199
200             fn visit_source_info(
201                 &mut self,
202                 source_info: & $($mutability)? SourceInfo,
203             ) {
204                 self.super_source_info(source_info);
205             }
206
207             fn visit_ty(
208                 &mut self,
209                 ty: $(& $mutability)? Ty<'tcx>,
210                 _: TyContext,
211             ) {
212                 self.super_ty(ty);
213             }
214
215             fn visit_user_type_projection(
216                 &mut self,
217                 ty: & $($mutability)? UserTypeProjection,
218             ) {
219                 self.super_user_type_projection(ty);
220             }
221
222             fn visit_user_type_annotation(
223                 &mut self,
224                 index: UserTypeAnnotationIndex,
225                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
226             ) {
227                 self.super_user_type_annotation(index, ty);
228             }
229
230             fn visit_region(
231                 &mut self,
232                 region: $(& $mutability)? ty::Region<'tcx>,
233                 _: Location,
234             ) {
235                 self.super_region(region);
236             }
237
238             fn visit_const(
239                 &mut self,
240                 constant: $(& $mutability)? ty::Const<'tcx>,
241                 _: Location,
242             ) {
243                 self.super_const(constant);
244             }
245
246             fn visit_substs(
247                 &mut self,
248                 substs: & $($mutability)? SubstsRef<'tcx>,
249                 _: Location,
250             ) {
251                 self.super_substs(substs);
252             }
253
254             fn visit_local_decl(
255                 &mut self,
256                 local: Local,
257                 local_decl: & $($mutability)? LocalDecl<'tcx>,
258             ) {
259                 self.super_local_decl(local, local_decl);
260             }
261
262             fn visit_var_debug_info(
263                 &mut self,
264                 var_debug_info: & $($mutability)* VarDebugInfo<'tcx>,
265             ) {
266                 self.super_var_debug_info(var_debug_info);
267             }
268
269             fn visit_local(
270                 &mut self,
271                 _local: $(& $mutability)? Local,
272                 _context: PlaceContext,
273                 _location: Location,
274             ) {}
275
276             fn visit_source_scope(
277                 &mut self,
278                 scope: $(& $mutability)? SourceScope,
279             ) {
280                 self.super_source_scope(scope);
281             }
282
283             // The `super_xxx` methods comprise the default behavior and are
284             // not meant to be overridden.
285
286             fn super_body(
287                 &mut self,
288                 body: &$($mutability)? Body<'tcx>,
289             ) {
290                 let span = body.span;
291                 if let Some(gen) = &$($mutability)? body.generator {
292                     if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
293                         self.visit_ty(
294                             yield_ty,
295                             TyContext::YieldTy(SourceInfo::outermost(span))
296                         );
297                     }
298                 }
299
300                 // for best performance, we want to use an iterator rather
301                 // than a for-loop, to avoid calling `body::Body::invalidate` for
302                 // each basic block.
303                 #[allow(unused_macro_rules)]
304                 macro_rules! basic_blocks {
305                     (mut) => (body.basic_blocks_mut().iter_enumerated_mut());
306                     () => (body.basic_blocks().iter_enumerated());
307                 }
308                 for (bb, data) in basic_blocks!($($mutability)?) {
309                     self.visit_basic_block_data(bb, data);
310                 }
311
312                 for scope in &$($mutability)? body.source_scopes {
313                     self.visit_source_scope_data(scope);
314                 }
315
316                 self.visit_ty(
317                     $(& $mutability)? body.return_ty(),
318                     TyContext::ReturnTy(SourceInfo::outermost(body.span))
319                 );
320
321                 for local in body.local_decls.indices() {
322                     self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
323                 }
324
325                 #[allow(unused_macro_rules)]
326                 macro_rules! type_annotations {
327                     (mut) => (body.user_type_annotations.iter_enumerated_mut());
328                     () => (body.user_type_annotations.iter_enumerated());
329                 }
330
331                 for (index, annotation) in type_annotations!($($mutability)?) {
332                     self.visit_user_type_annotation(
333                         index, annotation
334                     );
335                 }
336
337                 for var_debug_info in &$($mutability)? body.var_debug_info {
338                     self.visit_var_debug_info(var_debug_info);
339                 }
340
341                 self.visit_span($(& $mutability)? body.span);
342
343                 for const_ in &$($mutability)? body.required_consts {
344                     let location = START_BLOCK.start_location();
345                     self.visit_constant(const_, location);
346                 }
347             }
348
349             fn super_basic_block_data(&mut self,
350                                       block: BasicBlock,
351                                       data: & $($mutability)? BasicBlockData<'tcx>) {
352                 let BasicBlockData {
353                     statements,
354                     terminator,
355                     is_cleanup: _
356                 } = data;
357
358                 let mut index = 0;
359                 for statement in statements {
360                     let location = Location { block, statement_index: index };
361                     self.visit_statement(statement, location);
362                     index += 1;
363                 }
364
365                 if let Some(terminator) = terminator {
366                     let location = Location { block, statement_index: index };
367                     self.visit_terminator(terminator, location);
368                 }
369             }
370
371             fn super_source_scope_data(
372                 &mut self,
373                 scope_data: & $($mutability)? SourceScopeData<'tcx>,
374             ) {
375                 let SourceScopeData {
376                     span,
377                     parent_scope,
378                     inlined,
379                     inlined_parent_scope,
380                     local_data: _,
381                 } = scope_data;
382
383                 self.visit_span($(& $mutability)? *span);
384                 if let Some(parent_scope) = parent_scope {
385                     self.visit_source_scope($(& $mutability)? *parent_scope);
386                 }
387                 if let Some((callee, callsite_span)) = inlined {
388                     let location = START_BLOCK.start_location();
389
390                     self.visit_span($(& $mutability)? *callsite_span);
391
392                     let ty::Instance { def: callee_def, substs: callee_substs } = callee;
393                     match callee_def {
394                         ty::InstanceDef::Item(_def_id) => {}
395
396                         ty::InstanceDef::Intrinsic(_def_id) |
397                         ty::InstanceDef::VtableShim(_def_id) |
398                         ty::InstanceDef::ReifyShim(_def_id) |
399                         ty::InstanceDef::Virtual(_def_id, _) |
400                         ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
401                         ty::InstanceDef::DropGlue(_def_id, None) => {}
402
403                         ty::InstanceDef::FnPtrShim(_def_id, ty) |
404                         ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
405                         ty::InstanceDef::CloneShim(_def_id, ty) => {
406                             // FIXME(eddyb) use a better `TyContext` here.
407                             self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
408                         }
409                     }
410                     self.visit_substs(callee_substs, location);
411                 }
412                 if let Some(inlined_parent_scope) = inlined_parent_scope {
413                     self.visit_source_scope($(& $mutability)? *inlined_parent_scope);
414                 }
415             }
416
417             fn super_statement(&mut self,
418                                statement: & $($mutability)? Statement<'tcx>,
419                                location: Location) {
420                 let Statement {
421                     source_info,
422                     kind,
423                 } = statement;
424
425                 self.visit_source_info(source_info);
426                 match kind {
427                     StatementKind::Assign(
428                         box (place, rvalue)
429                     ) => {
430                         self.visit_assign(place, rvalue, location);
431                     }
432                     StatementKind::FakeRead(box (_, place)) => {
433                         self.visit_place(
434                             place,
435                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
436                             location
437                         );
438                     }
439                     StatementKind::SetDiscriminant { place, .. } => {
440                         self.visit_place(
441                             place,
442                             PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
443                             location
444                         );
445                     }
446                     StatementKind::Deinit(place) => {
447                         self.visit_place(
448                             place,
449                             PlaceContext::MutatingUse(MutatingUseContext::Deinit),
450                             location
451                         )
452                     }
453                     StatementKind::StorageLive(local) => {
454                         self.visit_local(
455                             $(& $mutability)? *local,
456                             PlaceContext::NonUse(NonUseContext::StorageLive),
457                             location
458                         );
459                     }
460                     StatementKind::StorageDead(local) => {
461                         self.visit_local(
462                             $(& $mutability)? *local,
463                             PlaceContext::NonUse(NonUseContext::StorageDead),
464                             location
465                         );
466                     }
467                     StatementKind::Retag(kind, place) => {
468                         self.visit_retag($(& $mutability)? *kind, place, location);
469                     }
470                     StatementKind::AscribeUserType(
471                         box (place, user_ty),
472                         variance
473                     ) => {
474                         self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location);
475                     }
476                     StatementKind::Coverage(coverage) => {
477                         self.visit_coverage(
478                             coverage,
479                             location
480                         )
481                     }
482                     StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
483                         src,
484                         dst,
485                         count,
486                     }) => {
487                       self.visit_operand(src, location);
488                       self.visit_operand(dst, location);
489                       self.visit_operand(count, location)
490                     }
491                     StatementKind::Nop => {}
492                 }
493             }
494
495             fn super_assign(&mut self,
496                             place: &$($mutability)? Place<'tcx>,
497                             rvalue: &$($mutability)? Rvalue<'tcx>,
498                             location: Location) {
499                 self.visit_place(
500                     place,
501                     PlaceContext::MutatingUse(MutatingUseContext::Store),
502                     location
503                 );
504                 self.visit_rvalue(rvalue, location);
505             }
506
507             fn super_terminator(&mut self,
508                                 terminator: &$($mutability)? Terminator<'tcx>,
509                                 location: Location) {
510                 let Terminator { source_info, kind } = terminator;
511
512                 self.visit_source_info(source_info);
513                 match kind {
514                     TerminatorKind::Goto { .. } |
515                     TerminatorKind::Resume |
516                     TerminatorKind::Abort |
517                     TerminatorKind::GeneratorDrop |
518                     TerminatorKind::Unreachable |
519                     TerminatorKind::FalseEdge { .. } |
520                     TerminatorKind::FalseUnwind { .. } => {}
521
522                     TerminatorKind::Return => {
523                         // `return` logically moves from the return place `_0`. Note that the place
524                         // cannot be changed by any visitor, though.
525                         let $($mutability)? local = RETURN_PLACE;
526                         self.visit_local(
527                             $(& $mutability)? local,
528                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
529                             location,
530                         );
531
532                         assert_eq!(
533                             local,
534                             RETURN_PLACE,
535                             "`MutVisitor` tried to mutate return place of `return` terminator"
536                         );
537                     }
538
539                     TerminatorKind::SwitchInt {
540                         discr,
541                         switch_ty,
542                         targets: _
543                     } => {
544                         self.visit_operand(discr, location);
545                         self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
546                     }
547
548                     TerminatorKind::Drop {
549                         place,
550                         target: _,
551                         unwind: _,
552                     } => {
553                         self.visit_place(
554                             place,
555                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
556                             location
557                         );
558                     }
559
560                     TerminatorKind::DropAndReplace {
561                         place,
562                         value,
563                         target: _,
564                         unwind: _,
565                     } => {
566                         self.visit_place(
567                             place,
568                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
569                             location
570                         );
571                         self.visit_operand(value, location);
572                     }
573
574                     TerminatorKind::Call {
575                         func,
576                         args,
577                         destination,
578                         target: _,
579                         cleanup: _,
580                         from_hir_call: _,
581                         fn_span: _
582                     } => {
583                         self.visit_operand(func, location);
584                         for arg in args {
585                             self.visit_operand(arg, location);
586                         }
587                         self.visit_place(
588                             destination,
589                             PlaceContext::MutatingUse(MutatingUseContext::Call),
590                             location
591                         );
592                     }
593
594                     TerminatorKind::Assert {
595                         cond,
596                         expected: _,
597                         msg,
598                         target: _,
599                         cleanup: _,
600                     } => {
601                         self.visit_operand(cond, location);
602                         self.visit_assert_message(msg, location);
603                     }
604
605                     TerminatorKind::Yield {
606                         value,
607                         resume: _,
608                         resume_arg,
609                         drop: _,
610                     } => {
611                         self.visit_operand(value, location);
612                         self.visit_place(
613                             resume_arg,
614                             PlaceContext::MutatingUse(MutatingUseContext::Yield),
615                             location,
616                         );
617                     }
618
619                     TerminatorKind::InlineAsm {
620                         template: _,
621                         operands,
622                         options: _,
623                         line_spans: _,
624                         destination: _,
625                         cleanup: _,
626                     } => {
627                         for op in operands {
628                             match op {
629                                 InlineAsmOperand::In { value, .. } => {
630                                     self.visit_operand(value, location);
631                                 }
632                                 InlineAsmOperand::Out { place: Some(place), .. } => {
633                                     self.visit_place(
634                                         place,
635                                         PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
636                                         location,
637                                     );
638                                 }
639                                 InlineAsmOperand::InOut { in_value, out_place, .. } => {
640                                     self.visit_operand(in_value, location);
641                                     if let Some(out_place) = out_place {
642                                         self.visit_place(
643                                             out_place,
644                                             PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
645                                             location,
646                                         );
647                                     }
648                                 }
649                                 InlineAsmOperand::Const { value }
650                                 | InlineAsmOperand::SymFn { value } => {
651                                     self.visit_constant(value, location);
652                                 }
653                                 InlineAsmOperand::Out { place: None, .. }
654                                 | InlineAsmOperand::SymStatic { def_id: _ } => {}
655                             }
656                         }
657                     }
658                 }
659             }
660
661             fn super_assert_message(&mut self,
662                                     msg: & $($mutability)? AssertMessage<'tcx>,
663                                     location: Location) {
664                 use crate::mir::AssertKind::*;
665                 match msg {
666                     BoundsCheck { len, index } => {
667                         self.visit_operand(len, location);
668                         self.visit_operand(index, location);
669                     }
670                     Overflow(_, l, r) => {
671                         self.visit_operand(l, location);
672                         self.visit_operand(r, location);
673                     }
674                     OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
675                         self.visit_operand(op, location);
676                     }
677                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
678                         // Nothing to visit
679                     }
680                 }
681             }
682
683             fn super_rvalue(&mut self,
684                             rvalue: & $($mutability)? Rvalue<'tcx>,
685                             location: Location) {
686                 match rvalue {
687                     Rvalue::Use(operand) => {
688                         self.visit_operand(operand, location);
689                     }
690
691                     Rvalue::Repeat(value, _) => {
692                         self.visit_operand(value, location);
693                     }
694
695                     Rvalue::ThreadLocalRef(_) => {}
696
697                     Rvalue::Ref(r, bk, path) => {
698                         self.visit_region($(& $mutability)? *r, location);
699                         let ctx = match bk {
700                             BorrowKind::Shared => PlaceContext::NonMutatingUse(
701                                 NonMutatingUseContext::SharedBorrow
702                             ),
703                             BorrowKind::Shallow => PlaceContext::NonMutatingUse(
704                                 NonMutatingUseContext::ShallowBorrow
705                             ),
706                             BorrowKind::Unique => PlaceContext::NonMutatingUse(
707                                 NonMutatingUseContext::UniqueBorrow
708                             ),
709                             BorrowKind::Mut { .. } =>
710                                 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
711                         };
712                         self.visit_place(path, ctx, location);
713                     }
714
715                     Rvalue::AddressOf(m, path) => {
716                         let ctx = match m {
717                             Mutability::Mut => PlaceContext::MutatingUse(
718                                 MutatingUseContext::AddressOf
719                             ),
720                             Mutability::Not => PlaceContext::NonMutatingUse(
721                                 NonMutatingUseContext::AddressOf
722                             ),
723                         };
724                         self.visit_place(path, ctx, location);
725                     }
726
727                     Rvalue::Len(path) => {
728                         self.visit_place(
729                             path,
730                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
731                             location
732                         );
733                     }
734
735                     Rvalue::Cast(_cast_kind, operand, ty) => {
736                         self.visit_operand(operand, location);
737                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
738                     }
739
740                     Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
741                     | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => {
742                         self.visit_operand(lhs, location);
743                         self.visit_operand(rhs, location);
744                     }
745
746                     Rvalue::UnaryOp(_un_op, op) => {
747                         self.visit_operand(op, location);
748                     }
749
750                     Rvalue::Discriminant(place) => {
751                         self.visit_place(
752                             place,
753                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
754                             location
755                         );
756                     }
757
758                     Rvalue::NullaryOp(_op, ty) => {
759                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
760                     }
761
762                     Rvalue::Aggregate(kind, operands) => {
763                         let kind = &$($mutability)? **kind;
764                         match kind {
765                             AggregateKind::Array(ty) => {
766                                 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
767                             }
768                             AggregateKind::Tuple => {
769                             }
770                             AggregateKind::Adt(
771                                 _adt_def,
772                                 _variant_index,
773                                 substs,
774                                 _user_substs,
775                                 _active_field_index
776                             ) => {
777                                 self.visit_substs(substs, location);
778                             }
779                             AggregateKind::Closure(
780                                 _,
781                                 closure_substs
782                             ) => {
783                                 self.visit_substs(closure_substs, location);
784                             }
785                             AggregateKind::Generator(
786                                 _,
787                                 generator_substs,
788                                 _movability,
789                             ) => {
790                                 self.visit_substs(generator_substs, location);
791                             }
792                         }
793
794                         for operand in operands {
795                             self.visit_operand(operand, location);
796                         }
797                     }
798
799                     Rvalue::ShallowInitBox(operand, ty) => {
800                         self.visit_operand(operand, location);
801                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
802                     }
803                 }
804             }
805
806             fn super_operand(&mut self,
807                              operand: & $($mutability)? Operand<'tcx>,
808                              location: Location) {
809                 match operand {
810                     Operand::Copy(place) => {
811                         self.visit_place(
812                             place,
813                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
814                             location
815                         );
816                     }
817                     Operand::Move(place) => {
818                         self.visit_place(
819                             place,
820                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
821                             location
822                         );
823                     }
824                     Operand::Constant(constant) => {
825                         self.visit_constant(constant, location);
826                     }
827                 }
828             }
829
830             fn super_ascribe_user_ty(&mut self,
831                                      place: & $($mutability)? Place<'tcx>,
832                                      _variance: $(& $mutability)? ty::Variance,
833                                      user_ty: & $($mutability)? UserTypeProjection,
834                                      location: Location) {
835                 self.visit_place(
836                     place,
837                     PlaceContext::NonUse(NonUseContext::AscribeUserTy),
838                     location
839                 );
840                 self.visit_user_type_projection(user_ty);
841             }
842
843             fn super_coverage(&mut self,
844                               _coverage: & $($mutability)? Coverage,
845                               _location: Location) {
846             }
847
848             fn super_retag(&mut self,
849                            _kind: $(& $mutability)? RetagKind,
850                            place: & $($mutability)? Place<'tcx>,
851                            location: Location) {
852                 self.visit_place(
853                     place,
854                     PlaceContext::MutatingUse(MutatingUseContext::Retag),
855                     location,
856                 );
857             }
858
859             fn super_local_decl(&mut self,
860                                 local: Local,
861                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
862                 let LocalDecl {
863                     mutability: _,
864                     ty,
865                     user_ty,
866                     source_info,
867                     internal: _,
868                     local_info: _,
869                     is_block_tail: _,
870                 } = local_decl;
871
872                 self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
873                     local,
874                     source_info: *source_info,
875                 });
876                 if let Some(user_ty) = user_ty {
877                     for (user_ty, _) in & $($mutability)? user_ty.contents {
878                         self.visit_user_type_projection(user_ty);
879                     }
880                 }
881                 self.visit_source_info(source_info);
882             }
883
884             fn super_var_debug_info(
885                 &mut self,
886                 var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
887             ) {
888                 let VarDebugInfo {
889                     name: _,
890                     source_info,
891                     value,
892                 } = var_debug_info;
893
894                 self.visit_source_info(source_info);
895                 let location = START_BLOCK.start_location();
896                 match value {
897                     VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
898                     VarDebugInfoContents::Place(place) =>
899                         self.visit_place(
900                             place,
901                             PlaceContext::NonUse(NonUseContext::VarDebugInfo),
902                             location
903                         ),
904                 }
905             }
906
907             fn super_source_scope(
908                 &mut self,
909                 _scope: $(& $mutability)? SourceScope
910             ) {}
911
912             fn super_constant(
913                 &mut self,
914                 constant: & $($mutability)? Constant<'tcx>,
915                 location: Location
916             ) {
917                 let Constant {
918                     span,
919                     user_ty,
920                     literal,
921                 } = constant;
922
923                 self.visit_span($(& $mutability)? *span);
924                 drop(user_ty); // no visit method for this
925                 match literal {
926                     ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location),
927                     ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
928                 }
929             }
930
931             fn super_span(&mut self, _span: $(& $mutability)? Span) {
932             }
933
934             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
935                 let SourceInfo {
936                     span,
937                     scope,
938                 } = source_info;
939
940                 self.visit_span($(& $mutability)? *span);
941                 self.visit_source_scope($(& $mutability)? *scope);
942             }
943
944             fn super_user_type_projection(
945                 &mut self,
946                 _ty: & $($mutability)? UserTypeProjection,
947             ) {
948             }
949
950             fn super_user_type_annotation(
951                 &mut self,
952                 _index: UserTypeAnnotationIndex,
953                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
954             ) {
955                 self.visit_span($(& $mutability)? ty.span);
956                 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
957             }
958
959             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
960             }
961
962             fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
963             }
964
965             fn super_const(&mut self, _const: $(& $mutability)? ty::Const<'tcx>) {
966             }
967
968             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
969             }
970
971             // Convenience methods
972
973             fn visit_location(
974                 &mut self,
975                 body: &$($mutability)? Body<'tcx>,
976                 location: Location
977             ) {
978                 #[allow(unused_macro_rules)]
979                 macro_rules! basic_blocks {
980                     (mut) => (body.basic_blocks_mut());
981                     () => (body.basic_blocks());
982                 }
983                 let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
984                 if basic_block.statements.len() == location.statement_index {
985                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
986                         self.visit_terminator(terminator, location)
987                     }
988                 } else {
989                     let statement = & $($mutability)?
990                         basic_block.statements[location.statement_index];
991                     self.visit_statement(statement, location)
992                 }
993             }
994         }
995     }
996 }
997
998 macro_rules! visit_place_fns {
999     (mut) => {
1000         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
1001
1002         fn super_place(
1003             &mut self,
1004             place: &mut Place<'tcx>,
1005             context: PlaceContext,
1006             location: Location,
1007         ) {
1008             self.visit_local(&mut place.local, context, location);
1009
1010             if let Some(new_projection) = self.process_projection(&place.projection, location) {
1011                 place.projection = self.tcx().intern_place_elems(&new_projection);
1012             }
1013         }
1014
1015         fn process_projection<'a>(
1016             &mut self,
1017             projection: &'a [PlaceElem<'tcx>],
1018             location: Location,
1019         ) -> Option<Vec<PlaceElem<'tcx>>> {
1020             let mut projection = Cow::Borrowed(projection);
1021
1022             for i in 0..projection.len() {
1023                 if let Some(&elem) = projection.get(i) {
1024                     if let Some(elem) = self.process_projection_elem(elem, location) {
1025                         // This converts the borrowed projection into `Cow::Owned(_)` and returns a
1026                         // clone of the projection so we can mutate and reintern later.
1027                         let vec = projection.to_mut();
1028                         vec[i] = elem;
1029                     }
1030                 }
1031             }
1032
1033             match projection {
1034                 Cow::Borrowed(_) => None,
1035                 Cow::Owned(vec) => Some(vec),
1036             }
1037         }
1038
1039         fn process_projection_elem(
1040             &mut self,
1041             elem: PlaceElem<'tcx>,
1042             location: Location,
1043         ) -> Option<PlaceElem<'tcx>> {
1044             match elem {
1045                 PlaceElem::Index(local) => {
1046                     let mut new_local = local;
1047                     self.visit_local(
1048                         &mut new_local,
1049                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1050                         location,
1051                     );
1052
1053                     if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
1054                 }
1055                 PlaceElem::Field(field, ty) => {
1056                     let mut new_ty = ty;
1057                     self.visit_ty(&mut new_ty, TyContext::Location(location));
1058                     if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
1059                 }
1060                 PlaceElem::Deref
1061                 | PlaceElem::ConstantIndex { .. }
1062                 | PlaceElem::Subslice { .. }
1063                 | PlaceElem::Downcast(..) => None,
1064             }
1065         }
1066     };
1067
1068     () => {
1069         fn visit_projection(
1070             &mut self,
1071             place_ref: PlaceRef<'tcx>,
1072             context: PlaceContext,
1073             location: Location,
1074         ) {
1075             self.super_projection(place_ref, context, location);
1076         }
1077
1078         fn visit_projection_elem(
1079             &mut self,
1080             local: Local,
1081             proj_base: &[PlaceElem<'tcx>],
1082             elem: PlaceElem<'tcx>,
1083             context: PlaceContext,
1084             location: Location,
1085         ) {
1086             self.super_projection_elem(local, proj_base, elem, context, location);
1087         }
1088
1089         fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
1090             let mut context = context;
1091
1092             if !place.projection.is_empty() {
1093                 if context.is_use() {
1094                     // ^ Only change the context if it is a real use, not a "use" in debuginfo.
1095                     context = if context.is_mutating_use() {
1096                         PlaceContext::MutatingUse(MutatingUseContext::Projection)
1097                     } else {
1098                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1099                     };
1100                 }
1101             }
1102
1103             self.visit_local(place.local, context, location);
1104
1105             self.visit_projection(place.as_ref(), context, location);
1106         }
1107
1108         fn super_projection(
1109             &mut self,
1110             place_ref: PlaceRef<'tcx>,
1111             context: PlaceContext,
1112             location: Location,
1113         ) {
1114             for (base, elem) in place_ref.iter_projections().rev() {
1115                 let base_proj = base.projection;
1116                 self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
1117             }
1118         }
1119
1120         fn super_projection_elem(
1121             &mut self,
1122             _local: Local,
1123             _proj_base: &[PlaceElem<'tcx>],
1124             elem: PlaceElem<'tcx>,
1125             _context: PlaceContext,
1126             location: Location,
1127         ) {
1128             match elem {
1129                 ProjectionElem::Field(_field, ty) => {
1130                     self.visit_ty(ty, TyContext::Location(location));
1131                 }
1132                 ProjectionElem::Index(local) => {
1133                     self.visit_local(
1134                         local,
1135                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1136                         location,
1137                     );
1138                 }
1139                 ProjectionElem::Deref
1140                 | ProjectionElem::Subslice { from: _, to: _, from_end: _ }
1141                 | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
1142                 | ProjectionElem::Downcast(_, _) => {}
1143             }
1144         }
1145     };
1146 }
1147
1148 make_mir_visitor!(Visitor,);
1149 make_mir_visitor!(MutVisitor, mut);
1150
1151 pub trait MirVisitable<'tcx> {
1152     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
1153 }
1154
1155 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
1156     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1157         visitor.visit_statement(self, location)
1158     }
1159 }
1160
1161 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
1162     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1163         visitor.visit_terminator(self, location)
1164     }
1165 }
1166
1167 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
1168     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1169         visitor.visit_terminator(self.as_ref().unwrap(), location)
1170     }
1171 }
1172
1173 /// Extra information passed to `visit_ty` and friends to give context
1174 /// about where the type etc appears.
1175 #[derive(Debug)]
1176 pub enum TyContext {
1177     LocalDecl {
1178         /// The index of the local variable we are visiting.
1179         local: Local,
1180
1181         /// The source location where this local variable was declared.
1182         source_info: SourceInfo,
1183     },
1184
1185     /// The inferred type of a user type annotation.
1186     UserTy(Span),
1187
1188     /// The return type of the function.
1189     ReturnTy(SourceInfo),
1190
1191     YieldTy(SourceInfo),
1192
1193     /// A type found at some location.
1194     Location(Location),
1195 }
1196
1197 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1198 pub enum NonMutatingUseContext {
1199     /// Being inspected in some way, like loading a len.
1200     Inspect,
1201     /// Consumed as part of an operand.
1202     Copy,
1203     /// Consumed as part of an operand.
1204     Move,
1205     /// Shared borrow.
1206     SharedBorrow,
1207     /// Shallow borrow.
1208     ShallowBorrow,
1209     /// Unique borrow.
1210     UniqueBorrow,
1211     /// AddressOf for *const pointer.
1212     AddressOf,
1213     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1214     /// For example, the projection `x.y` is not marked as a mutation in these cases:
1215     /// ```ignore (illustrative)
1216     /// z = x.y;
1217     /// f(&x.y);
1218     /// ```
1219     Projection,
1220 }
1221
1222 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1223 pub enum MutatingUseContext {
1224     /// Appears as LHS of an assignment.
1225     Store,
1226     /// Appears on `SetDiscriminant`
1227     SetDiscriminant,
1228     /// Appears on `Deinit`
1229     Deinit,
1230     /// Output operand of an inline assembly block.
1231     AsmOutput,
1232     /// Destination of a call.
1233     Call,
1234     /// Destination of a yield.
1235     Yield,
1236     /// Being dropped.
1237     Drop,
1238     /// Mutable borrow.
1239     Borrow,
1240     /// AddressOf for *mut pointer.
1241     AddressOf,
1242     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1243     /// For example, the projection `x.y` is marked as a mutation in these cases:
1244     /// ```ignore (illustrative)
1245     /// x.y = ...;
1246     /// f(&mut x.y);
1247     /// ```
1248     Projection,
1249     /// Retagging, a "Stacked Borrows" shadow state operation
1250     Retag,
1251 }
1252
1253 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1254 pub enum NonUseContext {
1255     /// Starting a storage live range.
1256     StorageLive,
1257     /// Ending a storage live range.
1258     StorageDead,
1259     /// User type annotation assertions for NLL.
1260     AscribeUserTy,
1261     /// The data of a user variable, for debug info.
1262     VarDebugInfo,
1263 }
1264
1265 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1266 pub enum PlaceContext {
1267     NonMutatingUse(NonMutatingUseContext),
1268     MutatingUse(MutatingUseContext),
1269     NonUse(NonUseContext),
1270 }
1271
1272 impl PlaceContext {
1273     /// Returns `true` if this place context represents a drop.
1274     #[inline]
1275     pub fn is_drop(&self) -> bool {
1276         matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
1277     }
1278
1279     /// Returns `true` if this place context represents a borrow.
1280     pub fn is_borrow(&self) -> bool {
1281         matches!(
1282             self,
1283             PlaceContext::NonMutatingUse(
1284                 NonMutatingUseContext::SharedBorrow
1285                     | NonMutatingUseContext::ShallowBorrow
1286                     | NonMutatingUseContext::UniqueBorrow
1287             ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
1288         )
1289     }
1290
1291     /// Returns `true` if this place context represents a storage live or storage dead marker.
1292     #[inline]
1293     pub fn is_storage_marker(&self) -> bool {
1294         matches!(
1295             self,
1296             PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
1297         )
1298     }
1299
1300     /// Returns `true` if this place context represents a use that potentially changes the value.
1301     #[inline]
1302     pub fn is_mutating_use(&self) -> bool {
1303         matches!(self, PlaceContext::MutatingUse(..))
1304     }
1305
1306     /// Returns `true` if this place context represents a use.
1307     #[inline]
1308     pub fn is_use(&self) -> bool {
1309         !matches!(self, PlaceContext::NonUse(..))
1310     }
1311
1312     /// Returns `true` if this place context represents an assignment statement.
1313     pub fn is_place_assignment(&self) -> bool {
1314         matches!(
1315             self,
1316             PlaceContext::MutatingUse(
1317                 MutatingUseContext::Store
1318                     | MutatingUseContext::Call
1319                     | MutatingUseContext::AsmOutput,
1320             )
1321         )
1322     }
1323 }