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