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