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