1
1
//! Propagate `Qualif`s between locals and query the results.
2
2
//!
3
- //! This also contains the dataflow analysis used to track `Qualif`s on complex control-flow
4
- //! graphs.
3
+ //! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs.
5
4
6
5
use rustc:: mir:: visit:: Visitor ;
7
6
use rustc:: mir:: { self , BasicBlock , Local , Location } ;
8
7
use rustc_index:: bit_set:: BitSet ;
9
8
10
- use std:: cell:: RefCell ;
11
9
use std:: marker:: PhantomData ;
12
10
13
11
use crate :: dataflow:: { self as old_dataflow, generic as dataflow} ;
14
12
use super :: { Item , Qualif } ;
15
- use self :: old_dataflow:: IndirectlyMutableLocals ;
16
13
17
14
/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
18
- /// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver` .
15
+ /// `FlowSensitiveAnalysis`.
19
16
///
20
17
/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
21
18
/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via
@@ -147,145 +144,6 @@ where
147
144
}
148
145
}
149
146
150
- /// Types that can compute the qualifs of each local at each location in a `mir::Body`.
151
- ///
152
- /// Code that wishes to use a `QualifResolver` must call `visit_{statement,terminator}` for each
153
- /// statement or terminator, processing blocks in reverse post-order beginning from the
154
- /// `START_BLOCK`. Calling code may optionally call `get` after visiting each statement or
155
- /// terminator to query the qualification state immediately before that statement or terminator.
156
- ///
157
- /// These conditions are much more restrictive than woud be required by `FlowSensitiveResolver`
158
- /// alone. This is to allow a linear, on-demand `TempPromotionResolver` that can operate
159
- /// efficiently on simple CFGs.
160
- pub trait QualifResolver < Q > {
161
- /// Get the qualifs of each local at the last location visited.
162
- ///
163
- /// This takes `&mut self` so qualifs can be computed lazily.
164
- fn get ( & mut self ) -> & BitSet < Local > ;
165
-
166
- /// A convenience method for `self.get().contains(local)`.
167
- fn contains ( & mut self , local : Local ) -> bool {
168
- self . get ( ) . contains ( local)
169
- }
170
-
171
- /// Resets the resolver to the `START_BLOCK`. This allows a resolver to be reused
172
- /// for multiple passes over a `mir::Body`.
173
- fn reset ( & mut self ) ;
174
- }
175
-
176
- pub type IndirectlyMutableResults < ' mir , ' tcx > =
177
- old_dataflow:: DataflowResultsCursor < ' mir , ' tcx , IndirectlyMutableLocals < ' mir , ' tcx > > ;
178
-
179
- /// A resolver for qualifs that works on arbitrarily complex CFGs.
180
- ///
181
- /// As soon as a `Local` becomes writable through a reference (as determined by the
182
- /// `IndirectlyMutableLocals` dataflow pass), we must assume that it takes on all other qualifs
183
- /// possible for its type. This is because no effort is made to track qualifs across indirect
184
- /// assignments (e.g. `*p = x` or calls to opaque functions).
185
- ///
186
- /// It is possible to be more precise here by waiting until an indirect assignment actually occurs
187
- /// before marking a borrowed `Local` as qualified.
188
- pub struct FlowSensitiveResolver < ' a , ' mir , ' tcx , Q >
189
- where
190
- Q : Qualif ,
191
- {
192
- location : Location ,
193
- indirectly_mutable_locals : & ' a RefCell < IndirectlyMutableResults < ' mir , ' tcx > > ,
194
- cursor : dataflow:: ResultsCursor < ' mir , ' tcx , FlowSensitiveAnalysis < ' a , ' mir , ' tcx , Q > > ,
195
- qualifs_per_local : BitSet < Local > ,
196
-
197
- /// The value of `Q::in_any_value_of_ty` for each local.
198
- qualifs_in_any_value_of_ty : BitSet < Local > ,
199
- }
200
-
201
- impl < Q > FlowSensitiveResolver < ' a , ' mir , ' tcx , Q >
202
- where
203
- Q : Qualif ,
204
- {
205
- pub fn new (
206
- _: Q ,
207
- item : & ' a Item < ' mir , ' tcx > ,
208
- indirectly_mutable_locals : & ' a RefCell < IndirectlyMutableResults < ' mir , ' tcx > > ,
209
- dead_unwinds : & BitSet < BasicBlock > ,
210
- ) -> Self {
211
- let analysis = FlowSensitiveAnalysis {
212
- item,
213
- _qualif : PhantomData ,
214
- } ;
215
- let results =
216
- dataflow:: Engine :: new ( item. tcx , item. body , item. def_id , dead_unwinds, analysis)
217
- . iterate_to_fixpoint ( ) ;
218
- let cursor = dataflow:: ResultsCursor :: new ( item. body , results) ;
219
-
220
- let mut qualifs_in_any_value_of_ty = BitSet :: new_empty ( item. body . local_decls . len ( ) ) ;
221
- for ( local, decl) in item. body . local_decls . iter_enumerated ( ) {
222
- if Q :: in_any_value_of_ty ( item, decl. ty ) {
223
- qualifs_in_any_value_of_ty. insert ( local) ;
224
- }
225
- }
226
-
227
- FlowSensitiveResolver {
228
- cursor,
229
- indirectly_mutable_locals,
230
- qualifs_per_local : BitSet :: new_empty ( item. body . local_decls . len ( ) ) ,
231
- qualifs_in_any_value_of_ty,
232
- location : Location { block : mir:: START_BLOCK , statement_index : 0 } ,
233
- }
234
- }
235
- }
236
-
237
- impl < Q > Visitor < ' tcx > for FlowSensitiveResolver < ' _ , ' _ , ' tcx , Q >
238
- where
239
- Q : Qualif
240
- {
241
- fn visit_statement ( & mut self , _: & mir:: Statement < ' tcx > , location : Location ) {
242
- self . location = location;
243
- }
244
-
245
- fn visit_terminator ( & mut self , _: & mir:: Terminator < ' tcx > , location : Location ) {
246
- self . location = location;
247
- }
248
- }
249
-
250
- impl < Q > QualifResolver < Q > for FlowSensitiveResolver < ' _ , ' _ , ' _ , Q >
251
- where
252
- Q : Qualif
253
- {
254
- fn get ( & mut self ) -> & BitSet < Local > {
255
- let mut indirectly_mutable_locals = self . indirectly_mutable_locals . borrow_mut ( ) ;
256
-
257
- indirectly_mutable_locals. seek ( self . location ) ;
258
- self . cursor . seek_before ( self . location ) ;
259
-
260
- self . qualifs_per_local . overwrite ( indirectly_mutable_locals. get ( ) ) ;
261
- self . qualifs_per_local . union ( self . cursor . get ( ) ) ;
262
- self . qualifs_per_local . intersect ( & self . qualifs_in_any_value_of_ty ) ;
263
- & self . qualifs_per_local
264
- }
265
-
266
- fn contains ( & mut self , local : Local ) -> bool {
267
- // No need to update the cursor if we know that `Local` cannot possibly be qualified.
268
- if !self . qualifs_in_any_value_of_ty . contains ( local) {
269
- return false ;
270
- }
271
-
272
- // Otherwise, return `true` if this local is qualified or was indirectly mutable at any
273
- // point before this statement.
274
- self . cursor . seek_before ( self . location ) ;
275
- if self . cursor . get ( ) . contains ( local) {
276
- return true ;
277
- }
278
-
279
- let mut indirectly_mutable_locals = self . indirectly_mutable_locals . borrow_mut ( ) ;
280
- indirectly_mutable_locals. seek ( self . location ) ;
281
- indirectly_mutable_locals. get ( ) . contains ( local)
282
- }
283
-
284
- fn reset ( & mut self ) {
285
- self . location = Location { block : mir:: START_BLOCK , statement_index : 0 } ;
286
- }
287
- }
288
-
289
147
/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
290
148
pub ( super ) struct FlowSensitiveAnalysis < ' a , ' mir , ' tcx , Q > {
291
149
item : & ' a Item < ' mir , ' tcx > ,
@@ -296,6 +154,13 @@ impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
296
154
where
297
155
Q : Qualif ,
298
156
{
157
+ pub ( super ) fn new ( _: Q , item : & ' a Item < ' mir , ' tcx > ) -> Self {
158
+ FlowSensitiveAnalysis {
159
+ item,
160
+ _qualif : PhantomData ,
161
+ }
162
+ }
163
+
299
164
fn transfer_function (
300
165
& self ,
301
166
state : & ' a mut BitSet < Local > ,
0 commit comments