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