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