]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/dataflow/framework/visitor.rs
Auto merge of #75573 - Aaron1011:feature/const-mutation-lint, r=oli-obk
[rust.git] / compiler / rustc_mir / src / dataflow / framework / visitor.rs
1 use rustc_middle::mir::{self, BasicBlock, Location};
2
3 use super::{Analysis, Direction, Results};
4 use crate::dataflow::impls::{borrows::Borrows, EverInitializedPlaces, MaybeUninitializedPlaces};
5
6 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
7 /// dataflow state at that location.
8 pub fn visit_results<F, V>(
9     body: &'mir mir::Body<'tcx>,
10     blocks: impl IntoIterator<Item = BasicBlock>,
11     results: &V,
12     vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
13 ) where
14     V: ResultsVisitable<'tcx, FlowState = F>,
15 {
16     let mut state = results.new_flow_state(body);
17
18     #[cfg(debug_assertions)]
19     let reachable_blocks = mir::traversal::reachable_as_bitset(body);
20
21     for block in blocks {
22         #[cfg(debug_assertions)]
23         assert!(reachable_blocks.contains(block));
24
25         let block_data = &body[block];
26         V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
27     }
28 }
29
30 pub trait ResultsVisitor<'mir, 'tcx> {
31     type FlowState;
32
33     fn visit_block_start(
34         &mut self,
35         _state: &Self::FlowState,
36         _block_data: &'mir mir::BasicBlockData<'tcx>,
37         _block: BasicBlock,
38     ) {
39     }
40
41     /// Called with the `before_statement_effect` of the given statement applied to `state` but not
42     /// its `statement_effect`.
43     fn visit_statement_before_primary_effect(
44         &mut self,
45         _state: &Self::FlowState,
46         _statement: &'mir mir::Statement<'tcx>,
47         _location: Location,
48     ) {
49     }
50
51     /// Called with both the `before_statement_effect` and the `statement_effect` of the given
52     /// statement applied to `state`.
53     fn visit_statement_after_primary_effect(
54         &mut self,
55         _state: &Self::FlowState,
56         _statement: &'mir mir::Statement<'tcx>,
57         _location: Location,
58     ) {
59     }
60
61     /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
62     /// its `terminator_effect`.
63     fn visit_terminator_before_primary_effect(
64         &mut self,
65         _state: &Self::FlowState,
66         _terminator: &'mir mir::Terminator<'tcx>,
67         _location: Location,
68     ) {
69     }
70
71     /// Called with both the `before_terminator_effect` and the `terminator_effect` of the given
72     /// terminator applied to `state`.
73     ///
74     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
75     fn visit_terminator_after_primary_effect(
76         &mut self,
77         _state: &Self::FlowState,
78         _terminator: &'mir mir::Terminator<'tcx>,
79         _location: Location,
80     ) {
81     }
82
83     fn visit_block_end(
84         &mut self,
85         _state: &Self::FlowState,
86         _block_data: &'mir mir::BasicBlockData<'tcx>,
87         _block: BasicBlock,
88     ) {
89     }
90 }
91
92 /// Things that can be visited by a `ResultsVisitor`.
93 ///
94 /// This trait exists so that we can visit the results of multiple dataflow analyses simultaneously.
95 /// DO NOT IMPLEMENT MANUALLY. Instead, use the `impl_visitable` macro below.
96 pub trait ResultsVisitable<'tcx> {
97     type Direction: Direction;
98     type FlowState;
99
100     /// Creates an empty `FlowState` to hold the transient state for these dataflow results.
101     ///
102     /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry`
103     /// before it can be observed by a `ResultsVisitor`.
104     fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState;
105
106     fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
107
108     fn reconstruct_before_statement_effect(
109         &self,
110         state: &mut Self::FlowState,
111         statement: &mir::Statement<'tcx>,
112         location: Location,
113     );
114
115     fn reconstruct_statement_effect(
116         &self,
117         state: &mut Self::FlowState,
118         statement: &mir::Statement<'tcx>,
119         location: Location,
120     );
121
122     fn reconstruct_before_terminator_effect(
123         &self,
124         state: &mut Self::FlowState,
125         terminator: &mir::Terminator<'tcx>,
126         location: Location,
127     );
128
129     fn reconstruct_terminator_effect(
130         &self,
131         state: &mut Self::FlowState,
132         terminator: &mir::Terminator<'tcx>,
133         location: Location,
134     );
135 }
136
137 impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
138 where
139     A: Analysis<'tcx>,
140 {
141     type FlowState = A::Domain;
142
143     type Direction = A::Direction;
144
145     fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
146         self.analysis.bottom_value(body)
147     }
148
149     fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
150         state.clone_from(&self.entry_set_for_block(block));
151     }
152
153     fn reconstruct_before_statement_effect(
154         &self,
155         state: &mut Self::FlowState,
156         stmt: &mir::Statement<'tcx>,
157         loc: Location,
158     ) {
159         self.analysis.apply_before_statement_effect(state, stmt, loc);
160     }
161
162     fn reconstruct_statement_effect(
163         &self,
164         state: &mut Self::FlowState,
165         stmt: &mir::Statement<'tcx>,
166         loc: Location,
167     ) {
168         self.analysis.apply_statement_effect(state, stmt, loc);
169     }
170
171     fn reconstruct_before_terminator_effect(
172         &self,
173         state: &mut Self::FlowState,
174         term: &mir::Terminator<'tcx>,
175         loc: Location,
176     ) {
177         self.analysis.apply_before_terminator_effect(state, term, loc);
178     }
179
180     fn reconstruct_terminator_effect(
181         &self,
182         state: &mut Self::FlowState,
183         term: &mir::Terminator<'tcx>,
184         loc: Location,
185     ) {
186         self.analysis.apply_terminator_effect(state, term, loc);
187     }
188 }
189
190 /// A tuple with named fields that can hold either the results or the transient state of the
191 /// dataflow analyses used by the borrow checker.
192 #[derive(Debug)]
193 pub struct BorrowckAnalyses<B, U, E> {
194     pub borrows: B,
195     pub uninits: U,
196     pub ever_inits: E,
197 }
198
199 /// The results of the dataflow analyses used by the borrow checker.
200 pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
201     Results<'tcx, Borrows<'mir, 'tcx>>,
202     Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
203     Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
204 >;
205
206 /// The transient state of the dataflow analyses used by the borrow checker.
207 pub type BorrowckFlowState<'mir, 'tcx> =
208     <BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
209
210 macro_rules! impl_visitable {
211     ( $(
212         $T:ident { $( $field:ident : $A:ident ),* $(,)? }
213     )* ) => { $(
214         impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
215         where
216             $( $A: Analysis<'tcx, Direction = D>, )*
217         {
218             type Direction = D;
219             type FlowState = $T<$( $A::Domain ),*>;
220
221             fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
222                 $T {
223                     $( $field: self.$field.analysis.bottom_value(body) ),*
224                 }
225             }
226
227             fn reset_to_block_entry(
228                 &self,
229                 state: &mut Self::FlowState,
230                 block: BasicBlock,
231             ) {
232                 $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
233             }
234
235             fn reconstruct_before_statement_effect(
236                 &self,
237                 state: &mut Self::FlowState,
238                 stmt: &mir::Statement<'tcx>,
239                 loc: Location,
240             ) {
241                 $( self.$field.analysis
242                     .apply_before_statement_effect(&mut state.$field, stmt, loc); )*
243             }
244
245             fn reconstruct_statement_effect(
246                 &self,
247                 state: &mut Self::FlowState,
248                 stmt: &mir::Statement<'tcx>,
249                 loc: Location,
250             ) {
251                 $( self.$field.analysis
252                     .apply_statement_effect(&mut state.$field, stmt, loc); )*
253             }
254
255             fn reconstruct_before_terminator_effect(
256                 &self,
257                 state: &mut Self::FlowState,
258                 term: &mir::Terminator<'tcx>,
259                 loc: Location,
260             ) {
261                 $( self.$field.analysis
262                     .apply_before_terminator_effect(&mut state.$field, term, loc); )*
263             }
264
265             fn reconstruct_terminator_effect(
266                 &self,
267                 state: &mut Self::FlowState,
268                 term: &mir::Terminator<'tcx>,
269                 loc: Location,
270             ) {
271                 $( self.$field.analysis
272                     .apply_terminator_effect(&mut state.$field, term, loc); )*
273             }
274         }
275     )* }
276 }
277
278 impl_visitable! {
279     BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
280 }