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
+
1
14
use either:: Either ;
2
15
use rustc_data_structures:: graph:: dominators:: Dominators ;
3
16
use rustc_index:: bit_set:: BitSet ;
4
17
use rustc_index:: { IndexSlice , IndexVec } ;
5
18
use rustc_middle:: middle:: resolve_bound_vars:: Set1 ;
6
19
use rustc_middle:: mir:: visit:: * ;
7
20
use rustc_middle:: mir:: * ;
8
- use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
9
21
use rustc_mir_dataflow:: storage:: always_storage_live_locals;
10
22
11
23
#[ derive( Debug ) ]
@@ -62,12 +74,7 @@ impl SmallDominators {
62
74
}
63
75
64
76
impl 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 {
71
78
let assignment_order = Vec :: with_capacity ( body. local_decls . len ( ) ) ;
72
79
73
80
let assignments = IndexVec :: from_elem ( Set1 :: Empty , & body. local_decls ) ;
@@ -80,13 +87,8 @@ impl SsaLocals {
80
87
let mut visitor =
81
88
SsaVisitor { assignments, assignment_order, dominators, direct_uses, storage_live } ;
82
89
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 ) ;
90
92
}
91
93
92
94
for local in always_storage_live_locals ( body) . iter ( ) {
@@ -237,6 +239,8 @@ struct SsaVisitor {
237
239
impl < ' tcx > Visitor < ' tcx > for SsaVisitor {
238
240
fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
239
241
match ctxt {
242
+ PlaceContext :: MutatingUse ( MutatingUseContext :: Projection )
243
+ | PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) => bug ! ( ) ,
240
244
PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
241
245
self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
242
246
if let Set1 :: One ( _) = self . assignments [ local] {
@@ -246,13 +250,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
246
250
self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
247
251
}
248
252
// 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
+ )
250
261
| PlaceContext :: MutatingUse ( _) => {
251
262
self . assignments [ local] = Set1 :: Many ;
252
263
self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
253
264
}
254
- // Immutable borrows are taken into account in `SsaLocals::new` by
255
- // removing non-freeze locals.
256
265
PlaceContext :: NonMutatingUse ( _) => {
257
266
self . dominators . check_dominates ( & mut self . assignments [ local] , loc) ;
258
267
self . dominators . check_dominates ( & mut self . storage_live [ local] , loc) ;
@@ -270,15 +279,17 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
270
279
// Do not do anything for storage statements and debuginfo.
271
280
if ctxt. is_use ( ) {
272
281
// 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 ) ;
274
283
275
284
self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
276
285
self . dominators . check_dominates ( & mut self . assignments [ place. local ] , loc) ;
277
286
self . dominators . check_dominates ( & mut self . storage_live [ place. local ] , loc) ;
278
287
}
279
288
return ;
289
+ } else {
290
+ self . visit_projection ( place. as_ref ( ) , ctxt, loc) ;
291
+ self . visit_local ( place. local , ctxt, loc) ;
280
292
}
281
- self . super_place ( place, ctxt, loc) ;
282
293
}
283
294
}
284
295
0 commit comments