7
7
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
+ //! # The MIR Visitor
11
+ //!
12
+ //! ## Overview
13
+ //!
14
+ //! There are two visitors, one for immutable and one for mutable references,
15
+ //! but both are generated by the following macro. The code is written according
16
+ //! to the following conventions:
17
+ //!
18
+ //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
19
+ //! - `visit_foo`, by default, calls `super_foo`
20
+ //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
21
+ //!
22
+ //! This allows you as a user to override `visit_foo` for types are
23
+ //! interested in, and invoke (within that method) call
24
+ //! `self.super_foo` to get the default behavior. Just as in an OO
25
+ //! language, you should never call `super` methods ordinarily except
26
+ //! in that circumstance.
27
+ //!
28
+ //! For the most part, we do not destructure things external to the
29
+ //! MIR, e.g. types, spans, etc, but simply visit them and stop. This
30
+ //! avoids duplication with other visitors like `TypeFoldable`. But
31
+ //! there is one exception: we do destructure the `FnOutput` to reach
32
+ //! the type within. Just because.
33
+ //!
34
+ //! ## Updating
35
+ //!
36
+ //! The code is written in a very deliberate style intended to minimize
37
+ //! the chance of things being overlooked. You'll notice that we always
38
+ //! use pattern matching to reference fields and we ensure that all
39
+ //! matches are exhaustive.
40
+ //!
41
+ //! For example, the `super_basic_block_data` method begins like this:
42
+ //!
43
+ //! ```rust
44
+ //! fn super_basic_block_data(&mut self,
45
+ //! block: BasicBlock,
46
+ //! data: & $($mutability)* BasicBlockData<'tcx>) {
47
+ //! let BasicBlockData {
48
+ //! ref $($mutability)* statements,
49
+ //! ref $($mutability)* terminator,
50
+ //! is_cleanup: _
51
+ //! } = *data;
52
+ //!
53
+ //! for statement in statements {
54
+ //! self.visit_statement(block, statement);
55
+ //! }
56
+ //!
57
+ //! ...
58
+ //! }
59
+ //! ```
60
+ //!
61
+ //! Here we used `let BasicBlockData { <fields> } = *data` deliberately,
62
+ //! rather than writing `data.statements` in the body. This is because if one
63
+ //! adds a new field to `BasicBlockData`, one will be forced to revise this code,
64
+ //! and hence one will (hopefully) invoke the correct visit methods (if any).
65
+ //!
66
+ //! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
67
+ //! That means you never write `..` to skip over fields, nor do you write `_`
68
+ //! to skip over variants in a `match`.
69
+ //!
70
+ //! The only place that `_` is acceptable is to match a field (or
71
+ //! variant argument) that does not require visiting, as in
72
+ //! `is_cleanup` above.
10
73
11
74
use middle:: const_val:: ConstVal ;
12
75
use hir:: def_id:: DefId ;
@@ -18,68 +81,6 @@ use rustc_data_structures::tuple_slice::TupleSlice;
18
81
use rustc_data_structures:: indexed_vec:: Idx ;
19
82
use syntax_pos:: Span ;
20
83
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
84
macro_rules! make_mir_visitor {
84
85
( $visitor_trait_name: ident, $( $mutability: ident) * ) => {
85
86
pub trait $visitor_trait_name<' tcx> {
@@ -419,7 +420,7 @@ macro_rules! make_mir_visitor {
419
420
self . visit_operand( arg) ;
420
421
}
421
422
if let Some ( ( ref $( $mutability) * destination, target) ) = * destination {
422
- self . visit_lvalue( destination, LvalueContext :: Call ) ;
423
+ self . visit_lvalue( destination, LvalueContext :: CallStore ) ;
423
424
self . visit_branch( block, target) ;
424
425
}
425
426
cleanup. map( |t| self . visit_branch( block, t) ) ;
@@ -529,7 +530,7 @@ macro_rules! make_mir_visitor {
529
530
ref $( $mutability) * inputs,
530
531
asm: _ } => {
531
532
for output in & $( $mutability) * outputs[ ..] {
532
- self . visit_lvalue( output, LvalueContext :: Store ) ;
533
+ self . visit_lvalue( output, LvalueContext :: AsmOutput ) ;
533
534
}
534
535
for input in & $( $mutability) * inputs[ ..] {
535
536
self . visit_operand( input) ;
@@ -723,33 +724,38 @@ macro_rules! make_mir_visitor {
723
724
make_mir_visitor ! ( Visitor , ) ;
724
725
make_mir_visitor ! ( MutVisitor , mut ) ;
725
726
726
- #[ derive( Copy , Clone , Debug ) ]
727
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
727
728
pub enum LvalueContext {
728
- // Appears as LHS of an assignment
729
+ /// Appears as LHS of an assignment
729
730
Store ,
730
731
731
- // Dest of a call
732
- Call ,
732
+ /// Dest of a call
733
+ CallStore ,
733
734
734
- // Being dropped
735
+ /// Being dropped
735
736
Drop ,
736
737
737
- // Being inspected in some way, like loading a len
738
+ /// Being inspected in some way, like loading a len
738
739
Inspect ,
739
740
740
- // Being borrowed
741
+ /// Being borrowed
741
742
Borrow { region : Region , kind : BorrowKind } ,
742
743
743
- // Being sliced -- this should be same as being borrowed, probably
744
+ /// Being sliced -- this should be same as being borrowed, probably
744
745
Slice { from_start : usize , from_end : usize } ,
745
746
746
- // Used as base for another lvalue, e.g. `x` in `x.y`
747
+ /// Used as base for another lvalue, e.g. `x` in `x.y`
747
748
Projection ,
748
749
749
- // Consumed as part of an operand
750
+ /// Consumed as part of an operand
750
751
Consume ,
751
752
752
- // Starting and ending a storage live range
753
+ /// Starting and ending a storage live range
753
754
StorageLive ,
754
755
StorageDead ,
756
+
757
+ /// “output” from inline asm.
758
+ ///
759
+ /// Cannot be interpreted as a store, because assembly may choose to ignore it.
760
+ AsmOutput
755
761
}
0 commit comments