]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
Auto merge of #45668 - nikomatsakis:nll-free-region, r=arielb1
[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, Region, Ty, GeneratorInterior};
14 use mir::*;
15 use rustc_const_math::ConstUsize;
16 use syntax_pos::Span;
17
18 // # The MIR Visitor
19 //
20 // ## Overview
21 //
22 // There are two visitors, one for immutable and one for mutable references,
23 // but both are generated by the following macro. The code is written according
24 // to the following conventions:
25 //
26 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
27 // - `visit_foo`, by default, calls `super_foo`
28 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
29 //
30 // This allows you as a user to override `visit_foo` for types are
31 // interested in, and invoke (within that method) call
32 // `self.super_foo` to get the default behavior. Just as in an OO
33 // language, you should never call `super` methods ordinarily except
34 // in that circumstance.
35 //
36 // For the most part, we do not destructure things external to the
37 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
38 // avoids duplication with other visitors like `TypeFoldable`.
39 //
40 // ## Updating
41 //
42 // The code is written in a very deliberate style intended to minimize
43 // the chance of things being overlooked. You'll notice that we always
44 // use pattern matching to reference fields and we ensure that all
45 // matches are exhaustive.
46 //
47 // For example, the `super_basic_block_data` method begins like this:
48 //
49 // ```rust
50 // fn super_basic_block_data(&mut self,
51 //                           block: BasicBlock,
52 //                           data: & $($mutability)* BasicBlockData<'tcx>) {
53 //     let BasicBlockData {
54 //         ref $($mutability)* statements,
55 //         ref $($mutability)* terminator,
56 //         is_cleanup: _
57 //     } = *data;
58 //
59 //     for statement in statements {
60 //         self.visit_statement(block, statement);
61 //     }
62 //
63 //     ...
64 // }
65 // ```
66 //
67 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
68 // rather than writing `data.statements` in the body. This is because if one
69 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
70 // and hence one will (hopefully) invoke the correct visit methods (if any).
71 //
72 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
73 // That means you never write `..` to skip over fields, nor do you write `_`
74 // to skip over variants in a `match`.
75 //
76 // The only place that `_` is acceptable is to match a field (or
77 // variant argument) that does not require visiting, as in
78 // `is_cleanup` above.
79
80 macro_rules! make_mir_visitor {
81     ($visitor_trait_name:ident, $($mutability:ident)*) => {
82         pub trait $visitor_trait_name<'tcx> {
83             // Override these, and call `self.super_xxx` to revert back to the
84             // default behavior.
85
86             fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
87                 self.super_mir(mir);
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_visibility_scope_data(&mut self,
97                                            scope_data: & $($mutability)* VisibilityScopeData) {
98                 self.super_visibility_scope_data(scope_data);
99             }
100
101             fn visit_statement(&mut self,
102                                block: BasicBlock,
103                                statement: & $($mutability)* Statement<'tcx>,
104                                location: Location) {
105                 self.super_statement(block, statement, location);
106             }
107
108             fn visit_assign(&mut self,
109                             block: BasicBlock,
110                             lvalue: & $($mutability)* Lvalue<'tcx>,
111                             rvalue: & $($mutability)* Rvalue<'tcx>,
112                             location: Location) {
113                 self.super_assign(block, lvalue, rvalue, location);
114             }
115
116             fn visit_terminator(&mut self,
117                                 block: BasicBlock,
118                                 terminator: & $($mutability)* Terminator<'tcx>,
119                                 location: Location) {
120                 self.super_terminator(block, terminator, location);
121             }
122
123             fn visit_terminator_kind(&mut self,
124                                      block: BasicBlock,
125                                      kind: & $($mutability)* TerminatorKind<'tcx>,
126                                      location: Location) {
127                 self.super_terminator_kind(block, kind, location);
128             }
129
130             fn visit_assert_message(&mut self,
131                                     msg: & $($mutability)* AssertMessage<'tcx>,
132                                     location: Location) {
133                 self.super_assert_message(msg, location);
134             }
135
136             fn visit_rvalue(&mut self,
137                             rvalue: & $($mutability)* Rvalue<'tcx>,
138                             location: Location) {
139                 self.super_rvalue(rvalue, location);
140             }
141
142             fn visit_operand(&mut self,
143                              operand: & $($mutability)* Operand<'tcx>,
144                              location: Location) {
145                 self.super_operand(operand, location);
146             }
147
148             fn visit_lvalue(&mut self,
149                             lvalue: & $($mutability)* Lvalue<'tcx>,
150                             context: LvalueContext<'tcx>,
151                             location: Location) {
152                 self.super_lvalue(lvalue, context, location);
153             }
154
155             fn visit_static(&mut self,
156                             static_: & $($mutability)* Static<'tcx>,
157                             context: LvalueContext<'tcx>,
158                             location: Location) {
159                 self.super_static(static_, context, location);
160             }
161
162             fn visit_projection(&mut self,
163                                 lvalue: & $($mutability)* LvalueProjection<'tcx>,
164                                 context: LvalueContext<'tcx>,
165                                 location: Location) {
166                 self.super_projection(lvalue, context, location);
167             }
168
169             fn visit_projection_elem(&mut self,
170                                      lvalue: & $($mutability)* LvalueElem<'tcx>,
171                                      context: LvalueContext<'tcx>,
172                                      location: Location) {
173                 self.super_projection_elem(lvalue, context, location);
174             }
175
176             fn visit_branch(&mut self,
177                             source: BasicBlock,
178                             target: BasicBlock) {
179                 self.super_branch(source, target);
180             }
181
182             fn visit_constant(&mut self,
183                               constant: & $($mutability)* Constant<'tcx>,
184                               location: Location) {
185                 self.super_constant(constant, location);
186             }
187
188             fn visit_literal(&mut self,
189                              literal: & $($mutability)* Literal<'tcx>,
190                              location: Location) {
191                 self.super_literal(literal, location);
192             }
193
194             fn visit_def_id(&mut self,
195                             def_id: & $($mutability)* DefId,
196                             _: Location) {
197                 self.super_def_id(def_id);
198             }
199
200             fn visit_span(&mut self,
201                           span: & $($mutability)* Span) {
202                 self.super_span(span);
203             }
204
205             fn visit_source_info(&mut self,
206                                  source_info: & $($mutability)* SourceInfo) {
207                 self.super_source_info(source_info);
208             }
209
210             fn visit_ty(&mut self,
211                         ty: & $($mutability)* Ty<'tcx>,
212                         _: TyContext) {
213                 self.super_ty(ty);
214             }
215
216             fn visit_region(&mut self,
217                             region: & $($mutability)* ty::Region<'tcx>,
218                             _: Location) {
219                 self.super_region(region);
220             }
221
222             fn visit_const(&mut self,
223                            constant: & $($mutability)* &'tcx ty::Const<'tcx>,
224                            _: Location) {
225                 self.super_const(constant);
226             }
227
228             fn visit_substs(&mut self,
229                             substs: & $($mutability)* &'tcx Substs<'tcx>,
230                             _: Location) {
231                 self.super_substs(substs);
232             }
233
234             fn visit_closure_substs(&mut self,
235                                     substs: & $($mutability)* ClosureSubsts<'tcx>,
236                                     _: Location) {
237                 self.super_closure_substs(substs);
238             }
239
240             fn visit_generator_interior(&mut self,
241                                     interior: & $($mutability)* GeneratorInterior<'tcx>,
242                                     _: Location) {
243                 self.super_generator_interior(interior);
244             }
245
246             fn visit_const_int(&mut self,
247                                const_int: &ConstInt,
248                                _: Location) {
249                 self.super_const_int(const_int);
250             }
251
252             fn visit_const_usize(&mut self,
253                                  const_usize: & $($mutability)* ConstUsize,
254                                  _: Location) {
255                 self.super_const_usize(const_usize);
256             }
257
258             fn visit_local_decl(&mut self,
259                                 local: Local,
260                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
261                 self.super_local_decl(local, local_decl);
262             }
263
264             fn visit_local(&mut self,
265                             _local: & $($mutability)* Local,
266                             _context: LvalueContext<'tcx>,
267                             _location: Location) {
268             }
269
270             fn visit_visibility_scope(&mut self,
271                                       scope: & $($mutability)* VisibilityScope) {
272                 self.super_visibility_scope(scope);
273             }
274
275             // The `super_xxx` methods comprise the default behavior and are
276             // not meant to be overridden.
277
278             fn super_mir(&mut self,
279                          mir: & $($mutability)* Mir<'tcx>) {
280                 // for best performance, we want to use an iterator rather
281                 // than a for-loop, to avoid calling Mir::invalidate for
282                 // each basic block.
283                 macro_rules! basic_blocks {
284                     (mut) => (mir.basic_blocks_mut().iter_enumerated_mut());
285                     () => (mir.basic_blocks().iter_enumerated());
286                 };
287                 for (bb, data) in basic_blocks!($($mutability)*) {
288                     self.visit_basic_block_data(bb, data);
289                 }
290
291                 for scope in &$($mutability)* mir.visibility_scopes {
292                     self.visit_visibility_scope_data(scope);
293                 }
294
295                 let lookup = TyContext::SourceInfo(SourceInfo {
296                     span: mir.span,
297                     scope: ARGUMENT_VISIBILITY_SCOPE,
298                 });
299                 self.visit_ty(&$($mutability)* mir.return_ty, lookup);
300
301                 for local in mir.local_decls.indices() {
302                     self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
303                 }
304
305                 self.visit_span(&$($mutability)* mir.span);
306             }
307
308             fn super_basic_block_data(&mut self,
309                                       block: BasicBlock,
310                                       data: & $($mutability)* BasicBlockData<'tcx>) {
311                 let BasicBlockData {
312                     ref $($mutability)* statements,
313                     ref $($mutability)* terminator,
314                     is_cleanup: _
315                 } = *data;
316
317                 let mut index = 0;
318                 for statement in statements {
319                     let location = Location { block: block, statement_index: index };
320                     self.visit_statement(block, statement, location);
321                     index += 1;
322                 }
323
324                 if let Some(ref $($mutability)* terminator) = *terminator {
325                     let location = Location { block: block, statement_index: index };
326                     self.visit_terminator(block, terminator, location);
327                 }
328             }
329
330             fn super_visibility_scope_data(&mut self,
331                                            scope_data: & $($mutability)* VisibilityScopeData) {
332                 let VisibilityScopeData {
333                     ref $($mutability)* span,
334                     ref $($mutability)* parent_scope,
335                 } = *scope_data;
336
337                 self.visit_span(span);
338                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
339                     self.visit_visibility_scope(parent_scope);
340                 }
341             }
342
343             fn super_statement(&mut self,
344                                block: BasicBlock,
345                                statement: & $($mutability)* Statement<'tcx>,
346                                location: Location) {
347                 let Statement {
348                     ref $($mutability)* source_info,
349                     ref $($mutability)* kind,
350                 } = *statement;
351
352                 self.visit_source_info(source_info);
353                 match *kind {
354                     StatementKind::Assign(ref $($mutability)* lvalue,
355                                           ref $($mutability)* rvalue) => {
356                         self.visit_assign(block, lvalue, rvalue, location);
357                     }
358                     StatementKind::EndRegion(_) => {}
359                     StatementKind::Validate(_, ref $($mutability)* lvalues) => {
360                         for operand in lvalues {
361                             self.visit_lvalue(& $($mutability)* operand.lval,
362                                               LvalueContext::Validate, location);
363                             self.visit_ty(& $($mutability)* operand.ty,
364                                           TyContext::Location(location));
365                         }
366                     }
367                     StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
368                         self.visit_lvalue(lvalue, LvalueContext::Store, location);
369                     }
370                     StatementKind::StorageLive(ref $($mutability)* local) => {
371                         self.visit_local(local, LvalueContext::StorageLive, location);
372                     }
373                     StatementKind::StorageDead(ref $($mutability)* local) => {
374                         self.visit_local(local, LvalueContext::StorageDead, location);
375                     }
376                     StatementKind::InlineAsm { ref $($mutability)* outputs,
377                                                ref $($mutability)* inputs,
378                                                asm: _ } => {
379                         for output in & $($mutability)* outputs[..] {
380                             self.visit_lvalue(output, LvalueContext::Store, location);
381                         }
382                         for input in & $($mutability)* inputs[..] {
383                             self.visit_operand(input, location);
384                         }
385                     }
386                     StatementKind::Nop => {}
387                 }
388             }
389
390             fn super_assign(&mut self,
391                             _block: BasicBlock,
392                             lvalue: &$($mutability)* Lvalue<'tcx>,
393                             rvalue: &$($mutability)* Rvalue<'tcx>,
394                             location: Location) {
395                 self.visit_lvalue(lvalue, LvalueContext::Store, location);
396                 self.visit_rvalue(rvalue, location);
397             }
398
399             fn super_terminator(&mut self,
400                                 block: BasicBlock,
401                                 terminator: &$($mutability)* Terminator<'tcx>,
402                                 location: Location) {
403                 let Terminator {
404                     ref $($mutability)* source_info,
405                     ref $($mutability)* kind,
406                 } = *terminator;
407
408                 self.visit_source_info(source_info);
409                 self.visit_terminator_kind(block, kind, location);
410             }
411
412             fn super_terminator_kind(&mut self,
413                                      block: BasicBlock,
414                                      kind: & $($mutability)* TerminatorKind<'tcx>,
415                                      source_location: Location) {
416                 match *kind {
417                     TerminatorKind::Goto { target } => {
418                         self.visit_branch(block, target);
419                     }
420
421                     TerminatorKind::SwitchInt { ref $($mutability)* discr,
422                                                 ref $($mutability)* switch_ty,
423                                                 ref values,
424                                                 ref targets } => {
425                         self.visit_operand(discr, source_location);
426                         self.visit_ty(switch_ty, TyContext::Location(source_location));
427                         for value in &values[..] {
428                             self.visit_const_int(value, source_location);
429                         }
430                         for &target in targets {
431                             self.visit_branch(block, target);
432                         }
433                     }
434
435                     TerminatorKind::Resume |
436                     TerminatorKind::Return |
437                     TerminatorKind::GeneratorDrop |
438                     TerminatorKind::Unreachable => {
439                     }
440
441                     TerminatorKind::Drop { ref $($mutability)* location,
442                                            target,
443                                            unwind } => {
444                         self.visit_lvalue(location, LvalueContext::Drop, source_location);
445                         self.visit_branch(block, target);
446                         unwind.map(|t| self.visit_branch(block, t));
447                     }
448
449                     TerminatorKind::DropAndReplace { ref $($mutability)* location,
450                                                      ref $($mutability)* value,
451                                                      target,
452                                                      unwind } => {
453                         self.visit_lvalue(location, LvalueContext::Drop, source_location);
454                         self.visit_operand(value, source_location);
455                         self.visit_branch(block, target);
456                         unwind.map(|t| self.visit_branch(block, t));
457                     }
458
459                     TerminatorKind::Call { ref $($mutability)* func,
460                                            ref $($mutability)* args,
461                                            ref $($mutability)* destination,
462                                            cleanup } => {
463                         self.visit_operand(func, source_location);
464                         for arg in args {
465                             self.visit_operand(arg, source_location);
466                         }
467                         if let Some((ref $($mutability)* destination, target)) = *destination {
468                             self.visit_lvalue(destination, LvalueContext::Call, source_location);
469                             self.visit_branch(block, target);
470                         }
471                         cleanup.map(|t| self.visit_branch(block, t));
472                     }
473
474                     TerminatorKind::Assert { ref $($mutability)* cond,
475                                              expected: _,
476                                              ref $($mutability)* msg,
477                                              target,
478                                              cleanup } => {
479                         self.visit_operand(cond, source_location);
480                         self.visit_assert_message(msg, source_location);
481                         self.visit_branch(block, target);
482                         cleanup.map(|t| self.visit_branch(block, t));
483                     }
484
485                     TerminatorKind::Yield { ref $($mutability)* value,
486                                               resume,
487                                               drop } => {
488                         self.visit_operand(value, source_location);
489                         self.visit_branch(block, resume);
490                         drop.map(|t| self.visit_branch(block, t));
491
492                     }
493
494                     TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
495                         self.visit_branch(block, real_target);
496                         for target in imaginary_targets {
497                             self.visit_branch(block, *target);
498                         }
499                     }
500                 }
501             }
502
503             fn super_assert_message(&mut self,
504                                     msg: & $($mutability)* AssertMessage<'tcx>,
505                                     location: Location) {
506                 match *msg {
507                     AssertMessage::BoundsCheck {
508                         ref $($mutability)* len,
509                         ref $($mutability)* index
510                     } => {
511                         self.visit_operand(len, location);
512                         self.visit_operand(index, location);
513                     }
514                     AssertMessage::Math(_) => {},
515                     AssertMessage::GeneratorResumedAfterReturn => {},
516                     AssertMessage::GeneratorResumedAfterPanic => {},
517                 }
518             }
519
520             fn super_rvalue(&mut self,
521                             rvalue: & $($mutability)* Rvalue<'tcx>,
522                             location: Location) {
523                 match *rvalue {
524                     Rvalue::Use(ref $($mutability)* operand) => {
525                         self.visit_operand(operand, location);
526                     }
527
528                     Rvalue::Repeat(ref $($mutability)* value,
529                                    ref $($mutability)* length) => {
530                         self.visit_operand(value, location);
531                         self.visit_const_usize(length, location);
532                     }
533
534                     Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
535                         self.visit_region(r, location);
536                         self.visit_lvalue(path, LvalueContext::Borrow {
537                             region: *r,
538                             kind: bk
539                         }, location);
540                     }
541
542                     Rvalue::Len(ref $($mutability)* path) => {
543                         self.visit_lvalue(path, LvalueContext::Inspect, location);
544                     }
545
546                     Rvalue::Cast(_cast_kind,
547                                  ref $($mutability)* operand,
548                                  ref $($mutability)* ty) => {
549                         self.visit_operand(operand, location);
550                         self.visit_ty(ty, TyContext::Location(location));
551                     }
552
553                     Rvalue::BinaryOp(_bin_op,
554                                      ref $($mutability)* lhs,
555                                      ref $($mutability)* rhs) |
556                     Rvalue::CheckedBinaryOp(_bin_op,
557                                      ref $($mutability)* lhs,
558                                      ref $($mutability)* rhs) => {
559                         self.visit_operand(lhs, location);
560                         self.visit_operand(rhs, location);
561                     }
562
563                     Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
564                         self.visit_operand(op, location);
565                     }
566
567                     Rvalue::Discriminant(ref $($mutability)* lvalue) => {
568                         self.visit_lvalue(lvalue, LvalueContext::Inspect, location);
569                     }
570
571                     Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
572                         self.visit_ty(ty, TyContext::Location(location));
573                     }
574
575                     Rvalue::Aggregate(ref $($mutability)* kind,
576                                       ref $($mutability)* operands) => {
577                         let kind = &$($mutability)* **kind;
578                         match *kind {
579                             AggregateKind::Array(ref $($mutability)* ty) => {
580                                 self.visit_ty(ty, TyContext::Location(location));
581                             }
582                             AggregateKind::Tuple => {
583                             }
584                             AggregateKind::Adt(_adt_def,
585                                                _variant_index,
586                                                ref $($mutability)* substs,
587                                                _active_field_index) => {
588                                 self.visit_substs(substs, location);
589                             }
590                             AggregateKind::Closure(ref $($mutability)* def_id,
591                                                    ref $($mutability)* closure_substs) => {
592                                 self.visit_def_id(def_id, location);
593                                 self.visit_closure_substs(closure_substs, location);
594                             }
595                             AggregateKind::Generator(ref $($mutability)* def_id,
596                                                    ref $($mutability)* closure_substs,
597                                                    ref $($mutability)* interior) => {
598                                 self.visit_def_id(def_id, location);
599                                 self.visit_closure_substs(closure_substs, location);
600                                 self.visit_generator_interior(interior, location);
601                             }
602                         }
603
604                         for operand in operands {
605                             self.visit_operand(operand, location);
606                         }
607                     }
608                 }
609             }
610
611             fn super_operand(&mut self,
612                              operand: & $($mutability)* Operand<'tcx>,
613                              location: Location) {
614                 match *operand {
615                     Operand::Consume(ref $($mutability)* lvalue) => {
616                         self.visit_lvalue(lvalue, LvalueContext::Consume, location);
617                     }
618                     Operand::Constant(ref $($mutability)* constant) => {
619                         self.visit_constant(constant, location);
620                     }
621                 }
622             }
623
624             fn super_lvalue(&mut self,
625                             lvalue: & $($mutability)* Lvalue<'tcx>,
626                             context: LvalueContext<'tcx>,
627                             location: Location) {
628                 match *lvalue {
629                     Lvalue::Local(ref $($mutability)* local) => {
630                         self.visit_local(local, context, location);
631                     }
632                     Lvalue::Static(ref $($mutability)* static_) => {
633                         self.visit_static(static_, context, location);
634                     }
635                     Lvalue::Projection(ref $($mutability)* proj) => {
636                         self.visit_projection(proj, context, location);
637                     }
638                 }
639             }
640
641             fn super_static(&mut self,
642                             static_: & $($mutability)* Static<'tcx>,
643                             _context: LvalueContext<'tcx>,
644                             location: Location) {
645                 let Static {
646                     ref $($mutability)* def_id,
647                     ref $($mutability)* ty,
648                 } = *static_;
649                 self.visit_def_id(def_id, location);
650                 self.visit_ty(ty, TyContext::Location(location));
651             }
652
653             fn super_projection(&mut self,
654                                 proj: & $($mutability)* LvalueProjection<'tcx>,
655                                 context: LvalueContext<'tcx>,
656                                 location: Location) {
657                 let Projection {
658                     ref $($mutability)* base,
659                     ref $($mutability)* elem,
660                 } = *proj;
661                 let context = if context.is_mutating_use() {
662                     LvalueContext::Projection(Mutability::Mut)
663                 } else {
664                     LvalueContext::Projection(Mutability::Not)
665                 };
666                 self.visit_lvalue(base, context, location);
667                 self.visit_projection_elem(elem, context, location);
668             }
669
670             fn super_projection_elem(&mut self,
671                                      proj: & $($mutability)* LvalueElem<'tcx>,
672                                      _context: LvalueContext<'tcx>,
673                                      location: Location) {
674                 match *proj {
675                     ProjectionElem::Deref => {
676                     }
677                     ProjectionElem::Subslice { from: _, to: _ } => {
678                     }
679                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
680                         self.visit_ty(ty, TyContext::Location(location));
681                     }
682                     ProjectionElem::Index(ref $($mutability)* local) => {
683                         self.visit_local(local, LvalueContext::Consume, location);
684                     }
685                     ProjectionElem::ConstantIndex { offset: _,
686                                                     min_length: _,
687                                                     from_end: _ } => {
688                     }
689                     ProjectionElem::Downcast(_adt_def, _variant_index) => {
690                     }
691                 }
692             }
693
694             fn super_local_decl(&mut self,
695                                 local: Local,
696                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
697                 let LocalDecl {
698                     mutability: _,
699                     ref $($mutability)* ty,
700                     name: _,
701                     ref $($mutability)* source_info,
702                     internal: _,
703                     ref $($mutability)* lexical_scope,
704                     is_user_variable: _,
705                 } = *local_decl;
706
707                 self.visit_ty(ty, TyContext::LocalDecl {
708                     local,
709                     source_info: *source_info,
710                 });
711                 self.visit_source_info(source_info);
712                 self.visit_visibility_scope(lexical_scope);
713             }
714
715             fn super_visibility_scope(&mut self,
716                                       _scope: & $($mutability)* VisibilityScope) {
717             }
718
719             fn super_branch(&mut self,
720                             _source: BasicBlock,
721                             _target: BasicBlock) {
722             }
723
724             fn super_constant(&mut self,
725                               constant: & $($mutability)* Constant<'tcx>,
726                               location: Location) {
727                 let Constant {
728                     ref $($mutability)* span,
729                     ref $($mutability)* ty,
730                     ref $($mutability)* literal,
731                 } = *constant;
732
733                 self.visit_span(span);
734                 self.visit_ty(ty, TyContext::Location(location));
735                 self.visit_literal(literal, location);
736             }
737
738             fn super_literal(&mut self,
739                              literal: & $($mutability)* Literal<'tcx>,
740                              location: Location) {
741                 match *literal {
742                     Literal::Value { ref $($mutability)* value } => {
743                         self.visit_const(value, location);
744                     }
745                     Literal::Promoted { index: _ } => {}
746                 }
747             }
748
749             fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
750             }
751
752             fn super_span(&mut self, _span: & $($mutability)* Span) {
753             }
754
755             fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
756                 let SourceInfo {
757                     ref $($mutability)* span,
758                     ref $($mutability)* scope,
759                 } = *source_info;
760
761                 self.visit_span(span);
762                 self.visit_visibility_scope(scope);
763             }
764
765             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
766             }
767
768             fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) {
769             }
770
771             fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) {
772             }
773
774             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
775             }
776
777             fn super_generator_interior(&mut self,
778                                     _interior: & $($mutability)* GeneratorInterior<'tcx>) {
779             }
780
781             fn super_closure_substs(&mut self,
782                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
783             }
784
785             fn super_const_int(&mut self, _const_int: &ConstInt) {
786             }
787
788             fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
789             }
790
791             // Convenience methods
792
793             fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
794                 let basic_block = & $($mutability)* mir[location.block];
795                 if basic_block.statements.len() == location.statement_index {
796                     if let Some(ref $($mutability)* terminator) = basic_block.terminator {
797                         self.visit_terminator(location.block, terminator, location)
798                     }
799                 } else {
800                     let statement = & $($mutability)*
801                         basic_block.statements[location.statement_index];
802                     self.visit_statement(location.block, statement, location)
803                 }
804             }
805         }
806     }
807 }
808
809 make_mir_visitor!(Visitor,);
810 make_mir_visitor!(MutVisitor,mut);
811
812 /// Extra information passed to `visit_ty` and friends to give context
813 /// about where the type etc appears.
814 #[derive(Copy, Clone, Debug)]
815 pub enum TyContext {
816     LocalDecl {
817         /// The index of the local variable we are visiting.
818         local: Local,
819
820         /// The source location where this local variable was declared.
821         source_info: SourceInfo,
822     },
823
824     Location(Location),
825
826     SourceInfo(SourceInfo),
827 }
828
829 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
830 pub enum LvalueContext<'tcx> {
831     // Appears as LHS of an assignment
832     Store,
833
834     // Dest of a call
835     Call,
836
837     // Being dropped
838     Drop,
839
840     // Being inspected in some way, like loading a len
841     Inspect,
842
843     // Being borrowed
844     Borrow { region: Region<'tcx>, kind: BorrowKind },
845
846     // Used as base for another lvalue, e.g. `x` in `x.y`.
847     //
848     // The `Mutability` argument specifies whether the projection is being performed in order to
849     // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
850     // in these cases:
851     //
852     //     x.y = ...;
853     //     f(&mut x.y);
854     //
855     // But not in these cases:
856     //
857     //     z = x.y;
858     //     f(&x.y);
859     Projection(Mutability),
860
861     // Consumed as part of an operand
862     Consume,
863
864     // Starting and ending a storage live range
865     StorageLive,
866     StorageDead,
867
868     // Validation command
869     Validate,
870 }
871
872 impl<'tcx> LvalueContext<'tcx> {
873     /// Returns true if this lvalue context represents a drop.
874     pub fn is_drop(&self) -> bool {
875         match *self {
876             LvalueContext::Drop => true,
877             _ => false,
878         }
879     }
880
881     /// Returns true if this lvalue context represents a storage live or storage dead marker.
882     pub fn is_storage_marker(&self) -> bool {
883         match *self {
884             LvalueContext::StorageLive | LvalueContext::StorageDead => true,
885             _ => false,
886         }
887     }
888
889     /// Returns true if this lvalue context represents a storage live marker.
890     pub fn is_storage_live_marker(&self) -> bool {
891         match *self {
892             LvalueContext::StorageLive => true,
893             _ => false,
894         }
895     }
896
897     /// Returns true if this lvalue context represents a storage dead marker.
898     pub fn is_storage_dead_marker(&self) -> bool {
899         match *self {
900             LvalueContext::StorageDead => true,
901             _ => false,
902         }
903     }
904
905     /// Returns true if this lvalue context represents a use that potentially changes the value.
906     pub fn is_mutating_use(&self) -> bool {
907         match *self {
908             LvalueContext::Store | LvalueContext::Call |
909             LvalueContext::Borrow { kind: BorrowKind::Mut, .. } |
910             LvalueContext::Projection(Mutability::Mut) |
911             LvalueContext::Drop => true,
912             LvalueContext::Inspect |
913             LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
914             LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
915             LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
916             LvalueContext::StorageLive | LvalueContext::StorageDead |
917             LvalueContext::Validate => false,
918         }
919     }
920
921     /// Returns true if this lvalue context represents a use that does not change the value.
922     pub fn is_nonmutating_use(&self) -> bool {
923         match *self {
924             LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
925             LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
926             LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
927             LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
928             LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
929             LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |
930             LvalueContext::Validate => false,
931         }
932     }
933
934     pub fn is_use(&self) -> bool {
935         self.is_mutating_use() || self.is_nonmutating_use()
936     }
937 }