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