1+ //! We denote as "SSA" the set of locals that verify the following properties:
2+ //! 1/ They are only assigned-to once, either as a function parameter, or in an assign statement;
3+ //! 2/ This single assignment dominates all uses;
4+ //!
5+ //! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
6+ //! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
7+ //!
8+ //! We say a local has a stable address if its address has SSA-like properties:
9+ //! 1/ It has a single `StorageLive` statement, or none at all (always-live);
10+ //! 2/ All its uses dominate this `StorageLive` statement.
11+ //!
12+ //! We do not discard borrowed locals from this analysis, as we cannot take their address' address.
13+
114use either:: Either ;
215use rustc_data_structures:: graph:: dominators:: Dominators ;
316use rustc_index:: bit_set:: BitSet ;
417use rustc_index:: { IndexSlice , IndexVec } ;
518use rustc_middle:: middle:: resolve_bound_vars:: Set1 ;
619use rustc_middle:: mir:: visit:: * ;
720use rustc_middle:: mir:: * ;
8- use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
921use rustc_mir_dataflow:: storage:: always_storage_live_locals;
1022
1123#[ derive( Debug ) ]
@@ -62,12 +74,7 @@ impl SmallDominators {
6274}
6375
6476impl SsaLocals {
65- pub fn new < ' tcx > (
66- tcx : TyCtxt < ' tcx > ,
67- param_env : ParamEnv < ' tcx > ,
68- body : & Body < ' tcx > ,
69- borrowed_locals : & BitSet < Local > ,
70- ) -> SsaLocals {
77+ pub fn new < ' tcx > ( body : & Body < ' tcx > ) -> SsaLocals {
7178 let assignment_order = Vec :: with_capacity ( body. local_decls . len ( ) ) ;
7279
7380 let assignments = IndexVec :: from_elem ( Set1 :: Empty , & body. local_decls ) ;
@@ -80,13 +87,8 @@ impl SsaLocals {
8087 let mut visitor =
8188 SsaVisitor { assignments, assignment_order, dominators, direct_uses, storage_live } ;
8289
83- for ( local, decl) in body. local_decls . iter_enumerated ( ) {
84- if matches ! ( body. local_kind( local) , LocalKind :: Arg ) {
85- visitor. assignments [ local] = Set1 :: One ( LocationExtended :: Arg ) ;
86- }
87- if borrowed_locals. contains ( local) && !decl. ty . is_freeze ( tcx, param_env) {
88- visitor. assignments [ local] = Set1 :: Many ;
89- }
90+ for local in body. args_iter ( ) {
91+ visitor. assignments [ local] = Set1 :: One ( LocationExtended :: Arg ) ;
9092 }
9193
9294 for local in always_storage_live_locals ( body) . iter ( ) {
@@ -237,6 +239,8 @@ struct SsaVisitor {
237239impl < ' tcx > Visitor < ' tcx > for SsaVisitor {
238240 fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
239241 match ctxt {
242+ PlaceContext :: MutatingUse ( MutatingUseContext :: Projection )
243+ | PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) => bug ! ( ) ,
240244 PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
241245 self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
242246 if let Set1 :: One ( _) = self . assignments [ local] {
@@ -246,13 +250,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
246250 self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
247251 }
248252 // Anything can happen with raw pointers, so remove them.
249- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: AddressOf )
253+ // We do not verify that all uses of the borrow dominate the assignment to `local`,
254+ // so we have to remove them too.
255+ PlaceContext :: NonMutatingUse (
256+ NonMutatingUseContext :: SharedBorrow
257+ | NonMutatingUseContext :: ShallowBorrow
258+ | NonMutatingUseContext :: UniqueBorrow
259+ | NonMutatingUseContext :: AddressOf ,
260+ )
250261 | PlaceContext :: MutatingUse ( _) => {
251262 self . assignments [ local] = Set1 :: Many ;
252263 self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
253264 }
254- // Immutable borrows are taken into account in `SsaLocals::new` by
255- // removing non-freeze locals.
256265 PlaceContext :: NonMutatingUse ( _) => {
257266 self . dominators . check_dominates ( & mut self . assignments [ local] , loc) ;
258267 self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
@@ -270,15 +279,17 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
270279 // Do not do anything for storage statements and debuginfo.
271280 if ctxt. is_use ( ) {
272281 // Only change the context if it is a real use, not a "use" in debuginfo.
273- let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) ;
282+ let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
274283
275284 self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
276285 self . dominators . check_dominates ( & mut self . assignments [ place. local ] , loc) ;
277286 self . dominators . check_dominates ( & mut self . storage_live [ place. local ] , loc) ;
278287 }
279288 return ;
289+ } else {
290+ self . visit_projection ( place. as_ref ( ) , ctxt, loc) ;
291+ self . visit_local ( place. local , ctxt, loc) ;
280292 }
281- self . super_place ( place, ctxt, loc) ;
282293 }
283294}
284295
0 commit comments