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