]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
9173c328006411cda989ebe0f3d2d0bd22da4b4a
[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                                 base: & $($mutability)? PlaceBase<'tcx>,
168                                 context: PlaceContext,
169                                 location: Location) {
170                 self.super_place_base(base, 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                         drop: _,
520                     } => {
521                         self.visit_operand(value, source_location);
522                     }
523
524                 }
525             }
526
527             fn super_assert_message(&mut self,
528                                     msg: & $($mutability)? AssertMessage<'tcx>,
529                                     location: Location) {
530                 use crate::mir::interpret::PanicInfo::*;
531                 match msg {
532                     BoundsCheck { len, index } => {
533                         self.visit_operand(len, location);
534                         self.visit_operand(index, location);
535                     }
536                     Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
537                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
538                         // Nothing to visit
539                     }
540                 }
541             }
542
543             fn super_rvalue(&mut self,
544                             rvalue: & $($mutability)? Rvalue<'tcx>,
545                             location: Location) {
546                 match rvalue {
547                     Rvalue::Use(operand) => {
548                         self.visit_operand(operand, location);
549                     }
550
551                     Rvalue::Repeat(value, _) => {
552                         self.visit_operand(value, location);
553                     }
554
555                     Rvalue::Ref(r, bk, path) => {
556                         self.visit_region(r, location);
557                         let ctx = match bk {
558                             BorrowKind::Shared => PlaceContext::NonMutatingUse(
559                                 NonMutatingUseContext::SharedBorrow
560                             ),
561                             BorrowKind::Shallow => PlaceContext::NonMutatingUse(
562                                 NonMutatingUseContext::ShallowBorrow
563                             ),
564                             BorrowKind::Unique => PlaceContext::NonMutatingUse(
565                                 NonMutatingUseContext::UniqueBorrow
566                             ),
567                             BorrowKind::Mut { .. } =>
568                                 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
569                         };
570                         self.visit_place(path, ctx, location);
571                     }
572
573                     Rvalue::AddressOf(m, path) => {
574                         let ctx = match m {
575                             Mutability::Mut => PlaceContext::MutatingUse(
576                                 MutatingUseContext::AddressOf
577                             ),
578                             Mutability::Not => PlaceContext::NonMutatingUse(
579                                 NonMutatingUseContext::AddressOf
580                             ),
581                         };
582                         self.visit_place(path, ctx, location);
583                     }
584
585                     Rvalue::Len(path) => {
586                         self.visit_place(
587                             path,
588                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
589                             location
590                         );
591                     }
592
593                     Rvalue::Cast(_cast_kind, operand, ty) => {
594                         self.visit_operand(operand, location);
595                         self.visit_ty(ty, TyContext::Location(location));
596                     }
597
598                     Rvalue::BinaryOp(_bin_op, lhs, rhs)
599                     | Rvalue::CheckedBinaryOp(_bin_op, lhs, rhs) => {
600                         self.visit_operand(lhs, location);
601                         self.visit_operand(rhs, location);
602                     }
603
604                     Rvalue::UnaryOp(_un_op, op) => {
605                         self.visit_operand(op, location);
606                     }
607
608                     Rvalue::Discriminant(place) => {
609                         self.visit_place(
610                             place,
611                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
612                             location
613                         );
614                     }
615
616                     Rvalue::NullaryOp(_op, ty) => {
617                         self.visit_ty(ty, TyContext::Location(location));
618                     }
619
620                     Rvalue::Aggregate(kind, operands) => {
621                         let kind = &$($mutability)? **kind;
622                         match kind {
623                             AggregateKind::Array(ty) => {
624                                 self.visit_ty(ty, TyContext::Location(location));
625                             }
626                             AggregateKind::Tuple => {
627                             }
628                             AggregateKind::Adt(
629                                 _adt_def,
630                                 _variant_index,
631                                 substs,
632                                 _user_substs,
633                                 _active_field_index
634                             ) => {
635                                 self.visit_substs(substs, location);
636                             }
637                             AggregateKind::Closure(
638                                 _,
639                                 closure_substs
640                             ) => {
641                                 self.visit_substs(closure_substs, location);
642                             }
643                             AggregateKind::Generator(
644                                 _,
645                                 generator_substs,
646                                 _movability,
647                             ) => {
648                                 self.visit_substs(generator_substs, location);
649                             }
650                         }
651
652                         for operand in operands {
653                             self.visit_operand(operand, location);
654                         }
655                     }
656                 }
657             }
658
659             fn super_operand(&mut self,
660                              operand: & $($mutability)? Operand<'tcx>,
661                              location: Location) {
662                 match operand {
663                     Operand::Copy(place) => {
664                         self.visit_place(
665                             place,
666                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
667                             location
668                         );
669                     }
670                     Operand::Move(place) => {
671                         self.visit_place(
672                             place,
673                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
674                             location
675                         );
676                     }
677                     Operand::Constant(constant) => {
678                         self.visit_constant(constant, location);
679                     }
680                 }
681             }
682
683             fn super_ascribe_user_ty(&mut self,
684                                      place: & $($mutability)? Place<'tcx>,
685                                      _variance: & $($mutability)? ty::Variance,
686                                      user_ty: & $($mutability)? UserTypeProjection,
687                                      location: Location) {
688                 self.visit_place(
689                     place,
690                     PlaceContext::NonUse(NonUseContext::AscribeUserTy),
691                     location
692                 );
693                 self.visit_user_type_projection(user_ty);
694             }
695
696             fn super_retag(&mut self,
697                            _kind: & $($mutability)? RetagKind,
698                            place: & $($mutability)? Place<'tcx>,
699                            location: Location) {
700                 self.visit_place(
701                     place,
702                     PlaceContext::MutatingUse(MutatingUseContext::Retag),
703                     location,
704                 );
705             }
706
707             fn super_place_base(&mut self,
708                                 place_base: & $($mutability)? PlaceBase<'tcx>,
709                                 context: PlaceContext,
710                                 location: Location) {
711                 match place_base {
712                     PlaceBase::Local(local) => {
713                         self.visit_local(local, context, location);
714                     }
715                     PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => {
716                         self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
717                     }
718                 }
719             }
720
721             fn super_local_decl(&mut self,
722                                 local: Local,
723                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
724                 let LocalDecl {
725                     mutability: _,
726                     ty,
727                     user_ty,
728                     source_info,
729                     internal: _,
730                     local_info: _,
731                     is_block_tail: _,
732                 } = local_decl;
733
734                 self.visit_ty(ty, TyContext::LocalDecl {
735                     local,
736                     source_info: *source_info,
737                 });
738                 for (user_ty, _) in & $($mutability)? user_ty.contents {
739                     self.visit_user_type_projection(user_ty);
740                 }
741                 self.visit_source_info(source_info);
742             }
743
744             fn super_var_debug_info(&mut self,
745                                     var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) {
746                 let VarDebugInfo {
747                     name: _,
748                     source_info,
749                     place,
750                 } = var_debug_info;
751
752                 self.visit_source_info(source_info);
753                 let location = START_BLOCK.start_location();
754                 self.visit_place(
755                     place,
756                     PlaceContext::NonUse(NonUseContext::VarDebugInfo),
757                     location,
758                 );
759             }
760
761             fn super_source_scope(&mut self,
762                                       _scope: & $($mutability)? SourceScope) {
763             }
764
765             fn super_constant(&mut self,
766                               constant: & $($mutability)? Constant<'tcx>,
767                               location: Location) {
768                 let Constant {
769                     span,
770                     user_ty,
771                     literal,
772                 } = constant;
773
774                 self.visit_span(span);
775                 drop(user_ty); // no visit method for this
776                 self.visit_const(literal, location);
777             }
778
779             fn super_span(&mut self, _span: & $($mutability)? Span) {
780             }
781
782             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
783                 let SourceInfo {
784                     span,
785                     scope,
786                 } = source_info;
787
788                 self.visit_span(span);
789                 self.visit_source_scope(scope);
790             }
791
792             fn super_user_type_projection(
793                 &mut self,
794                 _ty: & $($mutability)? UserTypeProjection,
795             ) {
796             }
797
798             fn super_user_type_annotation(
799                 &mut self,
800                 _index: UserTypeAnnotationIndex,
801                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
802             ) {
803                 self.visit_span(& $($mutability)? ty.span);
804                 self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
805             }
806
807             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
808             }
809
810             fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) {
811             }
812
813             fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {
814             }
815
816             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
817             }
818
819             // Convenience methods
820
821             fn visit_location(
822                 &mut self,
823                 body: body_cache_type!($($mutability)? '_, 'tcx),
824                 location: Location
825             ) {
826                 let basic_block = & $($mutability)? body[location.block];
827                 if basic_block.statements.len() == location.statement_index {
828                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
829                         self.visit_terminator(terminator, location)
830                     }
831                 } else {
832                     let statement = & $($mutability)?
833                         basic_block.statements[location.statement_index];
834                     self.visit_statement(statement, location)
835                 }
836             }
837         }
838     }
839 }
840
841 macro_rules! visit_place_fns {
842     (mut) => (
843         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
844
845         fn super_place(
846             &mut self,
847             place: &mut Place<'tcx>,
848             context: PlaceContext,
849             location: Location,
850         ) {
851             self.visit_place_base(&mut place.base, context, location);
852
853             if let Some(new_projection) = self.process_projection(&place.projection) {
854                 place.projection = self.tcx().intern_place_elems(&new_projection);
855             }
856         }
857
858         fn process_projection(
859             &mut self,
860             projection: &'a [PlaceElem<'tcx>],
861         ) -> Option<Vec<PlaceElem<'tcx>>> {
862             let mut projection = Cow::Borrowed(projection);
863
864             for i in 0..projection.len() {
865                 if let Some(elem) = projection.get(i) {
866                     if let Some(elem) = self.process_projection_elem(elem) {
867                         // This converts the borrowed projection into `Cow::Owned(_)` and returns a
868                         // clone of the projection so we can mutate and reintern later.
869                         let vec = projection.to_mut();
870                         vec[i] = elem;
871                     }
872                 }
873             }
874
875             match projection {
876                 Cow::Borrowed(_) => None,
877                 Cow::Owned(vec) => Some(vec),
878             }
879         }
880
881         fn process_projection_elem(
882             &mut self,
883             _elem: &PlaceElem<'tcx>,
884         ) -> Option<PlaceElem<'tcx>> {
885             None
886         }
887     );
888
889     () => (
890         fn visit_projection(
891             &mut self,
892             base: &PlaceBase<'tcx>,
893             projection: &[PlaceElem<'tcx>],
894             context: PlaceContext,
895             location: Location,
896         ) {
897             self.super_projection(base, projection, context, location);
898         }
899
900         fn visit_projection_elem(
901             &mut self,
902             base: &PlaceBase<'tcx>,
903             proj_base: &[PlaceElem<'tcx>],
904             elem: &PlaceElem<'tcx>,
905             context: PlaceContext,
906             location: Location,
907         ) {
908             self.super_projection_elem(base, proj_base, elem, context, location);
909         }
910
911         fn super_place(
912             &mut self,
913             place: &Place<'tcx>,
914             context: PlaceContext,
915             location: Location,
916         ) {
917             let mut context = context;
918
919             if !place.projection.is_empty() {
920                 context = if context.is_mutating_use() {
921                     PlaceContext::MutatingUse(MutatingUseContext::Projection)
922                 } else {
923                     PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
924                 };
925             }
926
927             self.visit_place_base(&place.base, context, location);
928
929             self.visit_projection(&place.base,
930                                   &place.projection,
931                                   context,
932                                   location);
933         }
934
935         fn super_projection(
936             &mut self,
937             base: &PlaceBase<'tcx>,
938             projection: &[PlaceElem<'tcx>],
939             context: PlaceContext,
940             location: Location,
941         ) {
942             let mut cursor = projection;
943             while let [proj_base @ .., elem] = cursor {
944                 cursor = proj_base;
945                 self.visit_projection_elem(base, cursor, elem, context, location);
946             }
947         }
948
949         fn super_projection_elem(
950             &mut self,
951             _base: &PlaceBase<'tcx>,
952             _proj_base: &[PlaceElem<'tcx>],
953             elem: &PlaceElem<'tcx>,
954             _context: PlaceContext,
955             location: Location,
956         ) {
957             match elem {
958                 ProjectionElem::Field(_field, ty) => {
959                     self.visit_ty(ty, TyContext::Location(location));
960                 }
961                 ProjectionElem::Index(local) => {
962                     self.visit_local(
963                         local,
964                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
965                         location
966                     );
967                 }
968                 ProjectionElem::Deref |
969                 ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
970                 ProjectionElem::ConstantIndex { offset: _,
971                                                 min_length: _,
972                                                 from_end: _ } |
973                 ProjectionElem::Downcast(_, _) => {
974                 }
975             }
976         }
977     );
978 }
979
980 make_mir_visitor!(Visitor,);
981 make_mir_visitor!(MutVisitor, mut);
982
983 pub trait MirVisitable<'tcx> {
984     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
985 }
986
987 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
988     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
989         visitor.visit_statement(self, location)
990     }
991 }
992
993 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
994     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
995         visitor.visit_terminator(self, location)
996     }
997 }
998
999 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
1000     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
1001         visitor.visit_terminator(self.as_ref().unwrap(), location)
1002     }
1003 }
1004
1005 /// Extra information passed to `visit_ty` and friends to give context
1006 /// about where the type etc appears.
1007 #[derive(Debug)]
1008 pub enum TyContext {
1009     LocalDecl {
1010         /// The index of the local variable we are visiting.
1011         local: Local,
1012
1013         /// The source location where this local variable was declared.
1014         source_info: SourceInfo,
1015     },
1016
1017     /// The inferred type of a user type annotation.
1018     UserTy(Span),
1019
1020     /// The return type of the function.
1021     ReturnTy(SourceInfo),
1022
1023     YieldTy(SourceInfo),
1024
1025     /// A type found at some location.
1026     Location(Location),
1027 }
1028
1029 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1030 pub enum NonMutatingUseContext {
1031     /// Being inspected in some way, like loading a len.
1032     Inspect,
1033     /// Consumed as part of an operand.
1034     Copy,
1035     /// Consumed as part of an operand.
1036     Move,
1037     /// Shared borrow.
1038     SharedBorrow,
1039     /// Shallow borrow.
1040     ShallowBorrow,
1041     /// Unique borrow.
1042     UniqueBorrow,
1043     /// AddressOf for *const pointer.
1044     AddressOf,
1045     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1046     /// For example, the projection `x.y` is not marked as a mutation in these cases:
1047     ///
1048     ///     z = x.y;
1049     ///     f(&x.y);
1050     ///
1051     Projection,
1052 }
1053
1054 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1055 pub enum MutatingUseContext {
1056     /// Appears as LHS of an assignment.
1057     Store,
1058     /// Can often be treated as a `Store`, but needs to be separate because
1059     /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
1060     /// cannot be simplified the way a `Store`-`Store` can be.
1061     AsmOutput,
1062     /// Destination of a call.
1063     Call,
1064     /// Being dropped.
1065     Drop,
1066     /// Mutable borrow.
1067     Borrow,
1068     /// AddressOf for *mut pointer.
1069     AddressOf,
1070     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1071     /// For example, the projection `x.y` is marked as a mutation in these cases:
1072     ///
1073     ///     x.y = ...;
1074     ///     f(&mut x.y);
1075     ///
1076     Projection,
1077     /// Retagging, a "Stacked Borrows" shadow state operation
1078     Retag,
1079 }
1080
1081 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1082 pub enum NonUseContext {
1083     /// Starting a storage live range.
1084     StorageLive,
1085     /// Ending a storage live range.
1086     StorageDead,
1087     /// User type annotation assertions for NLL.
1088     AscribeUserTy,
1089     /// The data of an user variable, for debug info.
1090     VarDebugInfo,
1091 }
1092
1093 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1094 pub enum PlaceContext {
1095     NonMutatingUse(NonMutatingUseContext),
1096     MutatingUse(MutatingUseContext),
1097     NonUse(NonUseContext),
1098 }
1099
1100 impl PlaceContext {
1101     /// Returns `true` if this place context represents a drop.
1102     pub fn is_drop(&self) -> bool {
1103         match *self {
1104             PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
1105             _ => false,
1106         }
1107     }
1108
1109     /// Returns `true` if this place context represents a borrow.
1110     pub fn is_borrow(&self) -> bool {
1111         match *self {
1112             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
1113             | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
1114             | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
1115             | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true,
1116             _ => false,
1117         }
1118     }
1119
1120     /// Returns `true` if this place context represents a storage live or storage dead marker.
1121     pub fn is_storage_marker(&self) -> bool {
1122         match *self {
1123             PlaceContext::NonUse(NonUseContext::StorageLive)
1124             | PlaceContext::NonUse(NonUseContext::StorageDead) => true,
1125             _ => false,
1126         }
1127     }
1128
1129     /// Returns `true` if this place context represents a storage live marker.
1130     pub fn is_storage_live_marker(&self) -> bool {
1131         match *self {
1132             PlaceContext::NonUse(NonUseContext::StorageLive) => true,
1133             _ => false,
1134         }
1135     }
1136
1137     /// Returns `true` if this place context represents a storage dead marker.
1138     pub fn is_storage_dead_marker(&self) -> bool {
1139         match *self {
1140             PlaceContext::NonUse(NonUseContext::StorageDead) => true,
1141             _ => false,
1142         }
1143     }
1144
1145     /// Returns `true` if this place context represents a use that potentially changes the value.
1146     pub fn is_mutating_use(&self) -> bool {
1147         match *self {
1148             PlaceContext::MutatingUse(..) => true,
1149             _ => false,
1150         }
1151     }
1152
1153     /// Returns `true` if this place context represents a use that does not change the value.
1154     pub fn is_nonmutating_use(&self) -> bool {
1155         match *self {
1156             PlaceContext::NonMutatingUse(..) => true,
1157             _ => false,
1158         }
1159     }
1160
1161     /// Returns `true` if this place context represents a use.
1162     pub fn is_use(&self) -> bool {
1163         match *self {
1164             PlaceContext::NonUse(..) => false,
1165             _ => true,
1166         }
1167     }
1168
1169     /// Returns `true` if this place context represents an assignment statement.
1170     pub fn is_place_assignment(&self) -> bool {
1171         match *self {
1172             PlaceContext::MutatingUse(MutatingUseContext::Store)
1173             | PlaceContext::MutatingUse(MutatingUseContext::Call)
1174             | PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) => true,
1175             _ => false,
1176         }
1177     }
1178 }