@@ -179,6 +179,25 @@ 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 {
@@ -192,24 +211,26 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
192
211
// Immutable borrows are taken into account in `SsaLocals::new` by
193
212
// removing non-freeze locals.
194
213
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
- }
214
+ self . check_assignment_dominates ( local, loc) ;
209
215
}
210
216
PlaceContext :: NonUse ( _) => { }
211
217
}
212
218
}
219
+
220
+ fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , loc : Location ) {
221
+ if place. projection . first ( ) == Some ( & PlaceElem :: Deref ) {
222
+ // Do not do anything for storage statements and debuginfo.
223
+ if ctxt. is_use ( ) {
224
+ // A use through a `deref` only reads from the local, and cannot write to it.
225
+ let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) ;
226
+
227
+ self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
228
+ self . check_assignment_dominates ( place. local , loc) ;
229
+ }
230
+ return ;
231
+ }
232
+ self . super_place ( place, ctxt, loc) ;
233
+ }
213
234
}
214
235
215
236
#[ instrument( level = "trace" , skip( ssa, body) ) ]
0 commit comments