]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
2c58d35973e73a2c6b7880875cf0824e10016ff4
[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_var_decl(&mut self,
240                               var_decl: & $($mutability)* VarDecl<'tcx>) {
241                 self.super_var_decl(var_decl);
242             }
243
244             fn visit_temp_decl(&mut self,
245                                temp_decl: & $($mutability)* TempDecl<'tcx>) {
246                 self.super_temp_decl(temp_decl);
247             }
248
249             fn visit_arg_decl(&mut self,
250                               arg_decl: & $($mutability)* ArgDecl<'tcx>) {
251                 self.super_arg_decl(arg_decl);
252             }
253
254             fn visit_visibility_scope(&mut self,
255                                       scope: & $($mutability)* VisibilityScope) {
256                 self.super_visibility_scope(scope);
257             }
258
259             // The `super_xxx` methods comprise the default behavior and are
260             // not meant to be overridden.
261
262             fn super_mir(&mut self,
263                          mir: & $($mutability)* Mir<'tcx>) {
264                 for index in 0..mir.basic_blocks().len() {
265                     let block = BasicBlock::new(index);
266                     self.visit_basic_block_data(block, &$($mutability)* mir[block]);
267                 }
268
269                 for scope in &$($mutability)* mir.visibility_scopes {
270                     self.visit_visibility_scope_data(scope);
271                 }
272
273                 self.visit_ty(&$($mutability)* mir.return_ty);
274
275                 for var_decl in &$($mutability)* mir.var_decls {
276                     self.visit_var_decl(var_decl);
277                 }
278
279                 for arg_decl in &$($mutability)* mir.arg_decls {
280                     self.visit_arg_decl(arg_decl);
281                 }
282
283                 for temp_decl in &$($mutability)* mir.temp_decls {
284                     self.visit_temp_decl(temp_decl);
285                 }
286
287                 self.visit_span(&$($mutability)* mir.span);
288             }
289
290             fn super_basic_block_data(&mut self,
291                                       block: BasicBlock,
292                                       data: & $($mutability)* BasicBlockData<'tcx>) {
293                 let BasicBlockData {
294                     ref $($mutability)* statements,
295                     ref $($mutability)* terminator,
296                     is_cleanup: _
297                 } = *data;
298
299                 let mut index = 0;
300                 for statement in statements {
301                     let location = Location { block: block, statement_index: index };
302                     self.visit_statement(block, statement, location);
303                     index += 1;
304                 }
305
306                 if let Some(ref $($mutability)* terminator) = *terminator {
307                     let location = Location { block: block, statement_index: index };
308                     self.visit_terminator(block, terminator, location);
309                 }
310             }
311
312             fn super_visibility_scope_data(&mut self,
313                                            scope_data: & $($mutability)* VisibilityScopeData) {
314                 let VisibilityScopeData {
315                     ref $($mutability)* span,
316                     ref $($mutability)* parent_scope,
317                 } = *scope_data;
318
319                 self.visit_span(span);
320                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
321                     self.visit_visibility_scope(parent_scope);
322                 }
323             }
324
325             fn super_statement(&mut self,
326                                block: BasicBlock,
327                                statement: & $($mutability)* Statement<'tcx>,
328                                location: Location) {
329                 let Statement {
330                     ref $($mutability)* source_info,
331                     ref $($mutability)* kind,
332                 } = *statement;
333
334                 self.visit_source_info(source_info);
335                 match *kind {
336                     StatementKind::Assign(ref $($mutability)* lvalue,
337                                           ref $($mutability)* rvalue) => {
338                         self.visit_assign(block, lvalue, rvalue, location);
339                     }
340                     StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
341                         self.visit_lvalue(lvalue, LvalueContext::Store, location);
342                     }
343                     StatementKind::StorageLive(ref $($mutability)* lvalue) => {
344                         self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
345                     }
346                     StatementKind::StorageDead(ref $($mutability)* lvalue) => {
347                         self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
348                     }
349                     StatementKind::Nop => {}
350                 }
351             }
352
353             fn super_assign(&mut self,
354                             _block: BasicBlock,
355                             lvalue: &$($mutability)* Lvalue<'tcx>,
356                             rvalue: &$($mutability)* Rvalue<'tcx>,
357                             location: Location) {
358                 self.visit_lvalue(lvalue, LvalueContext::Store, location);
359                 self.visit_rvalue(rvalue, location);
360             }
361
362             fn super_terminator(&mut self,
363                                 block: BasicBlock,
364                                 terminator: &$($mutability)* Terminator<'tcx>,
365                                 location: Location) {
366                 let Terminator {
367                     ref $($mutability)* source_info,
368                     ref $($mutability)* kind,
369                 } = *terminator;
370
371                 self.visit_source_info(source_info);
372                 self.visit_terminator_kind(block, kind, location);
373             }
374
375             fn super_terminator_kind(&mut self,
376                                      block: BasicBlock,
377                                      kind: & $($mutability)* TerminatorKind<'tcx>,
378                                      source_location: Location) {
379                 match *kind {
380                     TerminatorKind::Goto { target } => {
381                         self.visit_branch(block, target);
382                     }
383
384                     TerminatorKind::If { ref $($mutability)* cond,
385                                          ref $($mutability)* targets } => {
386                         self.visit_operand(cond, source_location);
387                         for &target in targets.as_slice() {
388                             self.visit_branch(block, target);
389                         }
390                     }
391
392                     TerminatorKind::Switch { ref $($mutability)* discr,
393                                              adt_def: _,
394                                              ref targets } => {
395                         self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
396                         for &target in targets {
397                             self.visit_branch(block, target);
398                         }
399                     }
400
401                     TerminatorKind::SwitchInt { ref $($mutability)* discr,
402                                                 ref $($mutability)* switch_ty,
403                                                 ref $($mutability)* values,
404                                                 ref targets } => {
405                         self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
406                         self.visit_ty(switch_ty);
407                         for value in values {
408                             self.visit_const_val(value, source_location);
409                         }
410                         for &target in targets {
411                             self.visit_branch(block, target);
412                         }
413                     }
414
415                     TerminatorKind::Resume |
416                     TerminatorKind::Return |
417                     TerminatorKind::Unreachable => {
418                     }
419
420                     TerminatorKind::Drop { ref $($mutability)* location,
421                                            target,
422                                            unwind } => {
423                         self.visit_lvalue(location, LvalueContext::Drop, source_location);
424                         self.visit_branch(block, target);
425                         unwind.map(|t| self.visit_branch(block, t));
426                     }
427
428                     TerminatorKind::DropAndReplace { ref $($mutability)* location,
429                                                      ref $($mutability)* value,
430                                                      target,
431                                                      unwind } => {
432                         self.visit_lvalue(location, LvalueContext::Drop, source_location);
433                         self.visit_operand(value, source_location);
434                         self.visit_branch(block, target);
435                         unwind.map(|t| self.visit_branch(block, t));
436                     }
437
438                     TerminatorKind::Call { ref $($mutability)* func,
439                                            ref $($mutability)* args,
440                                            ref $($mutability)* destination,
441                                            cleanup } => {
442                         self.visit_operand(func, source_location);
443                         for arg in args {
444                             self.visit_operand(arg, source_location);
445                         }
446                         if let Some((ref $($mutability)* destination, target)) = *destination {
447                             self.visit_lvalue(destination, LvalueContext::Call, source_location);
448                             self.visit_branch(block, target);
449                         }
450                         cleanup.map(|t| self.visit_branch(block, t));
451                     }
452
453                     TerminatorKind::Assert { ref $($mutability)* cond,
454                                              expected: _,
455                                              ref $($mutability)* msg,
456                                              target,
457                                              cleanup } => {
458                         self.visit_operand(cond, source_location);
459                         self.visit_assert_message(msg, source_location);
460                         self.visit_branch(block, target);
461                         cleanup.map(|t| self.visit_branch(block, t));
462                     }
463                 }
464             }
465
466             fn super_assert_message(&mut self,
467                                     msg: & $($mutability)* AssertMessage<'tcx>,
468                                     location: Location) {
469                 match *msg {
470                     AssertMessage::BoundsCheck {
471                         ref $($mutability)* len,
472                         ref $($mutability)* index
473                     } => {
474                         self.visit_operand(len, location);
475                         self.visit_operand(index, location);
476                     }
477                     AssertMessage::Math(_) => {}
478                 }
479             }
480
481             fn super_rvalue(&mut self,
482                             rvalue: & $($mutability)* Rvalue<'tcx>,
483                             location: Location) {
484                 match *rvalue {
485                     Rvalue::Use(ref $($mutability)* operand) => {
486                         self.visit_operand(operand, location);
487                     }
488
489                     Rvalue::Repeat(ref $($mutability)* value,
490                                    ref $($mutability)* typed_const_val) => {
491                         self.visit_operand(value, location);
492                         self.visit_typed_const_val(typed_const_val, location);
493                     }
494
495                     Rvalue::Ref(r, bk, ref $($mutability)* path) => {
496                         self.visit_lvalue(path, LvalueContext::Borrow {
497                             region: r,
498                             kind: bk
499                         }, location);
500                     }
501
502                     Rvalue::Len(ref $($mutability)* path) => {
503                         self.visit_lvalue(path, LvalueContext::Inspect, location);
504                     }
505
506                     Rvalue::Cast(_cast_kind,
507                                  ref $($mutability)* operand,
508                                  ref $($mutability)* ty) => {
509                         self.visit_operand(operand, location);
510                         self.visit_ty(ty);
511                     }
512
513                     Rvalue::BinaryOp(_bin_op,
514                                      ref $($mutability)* lhs,
515                                      ref $($mutability)* rhs) |
516                     Rvalue::CheckedBinaryOp(_bin_op,
517                                      ref $($mutability)* lhs,
518                                      ref $($mutability)* rhs) => {
519                         self.visit_operand(lhs, location);
520                         self.visit_operand(rhs, location);
521                     }
522
523                     Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
524                         self.visit_operand(op, location);
525                     }
526
527                     Rvalue::Box(ref $($mutability)* ty) => {
528                         self.visit_ty(ty);
529                     }
530
531                     Rvalue::Aggregate(ref $($mutability)* kind,
532                                       ref $($mutability)* operands) => {
533                         match *kind {
534                             AggregateKind::Vec => {
535                             }
536                             AggregateKind::Tuple => {
537                             }
538                             AggregateKind::Adt(_adt_def,
539                                                _variant_index,
540                                                ref $($mutability)* substs,
541                                                _active_field_index) => {
542                                 self.visit_substs(substs);
543                             }
544                             AggregateKind::Closure(ref $($mutability)* def_id,
545                                                    ref $($mutability)* closure_substs) => {
546                                 self.visit_def_id(def_id, location);
547                                 self.visit_closure_substs(closure_substs);
548                             }
549                         }
550
551                         for operand in operands {
552                             self.visit_operand(operand, location);
553                         }
554                     }
555
556                     Rvalue::InlineAsm { ref $($mutability)* outputs,
557                                         ref $($mutability)* inputs,
558                                         asm: _ } => {
559                         for output in & $($mutability)* outputs[..] {
560                             self.visit_lvalue(output, LvalueContext::Store, location);
561                         }
562                         for input in & $($mutability)* inputs[..] {
563                             self.visit_operand(input, location);
564                         }
565                     }
566                 }
567             }
568
569             fn super_operand(&mut self,
570                              operand: & $($mutability)* Operand<'tcx>,
571                              location: Location) {
572                 match *operand {
573                     Operand::Consume(ref $($mutability)* lvalue) => {
574                         self.visit_lvalue(lvalue, LvalueContext::Consume, location);
575                     }
576                     Operand::Constant(ref $($mutability)* constant) => {
577                         self.visit_constant(constant, location);
578                     }
579                 }
580             }
581
582             fn super_lvalue(&mut self,
583                             lvalue: & $($mutability)* Lvalue<'tcx>,
584                             context: LvalueContext<'tcx>,
585                             location: Location) {
586                 match *lvalue {
587                     Lvalue::Var(_) |
588                     Lvalue::Temp(_) |
589                     Lvalue::Arg(_) |
590                     Lvalue::ReturnPointer => {
591                     }
592                     Lvalue::Static(ref $($mutability)* def_id) => {
593                         self.visit_def_id(def_id, location);
594                     }
595                     Lvalue::Projection(ref $($mutability)* proj) => {
596                         self.visit_projection(proj, context, location);
597                     }
598                 }
599             }
600
601             fn super_projection(&mut self,
602                                 proj: & $($mutability)* LvalueProjection<'tcx>,
603                                 context: LvalueContext,
604                                 location: Location) {
605                 let Projection {
606                     ref $($mutability)* base,
607                     ref $($mutability)* elem,
608                 } = *proj;
609                 let context = if context.is_mutating_use() {
610                     LvalueContext::Projection(Mutability::Mut)
611                 } else {
612                     LvalueContext::Projection(Mutability::Not)
613                 };
614                 self.visit_lvalue(base, context, location);
615                 self.visit_projection_elem(elem, context, location);
616             }
617
618             fn super_projection_elem(&mut self,
619                                      proj: & $($mutability)* LvalueElem<'tcx>,
620                                      _context: LvalueContext,
621                                      location: Location) {
622                 match *proj {
623                     ProjectionElem::Deref => {
624                     }
625                     ProjectionElem::Subslice { from: _, to: _ } => {
626                     }
627                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
628                         self.visit_ty(ty);
629                     }
630                     ProjectionElem::Index(ref $($mutability)* operand) => {
631                         self.visit_operand(operand, location);
632                     }
633                     ProjectionElem::ConstantIndex { offset: _,
634                                                     min_length: _,
635                                                     from_end: _ } => {
636                     }
637                     ProjectionElem::Downcast(_adt_def, _variant_index) => {
638                     }
639                 }
640             }
641
642             fn super_var_decl(&mut self,
643                               var_decl: & $($mutability)* VarDecl<'tcx>) {
644                 let VarDecl {
645                     mutability: _,
646                     name: _,
647                     ref $($mutability)* ty,
648                     ref $($mutability)* source_info,
649                 } = *var_decl;
650
651                 self.visit_ty(ty);
652                 self.visit_source_info(source_info);
653             }
654
655             fn super_temp_decl(&mut self,
656                                temp_decl: & $($mutability)* TempDecl<'tcx>) {
657                 let TempDecl {
658                     ref $($mutability)* ty,
659                 } = *temp_decl;
660
661                 self.visit_ty(ty);
662             }
663
664             fn super_arg_decl(&mut self,
665                               arg_decl: & $($mutability)* ArgDecl<'tcx>) {
666                 let ArgDecl {
667                     ref $($mutability)* ty,
668                     spread: _,
669                     debug_name: _
670                 } = *arg_decl;
671
672                 self.visit_ty(ty);
673             }
674
675             fn super_visibility_scope(&mut self,
676                                       _scope: & $($mutability)* VisibilityScope) {
677             }
678
679             fn super_branch(&mut self,
680                             _source: BasicBlock,
681                             _target: BasicBlock) {
682             }
683
684             fn super_constant(&mut self,
685                               constant: & $($mutability)* Constant<'tcx>,
686                               location: Location) {
687                 let Constant {
688                     ref $($mutability)* span,
689                     ref $($mutability)* ty,
690                     ref $($mutability)* literal,
691                 } = *constant;
692
693                 self.visit_span(span);
694                 self.visit_ty(ty);
695                 self.visit_literal(literal, location);
696             }
697
698             fn super_typed_const_val(&mut self,
699                                      constant: & $($mutability)* TypedConstVal<'tcx>,
700                                      location: Location) {
701                 let TypedConstVal {
702                     ref $($mutability)* span,
703                     ref $($mutability)* ty,
704                     ref $($mutability)* value,
705                 } = *constant;
706
707                 self.visit_span(span);
708                 self.visit_ty(ty);
709                 self.visit_const_usize(value, location);
710             }
711
712             fn super_literal(&mut self,
713                              literal: & $($mutability)* Literal<'tcx>,
714                              location: Location) {
715                 match *literal {
716                     Literal::Item { ref $($mutability)* def_id,
717                                     ref $($mutability)* substs } => {
718                         self.visit_def_id(def_id, location);
719                         self.visit_substs(substs);
720                     }
721                     Literal::Value { ref $($mutability)* value } => {
722                         self.visit_const_val(value, location);
723                     }
724                     Literal::Promoted { index: _ } => {}
725                 }
726             }
727
728             fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
729             }
730
731             fn super_span(&mut self, _span: & $($mutability)* Span) {
732             }
733
734             fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
735                 let SourceInfo {
736                     ref $($mutability)* span,
737                     ref $($mutability)* scope,
738                 } = *source_info;
739
740                 self.visit_span(span);
741                 self.visit_visibility_scope(scope);
742             }
743
744             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
745             }
746
747             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
748             }
749
750             fn super_closure_substs(&mut self,
751                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
752             }
753
754             fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
755             }
756
757             fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
758             }
759
760             // Convenience methods
761
762             fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
763                 let basic_block = & $($mutability)* mir[location.block];
764                 if basic_block.statements.len() == location.statement_index {
765                     if let Some(ref $($mutability)* terminator) = basic_block.terminator {
766                         self.visit_terminator(location.block, terminator, location)
767                     }
768                 } else {
769                     let statement = & $($mutability)*
770                         basic_block.statements[location.statement_index];
771                     self.visit_statement(location.block, statement, location)
772                 }
773             }
774         }
775     }
776 }
777
778 make_mir_visitor!(Visitor,);
779 make_mir_visitor!(MutVisitor,mut);
780
781 #[derive(Copy, Clone, Debug)]
782 pub enum LvalueContext<'tcx> {
783     // Appears as LHS of an assignment
784     Store,
785
786     // Dest of a call
787     Call,
788
789     // Being dropped
790     Drop,
791
792     // Being inspected in some way, like loading a len
793     Inspect,
794
795     // Being borrowed
796     Borrow { region: &'tcx Region, kind: BorrowKind },
797
798     // Used as base for another lvalue, e.g. `x` in `x.y`.
799     //
800     // The `Mutability` argument specifies whether the projection is being performed in order to
801     // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
802     // in these cases:
803     //
804     //     x.y = ...;
805     //     f(&mut x.y);
806     //
807     // But not in these cases:
808     //
809     //     z = x.y;
810     //     f(&x.y);
811     Projection(Mutability),
812
813     // Consumed as part of an operand
814     Consume,
815
816     // Starting and ending a storage live range
817     StorageLive,
818     StorageDead,
819 }
820
821 impl<'tcx> LvalueContext<'tcx> {
822     /// Returns true if this lvalue context represents a drop.
823     pub fn is_drop(&self) -> bool {
824         match *self {
825             LvalueContext::Drop => true,
826             _ => false,
827         }
828     }
829
830     /// Returns true if this lvalue context represents a storage live or storage dead marker.
831     pub fn is_storage_marker(&self) -> bool {
832         match *self {
833             LvalueContext::StorageLive | LvalueContext::StorageDead => true,
834             _ => false,
835         }
836     }
837
838     /// Returns true if this lvalue context represents a storage live marker.
839     pub fn is_storage_live_marker(&self) -> bool {
840         match *self {
841             LvalueContext::StorageLive => true,
842             _ => false,
843         }
844     }
845
846     /// Returns true if this lvalue context represents a storage dead marker.
847     pub fn is_storage_dead_marker(&self) -> bool {
848         match *self {
849             LvalueContext::StorageDead => true,
850             _ => false,
851         }
852     }
853
854     /// Returns true if this lvalue context represents a use that potentially changes the value.
855     pub fn is_mutating_use(&self) -> bool {
856         match *self {
857             LvalueContext::Store | LvalueContext::Call |
858             LvalueContext::Borrow { kind: BorrowKind::Mut, .. } |
859             LvalueContext::Projection(Mutability::Mut) |
860             LvalueContext::Drop => true,
861             LvalueContext::Inspect |
862             LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
863             LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
864             LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
865             LvalueContext::StorageLive | LvalueContext::StorageDead => false,
866         }
867     }
868
869     /// Returns true if this lvalue context represents a use that does not change the value.
870     pub fn is_nonmutating_use(&self) -> bool {
871         match *self {
872             LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
873             LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
874             LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
875             LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
876             LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
877             LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false,
878         }
879     }
880
881     pub fn is_use(&self) -> bool {
882         self.is_mutating_use() || self.is_nonmutating_use()
883     }
884 }
885