@@ -53,7 +53,7 @@ impl SsaLocals {
53
53
body : & Body < ' tcx > ,
54
54
borrowed_locals : & BitSet < Local > ,
55
55
) -> SsaLocals {
56
- let assignment_order = Vec :: new ( ) ;
56
+ let assignment_order = Vec :: with_capacity ( body . local_decls . len ( ) ) ;
57
57
58
58
let assignments = IndexVec :: from_elem ( Set1 :: Empty , & body. local_decls ) ;
59
59
let dominators =
@@ -179,37 +179,61 @@ struct SsaVisitor {
179
179
assignment_order : Vec < Local > ,
180
180
}
181
181
182
+ impl SsaVisitor {
183
+ fn check_assignment_dominates ( & mut self , local : Local , loc : Location ) {
184
+ let set = & mut self . assignments [ local] ;
185
+ let assign_dominates = match * set {
186
+ Set1 :: Empty | Set1 :: Many => false ,
187
+ Set1 :: One ( LocationExtended :: Arg ) => true ,
188
+ Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
189
+ assign. successor_within_block ( ) . dominates ( loc, & self . dominators )
190
+ }
191
+ } ;
192
+ // We are visiting a use that is not dominated by an assignment.
193
+ // Either there is a cycle involved, or we are reading for uninitialized local.
194
+ // Bail out.
195
+ if !assign_dominates {
196
+ * set = Set1 :: Many ;
197
+ }
198
+ }
199
+ }
200
+
182
201
impl < ' tcx > Visitor < ' tcx > for SsaVisitor {
183
202
fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
184
203
match ctxt {
185
204
PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
186
205
self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
187
- self . assignment_order . push ( local) ;
206
+ if let Set1 :: One ( _) = self . assignments [ local] {
207
+ // Only record if SSA-like, to avoid growing the vector needlessly.
208
+ self . assignment_order . push ( local) ;
209
+ }
188
210
}
189
211
// Anything can happen with raw pointers, so remove them.
190
212
PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: AddressOf )
191
213
| PlaceContext :: MutatingUse ( _) => self . assignments [ local] = Set1 :: Many ,
192
214
// Immutable borrows are taken into account in `SsaLocals::new` by
193
215
// removing non-freeze locals.
194
216
PlaceContext :: NonMutatingUse ( _) => {
195
- let set = & mut self . assignments [ local] ;
196
- let assign_dominates = match * set {
197
- Set1 :: Empty | Set1 :: Many => false ,
198
- Set1 :: One ( LocationExtended :: Arg ) => true ,
199
- Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
200
- assign. successor_within_block ( ) . dominates ( loc, & self . dominators )
201
- }
202
- } ;
203
- // We are visiting a use that is not dominated by an assignment.
204
- // Either there is a cycle involved, or we are reading for uninitialized local.
205
- // Bail out.
206
- if !assign_dominates {
207
- * set = Set1 :: Many ;
208
- }
217
+ self . check_assignment_dominates ( local, loc) ;
209
218
}
210
219
PlaceContext :: NonUse ( _) => { }
211
220
}
212
221
}
222
+
223
+ fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , loc : Location ) {
224
+ if place. projection . first ( ) == Some ( & PlaceElem :: Deref ) {
225
+ // Do not do anything for storage statements and debuginfo.
226
+ if ctxt. is_use ( ) {
227
+ // A use through a `deref` only reads from the local, and cannot write to it.
228
+ let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) ;
229
+
230
+ self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
231
+ self . check_assignment_dominates ( place. local , loc) ;
232
+ }
233
+ return ;
234
+ }
235
+ self . super_place ( place, ctxt, loc) ;
236
+ }
213
237
}
214
238
215
239
#[ instrument( level = "trace" , skip( ssa, body) ) ]
0 commit comments