Skip to content

Commit c64dfd7

Browse files
Add a Visitor for dataflow results
1 parent 1ec9917 commit c64dfd7

File tree

2 files changed

+275
-0
lines changed

2 files changed

+275
-0
lines changed

src/librustc_mir/dataflow/generic/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ use crate::dataflow::BottomValue;
4545
mod cursor;
4646
mod engine;
4747
mod graphviz;
48+
mod visitor;
4849

4950
pub use self::cursor::{ResultsCursor, ResultsRefCursor};
5051
pub use self::engine::Engine;
52+
pub use self::visitor::{visit_results, ResultsVisitor};
53+
pub use self::visitor::{BorrowckFlowState, BorrowckResults};
5154

5255
/// A dataflow analysis that has converged to fixpoint.
5356
pub struct Results<'tcx, A>
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
use rustc::mir::{self, BasicBlock, Location};
2+
use rustc_index::bit_set::BitSet;
3+
4+
use super::{Analysis, Results};
5+
use 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.
9+
pub 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(&mut state, stmt, loc);
26+
27+
results.reconstruct_statement_effect(&mut state, stmt, loc);
28+
vis.visit_statement_exit(&mut 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(&mut state, term, loc);
36+
37+
results.reconstruct_terminator_effect(&mut state, term, loc);
38+
vis.visit_terminator_exit(&mut state, term, loc);
39+
}
40+
}
41+
42+
pub 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.
92+
pub 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+
132+
impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
133+
where
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)]
186+
pub 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.
193+
pub 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.
200+
pub type BorrowckFlowState<'mir, 'tcx> =
201+
<BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
202+
203+
macro_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+
270+
impl_visitable! {
271+
BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
272+
}

0 commit comments

Comments
 (0)