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