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