]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/visit.rs
impl SessionDiagnostic for LayoutError and Spanned<T>
[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                 }
851             }
852
853             fn super_source_scope(
854                 &mut self,
855                 _scope: $(& $mutability)? SourceScope
856             ) {}
857
858             fn super_constant(
859                 &mut self,
860                 constant: & $($mutability)? Constant<'tcx>,
861                 location: Location
862             ) {
863                 let Constant {
864                     span,
865                     user_ty,
866                     literal,
867                 } = constant;
868
869                 self.visit_span($(& $mutability)? *span);
870                 drop(user_ty); // no visit method for this
871                 match literal {
872                     ConstantKind::Ty(_) => {}
873                     ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
874                     ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
875                 }
876             }
877
878             fn super_span(&mut self, _span: $(& $mutability)? Span) {
879             }
880
881             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
882                 let SourceInfo {
883                     span,
884                     scope,
885                 } = source_info;
886
887                 self.visit_span($(& $mutability)? *span);
888                 self.visit_source_scope($(& $mutability)? *scope);
889             }
890
891             fn super_user_type_projection(
892                 &mut self,
893                 _ty: & $($mutability)? UserTypeProjection,
894             ) {
895             }
896
897             fn super_user_type_annotation(
898                 &mut self,
899                 _index: UserTypeAnnotationIndex,
900                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
901             ) {
902                 self.visit_span($(& $mutability)? ty.span);
903                 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
904             }
905
906             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
907             }
908
909             fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
910             }
911
912             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
913             }
914
915             // Convenience methods
916
917             fn visit_location(
918                 &mut self,
919                 body: &$($mutability)? Body<'tcx>,
920                 location: Location
921             ) {
922                 let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
923                 if basic_block.statements.len() == location.statement_index {
924                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
925                         self.visit_terminator(terminator, location)
926                     }
927                 } else {
928                     let statement = & $($mutability)?
929                         basic_block.statements[location.statement_index];
930                     self.visit_statement(statement, location)
931                 }
932             }
933         }
934     }
935 }
936
937 macro_rules! basic_blocks {
938     ($body:ident, mut, true) => {
939         $body.basic_blocks.as_mut()
940     };
941     ($body:ident, mut, false) => {
942         $body.basic_blocks.as_mut_preserves_cfg()
943     };
944     ($body:ident,) => {
945         $body.basic_blocks
946     };
947 }
948
949 macro_rules! basic_blocks_iter {
950     ($body:ident, mut, $invalidate:tt) => {
951         basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
952     };
953     ($body:ident,) => {
954         basic_blocks!($body,).iter_enumerated()
955     };
956 }
957
958 macro_rules! extra_body_methods {
959     (mut) => {
960         fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
961             self.super_body_preserves_cfg(body);
962         }
963
964         fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
965             super_body!(self, body, mut, false);
966         }
967     };
968     () => {};
969 }
970
971 macro_rules! super_body {
972     ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
973         let span = $body.span;
974         if let Some(gen) = &$($mutability)? $body.generator {
975             if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
976                 $self.visit_ty(
977                     yield_ty,
978                     TyContext::YieldTy(SourceInfo::outermost(span))
979                 );
980             }
981         }
982
983         for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
984             $self.visit_basic_block_data(bb, data);
985         }
986
987         for scope in &$($mutability)? $body.source_scopes {
988             $self.visit_source_scope_data(scope);
989         }
990
991         $self.visit_ty(
992             $(& $mutability)? $body.return_ty(),
993             TyContext::ReturnTy(SourceInfo::outermost($body.span))
994         );
995
996         for local in $body.local_decls.indices() {
997             $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
998         }
999
1000         #[allow(unused_macro_rules)]
1001         macro_rules! type_annotations {
1002             (mut) => ($body.user_type_annotations.iter_enumerated_mut());
1003             () => ($body.user_type_annotations.iter_enumerated());
1004         }
1005
1006         for (index, annotation) in type_annotations!($($mutability)?) {
1007             $self.visit_user_type_annotation(
1008                 index, annotation
1009             );
1010         }
1011
1012         for var_debug_info in &$($mutability)? $body.var_debug_info {
1013             $self.visit_var_debug_info(var_debug_info);
1014         }
1015
1016         $self.visit_span($(& $mutability)? $body.span);
1017
1018         for const_ in &$($mutability)? $body.required_consts {
1019             let location = START_BLOCK.start_location();
1020             $self.visit_constant(const_, location);
1021         }
1022     }
1023 }
1024
1025 macro_rules! visit_place_fns {
1026     (mut) => {
1027         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
1028
1029         fn super_place(
1030             &mut self,
1031             place: &mut Place<'tcx>,
1032             context: PlaceContext,
1033             location: Location,
1034         ) {
1035             self.visit_local(&mut place.local, context, location);
1036
1037             if let Some(new_projection) = self.process_projection(&place.projection, location) {
1038                 place.projection = self.tcx().intern_place_elems(&new_projection);
1039             }
1040         }
1041
1042         fn process_projection<'a>(
1043             &mut self,
1044             projection: &'a [PlaceElem<'tcx>],
1045             location: Location,
1046         ) -> Option<Vec<PlaceElem<'tcx>>> {
1047             let mut projection = Cow::Borrowed(projection);
1048
1049             for i in 0..projection.len() {
1050                 if let Some(&elem) = projection.get(i) {
1051                     if let Some(elem) = self.process_projection_elem(elem, location) {
1052                         // This converts the borrowed projection into `Cow::Owned(_)` and returns a
1053                         // clone of the projection so we can mutate and reintern later.
1054                         let vec = projection.to_mut();
1055                         vec[i] = elem;
1056                     }
1057                 }
1058             }
1059
1060             match projection {
1061                 Cow::Borrowed(_) => None,
1062                 Cow::Owned(vec) => Some(vec),
1063             }
1064         }
1065
1066         fn process_projection_elem(
1067             &mut self,
1068             elem: PlaceElem<'tcx>,
1069             location: Location,
1070         ) -> Option<PlaceElem<'tcx>> {
1071             match elem {
1072                 PlaceElem::Index(local) => {
1073                     let mut new_local = local;
1074                     self.visit_local(
1075                         &mut new_local,
1076                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1077                         location,
1078                     );
1079
1080                     if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
1081                 }
1082                 PlaceElem::Field(field, ty) => {
1083                     let mut new_ty = ty;
1084                     self.visit_ty(&mut new_ty, TyContext::Location(location));
1085                     if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
1086                 }
1087                 PlaceElem::OpaqueCast(ty) => {
1088                     let mut new_ty = ty;
1089                     self.visit_ty(&mut new_ty, TyContext::Location(location));
1090                     if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
1091                 }
1092                 PlaceElem::Deref
1093                 | PlaceElem::ConstantIndex { .. }
1094                 | PlaceElem::Subslice { .. }
1095                 | PlaceElem::Downcast(..) => None,
1096             }
1097         }
1098     };
1099
1100     () => {
1101         fn visit_projection(
1102             &mut self,
1103             place_ref: PlaceRef<'tcx>,
1104             context: PlaceContext,
1105             location: Location,
1106         ) {
1107             self.super_projection(place_ref, context, location);
1108         }
1109
1110         fn visit_projection_elem(
1111             &mut self,
1112             local: Local,
1113             proj_base: &[PlaceElem<'tcx>],
1114             elem: PlaceElem<'tcx>,
1115             context: PlaceContext,
1116             location: Location,
1117         ) {
1118             self.super_projection_elem(local, proj_base, elem, context, location);
1119         }
1120
1121         fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
1122             let mut context = context;
1123
1124             if !place.projection.is_empty() {
1125                 if context.is_use() {
1126                     // ^ Only change the context if it is a real use, not a "use" in debuginfo.
1127                     context = if context.is_mutating_use() {
1128                         PlaceContext::MutatingUse(MutatingUseContext::Projection)
1129                     } else {
1130                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1131                     };
1132                 }
1133             }
1134
1135             self.visit_local(place.local, context, location);
1136
1137             self.visit_projection(place.as_ref(), context, location);
1138         }
1139
1140         fn super_projection(
1141             &mut self,
1142             place_ref: PlaceRef<'tcx>,
1143             context: PlaceContext,
1144             location: Location,
1145         ) {
1146             for (base, elem) in place_ref.iter_projections().rev() {
1147                 let base_proj = base.projection;
1148                 self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
1149             }
1150         }
1151
1152         fn super_projection_elem(
1153             &mut self,
1154             _local: Local,
1155             _proj_base: &[PlaceElem<'tcx>],
1156             elem: PlaceElem<'tcx>,
1157             _context: PlaceContext,
1158             location: Location,
1159         ) {
1160             match elem {
1161                 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
1162                     self.visit_ty(ty, TyContext::Location(location));
1163                 }
1164                 ProjectionElem::Index(local) => {
1165                     self.visit_local(
1166                         local,
1167                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1168                         location,
1169                     );
1170                 }
1171                 ProjectionElem::Deref
1172                 | ProjectionElem::Subslice { from: _, to: _, from_end: _ }
1173                 | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
1174                 | ProjectionElem::Downcast(_, _) => {}
1175             }
1176         }
1177     };
1178 }
1179
1180 make_mir_visitor!(Visitor,);
1181 make_mir_visitor!(MutVisitor, mut);
1182
1183 pub trait MirVisitable<'tcx> {
1184     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
1185 }
1186
1187 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
1188     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1189         visitor.visit_statement(self, location)
1190     }
1191 }
1192
1193 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
1194     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1195         visitor.visit_terminator(self, location)
1196     }
1197 }
1198
1199 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
1200     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1201         visitor.visit_terminator(self.as_ref().unwrap(), location)
1202     }
1203 }
1204
1205 /// Extra information passed to `visit_ty` and friends to give context
1206 /// about where the type etc appears.
1207 #[derive(Debug)]
1208 pub enum TyContext {
1209     LocalDecl {
1210         /// The index of the local variable we are visiting.
1211         local: Local,
1212
1213         /// The source location where this local variable was declared.
1214         source_info: SourceInfo,
1215     },
1216
1217     /// The inferred type of a user type annotation.
1218     UserTy(Span),
1219
1220     /// The return type of the function.
1221     ReturnTy(SourceInfo),
1222
1223     YieldTy(SourceInfo),
1224
1225     /// A type found at some location.
1226     Location(Location),
1227 }
1228
1229 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1230 pub enum NonMutatingUseContext {
1231     /// Being inspected in some way, like loading a len.
1232     Inspect,
1233     /// Consumed as part of an operand.
1234     Copy,
1235     /// Consumed as part of an operand.
1236     Move,
1237     /// Shared borrow.
1238     SharedBorrow,
1239     /// Shallow borrow.
1240     ShallowBorrow,
1241     /// Unique borrow.
1242     UniqueBorrow,
1243     /// AddressOf for *const pointer.
1244     AddressOf,
1245     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1246     /// For example, the projection `x.y` is not marked as a mutation in these cases:
1247     /// ```ignore (illustrative)
1248     /// z = x.y;
1249     /// f(&x.y);
1250     /// ```
1251     Projection,
1252 }
1253
1254 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1255 pub enum MutatingUseContext {
1256     /// Appears as LHS of an assignment.
1257     Store,
1258     /// Appears on `SetDiscriminant`
1259     SetDiscriminant,
1260     /// Appears on `Deinit`
1261     Deinit,
1262     /// Output operand of an inline assembly block.
1263     AsmOutput,
1264     /// Destination of a call.
1265     Call,
1266     /// Destination of a yield.
1267     Yield,
1268     /// Being dropped.
1269     Drop,
1270     /// Mutable borrow.
1271     Borrow,
1272     /// AddressOf for *mut pointer.
1273     AddressOf,
1274     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1275     /// For example, the projection `x.y` is marked as a mutation in these cases:
1276     /// ```ignore (illustrative)
1277     /// x.y = ...;
1278     /// f(&mut x.y);
1279     /// ```
1280     Projection,
1281     /// Retagging, a "Stacked Borrows" shadow state operation
1282     Retag,
1283 }
1284
1285 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1286 pub enum NonUseContext {
1287     /// Starting a storage live range.
1288     StorageLive,
1289     /// Ending a storage live range.
1290     StorageDead,
1291     /// User type annotation assertions for NLL.
1292     AscribeUserTy,
1293     /// The data of a user variable, for debug info.
1294     VarDebugInfo,
1295 }
1296
1297 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1298 pub enum PlaceContext {
1299     NonMutatingUse(NonMutatingUseContext),
1300     MutatingUse(MutatingUseContext),
1301     NonUse(NonUseContext),
1302 }
1303
1304 impl PlaceContext {
1305     /// Returns `true` if this place context represents a drop.
1306     #[inline]
1307     pub fn is_drop(&self) -> bool {
1308         matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
1309     }
1310
1311     /// Returns `true` if this place context represents a borrow.
1312     pub fn is_borrow(&self) -> bool {
1313         matches!(
1314             self,
1315             PlaceContext::NonMutatingUse(
1316                 NonMutatingUseContext::SharedBorrow
1317                     | NonMutatingUseContext::ShallowBorrow
1318                     | NonMutatingUseContext::UniqueBorrow
1319             ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
1320         )
1321     }
1322
1323     /// Returns `true` if this place context represents a storage live or storage dead marker.
1324     #[inline]
1325     pub fn is_storage_marker(&self) -> bool {
1326         matches!(
1327             self,
1328             PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
1329         )
1330     }
1331
1332     /// Returns `true` if this place context represents a use that potentially changes the value.
1333     #[inline]
1334     pub fn is_mutating_use(&self) -> bool {
1335         matches!(self, PlaceContext::MutatingUse(..))
1336     }
1337
1338     /// Returns `true` if this place context represents a use.
1339     #[inline]
1340     pub fn is_use(&self) -> bool {
1341         !matches!(self, PlaceContext::NonUse(..))
1342     }
1343
1344     /// Returns `true` if this place context represents an assignment statement.
1345     pub fn is_place_assignment(&self) -> bool {
1346         matches!(
1347             self,
1348             PlaceContext::MutatingUse(
1349                 MutatingUseContext::Store
1350                     | MutatingUseContext::Call
1351                     | MutatingUseContext::AsmOutput,
1352             )
1353         )
1354     }
1355 }