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