11//! Propagate `Qualif`s between locals and query the results.
22//!
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.
54
65use rustc:: mir:: visit:: Visitor ;
76use rustc:: mir:: { self , BasicBlock , Local , Location } ;
87use rustc_index:: bit_set:: BitSet ;
98
10- use std:: cell:: RefCell ;
119use std:: marker:: PhantomData ;
1210
1311use crate :: dataflow:: { self as old_dataflow, generic as dataflow} ;
1412use super :: { Item , Qualif } ;
15- use self :: old_dataflow:: IndirectlyMutableLocals ;
1613
1714/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
18- /// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver` .
15+ /// `FlowSensitiveAnalysis`.
1916///
2017/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
2118/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via
@@ -147,145 +144,6 @@ where
147144 }
148145}
149146
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-
289147/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
290148pub ( super ) struct FlowSensitiveAnalysis < ' a , ' mir , ' tcx , Q > {
291149 item : & ' a Item < ' mir , ' tcx > ,
@@ -296,6 +154,13 @@ impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
296154where
297155 Q : Qualif ,
298156{
157+ pub ( super ) fn new ( _: Q , item : & ' a Item < ' mir , ' tcx > ) -> Self {
158+ FlowSensitiveAnalysis {
159+ item,
160+ _qualif : PhantomData ,
161+ }
162+ }
163+
299164 fn transfer_function (
300165 & self ,
301166 state : & ' a mut BitSet < Local > ,
0 commit comments