@@ -85,7 +85,9 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
85
85
let ssa = SsaLocals :: new ( body) ;
86
86
87
87
let mut replacer = compute_replacement ( tcx, body, & ssa) ;
88
- debug ! ( ?replacer. targets, ?replacer. allowed_replacements, ?replacer. storage_to_remove) ;
88
+ debug ! ( ?replacer. targets) ;
89
+ debug ! ( ?replacer. allowed_replacements) ;
90
+ debug ! ( ?replacer. storage_to_remove) ;
89
91
90
92
replacer. visit_body_preserves_cfg ( body) ;
91
93
@@ -190,8 +192,11 @@ fn compute_replacement<'tcx>(
190
192
continue ;
191
193
}
192
194
195
+ // Whether the current local is subject to the uniqueness rule.
196
+ let needs_unique = ty. is_mutable_ptr ( ) ;
197
+
193
198
// If this a mutable reference that we cannot fully replace, mark it as unknown.
194
- if ty . is_mutable_ptr ( ) && !fully_replacable_locals. contains ( local) {
199
+ if needs_unique && !fully_replacable_locals. contains ( local) {
195
200
debug ! ( "not fully replaceable" ) ;
196
201
continue ;
197
202
}
@@ -203,32 +208,33 @@ fn compute_replacement<'tcx>(
203
208
// have been visited before.
204
209
Rvalue :: Use ( Operand :: Copy ( place) | Operand :: Move ( place) )
205
210
| Rvalue :: CopyForDeref ( place) => {
206
- if let Some ( rhs) = place. as_local ( ) {
211
+ if let Some ( rhs) = place. as_local ( ) && ssa . is_ssa ( rhs ) {
207
212
let target = targets[ rhs] ;
208
- if matches ! ( target, Value :: Pointer ( ..) ) {
213
+ // Only see through immutable reference and pointers, as we do not know yet if
214
+ // mutable references are fully replaced.
215
+ if !needs_unique && matches ! ( target, Value :: Pointer ( ..) ) {
209
216
targets[ local] = target;
210
- } else if ssa. is_ssa ( rhs) {
211
- let refmut = body. local_decls [ rhs] . ty . is_mutable_ptr ( ) ;
212
- targets[ local] = Value :: Pointer ( tcx. mk_place_deref ( rhs. into ( ) ) , refmut) ;
217
+ } else {
218
+ targets[ local] = Value :: Pointer ( tcx. mk_place_deref ( rhs. into ( ) ) , needs_unique) ;
213
219
}
214
220
}
215
221
}
216
222
Rvalue :: Ref ( _, _, place) | Rvalue :: AddressOf ( _, place) => {
217
223
let mut place = * place;
218
224
// Try to see through `place` in order to collapse reborrow chains.
219
225
if place. projection . first ( ) == Some ( & PlaceElem :: Deref )
220
- && let Value :: Pointer ( target, refmut ) = targets[ place. local ]
226
+ && let Value :: Pointer ( target, inner_needs_unique ) = targets[ place. local ]
221
227
// Only see through immutable reference and pointers, as we do not know yet if
222
228
// mutable references are fully replaced.
223
- && !refmut
229
+ && !inner_needs_unique
224
230
// Only collapse chain if the pointee is definitely live.
225
231
&& can_perform_opt ( target, location)
226
232
{
227
233
place = target. project_deeper ( & place. projection [ 1 ..] , tcx) ;
228
234
}
229
235
assert_ne ! ( place. local, local) ;
230
236
if is_constant_place ( place) {
231
- targets[ local] = Value :: Pointer ( place, ty . is_mutable_ptr ( ) ) ;
237
+ targets[ local] = Value :: Pointer ( place, needs_unique ) ;
232
238
}
233
239
}
234
240
// We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +282,35 @@ fn compute_replacement<'tcx>(
276
282
return ;
277
283
}
278
284
279
- if let Value :: Pointer ( target, refmut) = self . targets [ place. local ]
280
- && place. projection . first ( ) == Some ( & PlaceElem :: Deref )
281
- {
282
- let perform_opt = ( self . can_perform_opt ) ( target, loc) ;
283
- if perform_opt {
284
- self . allowed_replacements . insert ( ( target. local , loc) ) ;
285
- } else if refmut {
286
- // This mutable reference is not fully replacable, so drop it.
287
- self . targets [ place. local ] = Value :: Unknown ;
285
+ if place. projection . first ( ) != Some ( & PlaceElem :: Deref ) {
286
+ // This is not a dereference, nothing to do.
287
+ return ;
288
+ }
289
+
290
+ let mut place = place. as_ref ( ) ;
291
+ loop {
292
+ if let Value :: Pointer ( target, needs_unique) = self . targets [ place. local ] {
293
+ let perform_opt = ( self . can_perform_opt ) ( target, loc) ;
294
+ debug ! ( ?place, ?target, ?needs_unique, ?perform_opt) ;
295
+
296
+ // This a reborrow chain, recursively allow the replacement.
297
+ //
298
+ // This also allows to detect cases where `target.local` is not replacable,
299
+ // and mark it as such.
300
+ if let & [ PlaceElem :: Deref ] = & target. projection [ ..] {
301
+ assert ! ( perform_opt) ;
302
+ self . allowed_replacements . insert ( ( target. local , loc) ) ;
303
+ place. local = target. local ;
304
+ continue ;
305
+ } else if perform_opt {
306
+ self . allowed_replacements . insert ( ( target. local , loc) ) ;
307
+ } else if needs_unique {
308
+ // This mutable reference is not fully replacable, so drop it.
309
+ self . targets [ place. local ] = Value :: Unknown ;
310
+ }
288
311
}
312
+
313
+ break ;
289
314
}
290
315
}
291
316
}
@@ -326,18 +351,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
326
351
}
327
352
328
353
fn visit_place ( & mut self , place : & mut Place < ' tcx > , ctxt : PlaceContext , loc : Location ) {
329
- if let Value :: Pointer ( target, _) = self . targets [ place. local ]
330
- && place. projection . first ( ) == Some ( & PlaceElem :: Deref )
331
- {
332
- let perform_opt = matches ! ( ctxt, PlaceContext :: NonUse ( _) )
333
- || self . allowed_replacements . contains ( & ( target. local , loc) ) ;
334
-
335
- if perform_opt {
336
- * place = target. project_deeper ( & place. projection [ 1 ..] , self . tcx ) ;
337
- self . any_replacement = true ;
354
+ if place. projection . first ( ) != Some ( & PlaceElem :: Deref ) {
355
+ return ;
356
+ }
357
+
358
+ loop {
359
+ if let Value :: Pointer ( target, _) = self . targets [ place. local ] {
360
+ let perform_opt = matches ! ( ctxt, PlaceContext :: NonUse ( _) )
361
+ || self . allowed_replacements . contains ( & ( target. local , loc) ) ;
362
+
363
+ if perform_opt {
364
+ * place = target. project_deeper ( & place. projection [ 1 ..] , self . tcx ) ;
365
+ self . any_replacement = true ;
366
+ continue ;
367
+ }
338
368
}
339
- } else {
340
- self . super_place ( place , ctxt , loc ) ;
369
+
370
+ break ;
341
371
}
342
372
}
343
373
0 commit comments