]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/visit.rs
Auto merge of #105363 - WaffleLapkin:thin2win_box_next_argument, r=nnethercote
[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             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                         switch_ty,
481                         targets: _
482                     } => {
483                         self.visit_operand(discr, location);
484                         self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
485                     }
486
487                     TerminatorKind::Drop {
488                         place,
489                         target: _,
490                         unwind: _,
491                     } => {
492                         self.visit_place(
493                             place,
494                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
495                             location
496                         );
497                     }
498
499                     TerminatorKind::DropAndReplace {
500                         place,
501                         value,
502                         target: _,
503                         unwind: _,
504                     } => {
505                         self.visit_place(
506                             place,
507                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
508                             location
509                         );
510                         self.visit_operand(value, location);
511                     }
512
513                     TerminatorKind::Call {
514                         func,
515                         args,
516                         destination,
517                         target: _,
518                         cleanup: _,
519                         from_hir_call: _,
520                         fn_span: _
521                     } => {
522                         self.visit_operand(func, location);
523                         for arg in args {
524                             self.visit_operand(arg, location);
525                         }
526                         self.visit_place(
527                             destination,
528                             PlaceContext::MutatingUse(MutatingUseContext::Call),
529                             location
530                         );
531                     }
532
533                     TerminatorKind::Assert {
534                         cond,
535                         expected: _,
536                         msg,
537                         target: _,
538                         cleanup: _,
539                     } => {
540                         self.visit_operand(cond, location);
541                         self.visit_assert_message(msg, location);
542                     }
543
544                     TerminatorKind::Yield {
545                         value,
546                         resume: _,
547                         resume_arg,
548                         drop: _,
549                     } => {
550                         self.visit_operand(value, location);
551                         self.visit_place(
552                             resume_arg,
553                             PlaceContext::MutatingUse(MutatingUseContext::Yield),
554                             location,
555                         );
556                     }
557
558                     TerminatorKind::InlineAsm {
559                         template: _,
560                         operands,
561                         options: _,
562                         line_spans: _,
563                         destination: _,
564                         cleanup: _,
565                     } => {
566                         for op in operands {
567                             match op {
568                                 InlineAsmOperand::In { value, .. } => {
569                                     self.visit_operand(value, location);
570                                 }
571                                 InlineAsmOperand::Out { place: Some(place), .. } => {
572                                     self.visit_place(
573                                         place,
574                                         PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
575                                         location,
576                                     );
577                                 }
578                                 InlineAsmOperand::InOut { in_value, out_place, .. } => {
579                                     self.visit_operand(in_value, location);
580                                     if let Some(out_place) = out_place {
581                                         self.visit_place(
582                                             out_place,
583                                             PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
584                                             location,
585                                         );
586                                     }
587                                 }
588                                 InlineAsmOperand::Const { value }
589                                 | InlineAsmOperand::SymFn { value } => {
590                                     self.visit_constant(value, location);
591                                 }
592                                 InlineAsmOperand::Out { place: None, .. }
593                                 | InlineAsmOperand::SymStatic { def_id: _ } => {}
594                             }
595                         }
596                     }
597                 }
598             }
599
600             fn super_assert_message(&mut self,
601                                     msg: & $($mutability)? AssertMessage<'tcx>,
602                                     location: Location) {
603                 use crate::mir::AssertKind::*;
604                 match msg {
605                     BoundsCheck { len, index } => {
606                         self.visit_operand(len, location);
607                         self.visit_operand(index, location);
608                     }
609                     Overflow(_, l, r) => {
610                         self.visit_operand(l, location);
611                         self.visit_operand(r, location);
612                     }
613                     OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
614                         self.visit_operand(op, location);
615                     }
616                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
617                         // Nothing to visit
618                     }
619                 }
620             }
621
622             fn super_rvalue(&mut self,
623                             rvalue: & $($mutability)? Rvalue<'tcx>,
624                             location: Location) {
625                 match rvalue {
626                     Rvalue::Use(operand) => {
627                         self.visit_operand(operand, location);
628                     }
629
630                     Rvalue::Repeat(value, _) => {
631                         self.visit_operand(value, location);
632                     }
633
634                     Rvalue::ThreadLocalRef(_) => {}
635
636                     Rvalue::Ref(r, bk, path) => {
637                         self.visit_region($(& $mutability)? *r, location);
638                         let ctx = match bk {
639                             BorrowKind::Shared => PlaceContext::NonMutatingUse(
640                                 NonMutatingUseContext::SharedBorrow
641                             ),
642                             BorrowKind::Shallow => PlaceContext::NonMutatingUse(
643                                 NonMutatingUseContext::ShallowBorrow
644                             ),
645                             BorrowKind::Unique => PlaceContext::NonMutatingUse(
646                                 NonMutatingUseContext::UniqueBorrow
647                             ),
648                             BorrowKind::Mut { .. } =>
649                                 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
650                         };
651                         self.visit_place(path, ctx, location);
652                     }
653                     Rvalue::CopyForDeref(place) => {
654                         self.visit_place(
655                             place,
656                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
657                             location
658                         );
659                     }
660
661                     Rvalue::AddressOf(m, path) => {
662                         let ctx = match m {
663                             Mutability::Mut => PlaceContext::MutatingUse(
664                                 MutatingUseContext::AddressOf
665                             ),
666                             Mutability::Not => PlaceContext::NonMutatingUse(
667                                 NonMutatingUseContext::AddressOf
668                             ),
669                         };
670                         self.visit_place(path, ctx, location);
671                     }
672
673                     Rvalue::Len(path) => {
674                         self.visit_place(
675                             path,
676                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
677                             location
678                         );
679                     }
680
681                     Rvalue::Cast(_cast_kind, operand, ty) => {
682                         self.visit_operand(operand, location);
683                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
684                     }
685
686                     Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
687                     | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => {
688                         self.visit_operand(lhs, location);
689                         self.visit_operand(rhs, location);
690                     }
691
692                     Rvalue::UnaryOp(_un_op, op) => {
693                         self.visit_operand(op, location);
694                     }
695
696                     Rvalue::Discriminant(place) => {
697                         self.visit_place(
698                             place,
699                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
700                             location
701                         );
702                     }
703
704                     Rvalue::NullaryOp(_op, ty) => {
705                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
706                     }
707
708                     Rvalue::Aggregate(kind, operands) => {
709                         let kind = &$($mutability)? **kind;
710                         match kind {
711                             AggregateKind::Array(ty) => {
712                                 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
713                             }
714                             AggregateKind::Tuple => {
715                             }
716                             AggregateKind::Adt(
717                                 _adt_def,
718                                 _variant_index,
719                                 substs,
720                                 _user_substs,
721                                 _active_field_index
722                             ) => {
723                                 self.visit_substs(substs, location);
724                             }
725                             AggregateKind::Closure(
726                                 _,
727                                 closure_substs
728                             ) => {
729                                 self.visit_substs(closure_substs, location);
730                             }
731                             AggregateKind::Generator(
732                                 _,
733                                 generator_substs,
734                                 _movability,
735                             ) => {
736                                 self.visit_substs(generator_substs, location);
737                             }
738                         }
739
740                         for operand in operands {
741                             self.visit_operand(operand, location);
742                         }
743                     }
744
745                     Rvalue::ShallowInitBox(operand, ty) => {
746                         self.visit_operand(operand, location);
747                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
748                     }
749                 }
750             }
751
752             fn super_operand(&mut self,
753                              operand: & $($mutability)? Operand<'tcx>,
754                              location: Location) {
755                 match operand {
756                     Operand::Copy(place) => {
757                         self.visit_place(
758                             place,
759                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
760                             location
761                         );
762                     }
763                     Operand::Move(place) => {
764                         self.visit_place(
765                             place,
766                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
767                             location
768                         );
769                     }
770                     Operand::Constant(constant) => {
771                         self.visit_constant(constant, location);
772                     }
773                 }
774             }
775
776             fn super_ascribe_user_ty(&mut self,
777                                      place: & $($mutability)? Place<'tcx>,
778                                      _variance: $(& $mutability)? ty::Variance,
779                                      user_ty: & $($mutability)? UserTypeProjection,
780                                      location: Location) {
781                 self.visit_place(
782                     place,
783                     PlaceContext::NonUse(NonUseContext::AscribeUserTy),
784                     location
785                 );
786                 self.visit_user_type_projection(user_ty);
787             }
788
789             fn super_coverage(&mut self,
790                               _coverage: & $($mutability)? Coverage,
791                               _location: Location) {
792             }
793
794             fn super_retag(&mut self,
795                            _kind: $(& $mutability)? RetagKind,
796                            place: & $($mutability)? Place<'tcx>,
797                            location: Location) {
798                 self.visit_place(
799                     place,
800                     PlaceContext::MutatingUse(MutatingUseContext::Retag),
801                     location,
802                 );
803             }
804
805             fn super_local_decl(&mut self,
806                                 local: Local,
807                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
808                 let LocalDecl {
809                     mutability: _,
810                     ty,
811                     user_ty,
812                     source_info,
813                     internal: _,
814                     local_info: _,
815                     is_block_tail: _,
816                 } = local_decl;
817
818                 self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
819                     local,
820                     source_info: *source_info,
821                 });
822                 if let Some(user_ty) = user_ty {
823                     for (user_ty, _) in & $($mutability)? user_ty.contents {
824                         self.visit_user_type_projection(user_ty);
825                     }
826                 }
827                 self.visit_source_info(source_info);
828             }
829
830             fn super_var_debug_info(
831                 &mut self,
832                 var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
833             ) {
834                 let VarDebugInfo {
835                     name: _,
836                     source_info,
837                     value,
838                 } = var_debug_info;
839
840                 self.visit_source_info(source_info);
841                 let location = START_BLOCK.start_location();
842                 match value {
843                     VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
844                     VarDebugInfoContents::Place(place) =>
845                         self.visit_place(
846                             place,
847                             PlaceContext::NonUse(NonUseContext::VarDebugInfo),
848                             location
849                         ),
850                     VarDebugInfoContents::Composite { ty, fragments } => {
851                         // FIXME(eddyb) use a better `TyContext` here.
852                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
853                         for VarDebugInfoFragment { projection: _, contents } in fragments {
854                             self.visit_place(
855                                 contents,
856                                 PlaceContext::NonUse(NonUseContext::VarDebugInfo),
857                                 location,
858                             );
859                         }
860                     }
861                 }
862             }
863
864             fn super_source_scope(
865                 &mut self,
866                 _scope: $(& $mutability)? SourceScope
867             ) {}
868
869             fn super_constant(
870                 &mut self,
871                 constant: & $($mutability)? Constant<'tcx>,
872                 location: Location
873             ) {
874                 let Constant {
875                     span,
876                     user_ty,
877                     literal,
878                 } = constant;
879
880                 self.visit_span($(& $mutability)? *span);
881                 drop(user_ty); // no visit method for this
882                 match literal {
883                     ConstantKind::Ty(_) => {}
884                     ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
885                     ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
886                 }
887             }
888
889             fn super_span(&mut self, _span: $(& $mutability)? Span) {
890             }
891
892             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
893                 let SourceInfo {
894                     span,
895                     scope,
896                 } = source_info;
897
898                 self.visit_span($(& $mutability)? *span);
899                 self.visit_source_scope($(& $mutability)? *scope);
900             }
901
902             fn super_user_type_projection(
903                 &mut self,
904                 _ty: & $($mutability)? UserTypeProjection,
905             ) {
906             }
907
908             fn super_user_type_annotation(
909                 &mut self,
910                 _index: UserTypeAnnotationIndex,
911                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
912             ) {
913                 self.visit_span($(& $mutability)? ty.span);
914                 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
915             }
916
917             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
918             }
919
920             fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
921             }
922
923             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
924             }
925
926             // Convenience methods
927
928             fn visit_location(
929                 &mut self,
930                 body: &$($mutability)? Body<'tcx>,
931                 location: Location
932             ) {
933                 let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
934                 if basic_block.statements.len() == location.statement_index {
935                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
936                         self.visit_terminator(terminator, location)
937                     }
938                 } else {
939                     let statement = & $($mutability)?
940                         basic_block.statements[location.statement_index];
941                     self.visit_statement(statement, location)
942                 }
943             }
944         }
945     }
946 }
947
948 macro_rules! basic_blocks {
949     ($body:ident, mut, true) => {
950         $body.basic_blocks.as_mut()
951     };
952     ($body:ident, mut, false) => {
953         $body.basic_blocks.as_mut_preserves_cfg()
954     };
955     ($body:ident,) => {
956         $body.basic_blocks
957     };
958 }
959
960 macro_rules! basic_blocks_iter {
961     ($body:ident, mut, $invalidate:tt) => {
962         basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
963     };
964     ($body:ident,) => {
965         basic_blocks!($body,).iter_enumerated()
966     };
967 }
968
969 macro_rules! extra_body_methods {
970     (mut) => {
971         fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
972             self.super_body_preserves_cfg(body);
973         }
974
975         fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
976             super_body!(self, body, mut, false);
977         }
978     };
979     () => {};
980 }
981
982 macro_rules! super_body {
983     ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
984         let span = $body.span;
985         if let Some(gen) = &$($mutability)? $body.generator {
986             if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
987                 $self.visit_ty(
988                     yield_ty,
989                     TyContext::YieldTy(SourceInfo::outermost(span))
990                 );
991             }
992         }
993
994         for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
995             $self.visit_basic_block_data(bb, data);
996         }
997
998         for scope in &$($mutability)? $body.source_scopes {
999             $self.visit_source_scope_data(scope);
1000         }
1001
1002         $self.visit_ty(
1003             $(& $mutability)? $body.return_ty(),
1004             TyContext::ReturnTy(SourceInfo::outermost($body.span))
1005         );
1006
1007         for local in $body.local_decls.indices() {
1008             $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
1009         }
1010
1011         #[allow(unused_macro_rules)]
1012         macro_rules! type_annotations {
1013             (mut) => ($body.user_type_annotations.iter_enumerated_mut());
1014             () => ($body.user_type_annotations.iter_enumerated());
1015         }
1016
1017         for (index, annotation) in type_annotations!($($mutability)?) {
1018             $self.visit_user_type_annotation(
1019                 index, annotation
1020             );
1021         }
1022
1023         for var_debug_info in &$($mutability)? $body.var_debug_info {
1024             $self.visit_var_debug_info(var_debug_info);
1025         }
1026
1027         $self.visit_span($(& $mutability)? $body.span);
1028
1029         for const_ in &$($mutability)? $body.required_consts {
1030             let location = START_BLOCK.start_location();
1031             $self.visit_constant(const_, location);
1032         }
1033     }
1034 }
1035
1036 macro_rules! visit_place_fns {
1037     (mut) => {
1038         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
1039
1040         fn super_place(
1041             &mut self,
1042             place: &mut Place<'tcx>,
1043             context: PlaceContext,
1044             location: Location,
1045         ) {
1046             self.visit_local(&mut place.local, context, location);
1047
1048             if let Some(new_projection) = self.process_projection(&place.projection, location) {
1049                 place.projection = self.tcx().intern_place_elems(&new_projection);
1050             }
1051         }
1052
1053         fn process_projection<'a>(
1054             &mut self,
1055             projection: &'a [PlaceElem<'tcx>],
1056             location: Location,
1057         ) -> Option<Vec<PlaceElem<'tcx>>> {
1058             let mut projection = Cow::Borrowed(projection);
1059
1060             for i in 0..projection.len() {
1061                 if let Some(&elem) = projection.get(i) {
1062                     if let Some(elem) = self.process_projection_elem(elem, location) {
1063                         // This converts the borrowed projection into `Cow::Owned(_)` and returns a
1064                         // clone of the projection so we can mutate and reintern later.
1065                         let vec = projection.to_mut();
1066                         vec[i] = elem;
1067                     }
1068                 }
1069             }
1070
1071             match projection {
1072                 Cow::Borrowed(_) => None,
1073                 Cow::Owned(vec) => Some(vec),
1074             }
1075         }
1076
1077         fn process_projection_elem(
1078             &mut self,
1079             elem: PlaceElem<'tcx>,
1080             location: Location,
1081         ) -> Option<PlaceElem<'tcx>> {
1082             match elem {
1083                 PlaceElem::Index(local) => {
1084                     let mut new_local = local;
1085                     self.visit_local(
1086                         &mut new_local,
1087                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1088                         location,
1089                     );
1090
1091                     if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
1092                 }
1093                 PlaceElem::Field(field, ty) => {
1094                     let mut new_ty = ty;
1095                     self.visit_ty(&mut new_ty, TyContext::Location(location));
1096                     if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
1097                 }
1098                 PlaceElem::OpaqueCast(ty) => {
1099                     let mut new_ty = ty;
1100                     self.visit_ty(&mut new_ty, TyContext::Location(location));
1101                     if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
1102                 }
1103                 PlaceElem::Deref
1104                 | PlaceElem::ConstantIndex { .. }
1105                 | PlaceElem::Subslice { .. }
1106                 | PlaceElem::Downcast(..) => None,
1107             }
1108         }
1109     };
1110
1111     () => {
1112         fn visit_projection(
1113             &mut self,
1114             place_ref: PlaceRef<'tcx>,
1115             context: PlaceContext,
1116             location: Location,
1117         ) {
1118             self.super_projection(place_ref, context, location);
1119         }
1120
1121         fn visit_projection_elem(
1122             &mut self,
1123             local: Local,
1124             proj_base: &[PlaceElem<'tcx>],
1125             elem: PlaceElem<'tcx>,
1126             context: PlaceContext,
1127             location: Location,
1128         ) {
1129             self.super_projection_elem(local, proj_base, elem, context, location);
1130         }
1131
1132         fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
1133             let mut context = context;
1134
1135             if !place.projection.is_empty() {
1136                 if context.is_use() {
1137                     // ^ Only change the context if it is a real use, not a "use" in debuginfo.
1138                     context = if context.is_mutating_use() {
1139                         PlaceContext::MutatingUse(MutatingUseContext::Projection)
1140                     } else {
1141                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1142                     };
1143                 }
1144             }
1145
1146             self.visit_local(place.local, context, location);
1147
1148             self.visit_projection(place.as_ref(), context, location);
1149         }
1150
1151         fn super_projection(
1152             &mut self,
1153             place_ref: PlaceRef<'tcx>,
1154             context: PlaceContext,
1155             location: Location,
1156         ) {
1157             for (base, elem) in place_ref.iter_projections().rev() {
1158                 let base_proj = base.projection;
1159                 self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
1160             }
1161         }
1162
1163         fn super_projection_elem(
1164             &mut self,
1165             _local: Local,
1166             _proj_base: &[PlaceElem<'tcx>],
1167             elem: PlaceElem<'tcx>,
1168             _context: PlaceContext,
1169             location: Location,
1170         ) {
1171             match elem {
1172                 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
1173                     self.visit_ty(ty, TyContext::Location(location));
1174                 }
1175                 ProjectionElem::Index(local) => {
1176                     self.visit_local(
1177                         local,
1178                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1179                         location,
1180                     );
1181                 }
1182                 ProjectionElem::Deref
1183                 | ProjectionElem::Subslice { from: _, to: _, from_end: _ }
1184                 | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
1185                 | ProjectionElem::Downcast(_, _) => {}
1186             }
1187         }
1188     };
1189 }
1190
1191 make_mir_visitor!(Visitor,);
1192 make_mir_visitor!(MutVisitor, mut);
1193
1194 pub trait MirVisitable<'tcx> {
1195     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
1196 }
1197
1198 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
1199     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1200         visitor.visit_statement(self, location)
1201     }
1202 }
1203
1204 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
1205     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1206         visitor.visit_terminator(self, location)
1207     }
1208 }
1209
1210 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
1211     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1212         visitor.visit_terminator(self.as_ref().unwrap(), location)
1213     }
1214 }
1215
1216 /// Extra information passed to `visit_ty` and friends to give context
1217 /// about where the type etc appears.
1218 #[derive(Debug)]
1219 pub enum TyContext {
1220     LocalDecl {
1221         /// The index of the local variable we are visiting.
1222         local: Local,
1223
1224         /// The source location where this local variable was declared.
1225         source_info: SourceInfo,
1226     },
1227
1228     /// The inferred type of a user type annotation.
1229     UserTy(Span),
1230
1231     /// The return type of the function.
1232     ReturnTy(SourceInfo),
1233
1234     YieldTy(SourceInfo),
1235
1236     /// A type found at some location.
1237     Location(Location),
1238 }
1239
1240 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1241 pub enum NonMutatingUseContext {
1242     /// Being inspected in some way, like loading a len.
1243     Inspect,
1244     /// Consumed as part of an operand.
1245     Copy,
1246     /// Consumed as part of an operand.
1247     Move,
1248     /// Shared borrow.
1249     SharedBorrow,
1250     /// Shallow borrow.
1251     ShallowBorrow,
1252     /// Unique borrow.
1253     UniqueBorrow,
1254     /// AddressOf for *const pointer.
1255     AddressOf,
1256     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1257     /// For example, the projection `x.y` is not marked as a mutation in these cases:
1258     /// ```ignore (illustrative)
1259     /// z = x.y;
1260     /// f(&x.y);
1261     /// ```
1262     Projection,
1263 }
1264
1265 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1266 pub enum MutatingUseContext {
1267     /// Appears as LHS of an assignment.
1268     Store,
1269     /// Appears on `SetDiscriminant`
1270     SetDiscriminant,
1271     /// Appears on `Deinit`
1272     Deinit,
1273     /// Output operand of an inline assembly block.
1274     AsmOutput,
1275     /// Destination of a call.
1276     Call,
1277     /// Destination of a yield.
1278     Yield,
1279     /// Being dropped.
1280     Drop,
1281     /// Mutable borrow.
1282     Borrow,
1283     /// AddressOf for *mut pointer.
1284     AddressOf,
1285     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1286     /// For example, the projection `x.y` is marked as a mutation in these cases:
1287     /// ```ignore (illustrative)
1288     /// x.y = ...;
1289     /// f(&mut x.y);
1290     /// ```
1291     Projection,
1292     /// Retagging, a "Stacked Borrows" shadow state operation
1293     Retag,
1294 }
1295
1296 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1297 pub enum NonUseContext {
1298     /// Starting a storage live range.
1299     StorageLive,
1300     /// Ending a storage live range.
1301     StorageDead,
1302     /// User type annotation assertions for NLL.
1303     AscribeUserTy,
1304     /// The data of a user variable, for debug info.
1305     VarDebugInfo,
1306 }
1307
1308 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1309 pub enum PlaceContext {
1310     NonMutatingUse(NonMutatingUseContext),
1311     MutatingUse(MutatingUseContext),
1312     NonUse(NonUseContext),
1313 }
1314
1315 impl PlaceContext {
1316     /// Returns `true` if this place context represents a drop.
1317     #[inline]
1318     pub fn is_drop(&self) -> bool {
1319         matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
1320     }
1321
1322     /// Returns `true` if this place context represents a borrow.
1323     pub fn is_borrow(&self) -> bool {
1324         matches!(
1325             self,
1326             PlaceContext::NonMutatingUse(
1327                 NonMutatingUseContext::SharedBorrow
1328                     | NonMutatingUseContext::ShallowBorrow
1329                     | NonMutatingUseContext::UniqueBorrow
1330             ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
1331         )
1332     }
1333
1334     /// Returns `true` if this place context represents an address-of.
1335     pub fn is_address_of(&self) -> bool {
1336         matches!(
1337             self,
1338             PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
1339                 | PlaceContext::MutatingUse(MutatingUseContext::AddressOf)
1340         )
1341     }
1342
1343     /// Returns `true` if this place context represents a storage live or storage dead marker.
1344     #[inline]
1345     pub fn is_storage_marker(&self) -> bool {
1346         matches!(
1347             self,
1348             PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
1349         )
1350     }
1351
1352     /// Returns `true` if this place context represents a use that potentially changes the value.
1353     #[inline]
1354     pub fn is_mutating_use(&self) -> bool {
1355         matches!(self, PlaceContext::MutatingUse(..))
1356     }
1357
1358     /// Returns `true` if this place context represents a use.
1359     #[inline]
1360     pub fn is_use(&self) -> bool {
1361         !matches!(self, PlaceContext::NonUse(..))
1362     }
1363
1364     /// Returns `true` if this place context represents an assignment statement.
1365     pub fn is_place_assignment(&self) -> bool {
1366         matches!(
1367             self,
1368             PlaceContext::MutatingUse(
1369                 MutatingUseContext::Store
1370                     | MutatingUseContext::Call
1371                     | MutatingUseContext::AsmOutput,
1372             )
1373         )
1374     }
1375 }