@@ -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
}
@@ -217,18 +222,18 @@ fn compute_replacement<'tcx>(
217
222
let mut place = * place;
218
223
// Try to see through `place` in order to collapse reborrow chains.
219
224
if place. projection . first ( ) == Some ( & PlaceElem :: Deref )
220
- && let Value :: Pointer ( target, refmut ) = targets[ place. local ]
225
+ && let Value :: Pointer ( target, needs_unique ) = targets[ place. local ]
221
226
// Only see through immutable reference and pointers, as we do not know yet if
222
227
// mutable references are fully replaced.
223
- && !refmut
228
+ && !needs_unique
224
229
// Only collapse chain if the pointee is definitely live.
225
230
&& can_perform_opt ( target, location)
226
231
{
227
232
place = target. project_deeper ( & place. projection [ 1 ..] , tcx) ;
228
233
}
229
234
assert_ne ! ( place. local, local) ;
230
235
if is_constant_place ( place) {
231
- targets[ local] = Value :: Pointer ( place, ty . is_mutable_ptr ( ) ) ;
236
+ targets[ local] = Value :: Pointer ( place, needs_unique ) ;
232
237
}
233
238
}
234
239
// We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +281,35 @@ fn compute_replacement<'tcx>(
276
281
return ;
277
282
}
278
283
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 ;
284
+ if place. projection . first ( ) != Some ( & PlaceElem :: Deref ) {
285
+ // This is not a dereference, nothing to do.
286
+ return ;
287
+ }
288
+
289
+ let mut place = place. as_ref ( ) ;
290
+ loop {
291
+ if let Value :: Pointer ( target, needs_unique) = self . targets [ place. local ] {
292
+ let perform_opt = ( self . can_perform_opt ) ( target, loc) ;
293
+ debug ! ( ?place, ?target, ?needs_unique, ?perform_opt) ;
294
+
295
+ // This a reborrow chain, recursively allow the replacement.
296
+ //
297
+ // This also allows to detect cases where `target.local` is not replacable,
298
+ // and mark it as such.
299
+ if let & [ PlaceElem :: Deref ] = & target. projection [ ..] {
300
+ assert ! ( perform_opt) ;
301
+ self . allowed_replacements . insert ( ( target. local , loc) ) ;
302
+ place. local = target. local ;
303
+ continue ;
304
+ } else if perform_opt {
305
+ self . allowed_replacements . insert ( ( target. local , loc) ) ;
306
+ } else if needs_unique {
307
+ // This mutable reference is not fully replacable, so drop it.
308
+ self . targets [ place. local ] = Value :: Unknown ;
309
+ }
288
310
}
311
+
312
+ break ;
289
313
}
290
314
}
291
315
}
@@ -326,18 +350,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
326
350
}
327
351
328
352
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 ;
353
+ if place. projection . first ( ) != Some ( & PlaceElem :: Deref ) {
354
+ return ;
355
+ }
356
+
357
+ loop {
358
+ if let Value :: Pointer ( target, _) = self . targets [ place. local ] {
359
+ let perform_opt = matches ! ( ctxt, PlaceContext :: NonUse ( _) )
360
+ || self . allowed_replacements . contains ( & ( target. local , loc) ) ;
361
+
362
+ if perform_opt {
363
+ * place = target. project_deeper ( & place. projection [ 1 ..] , self . tcx ) ;
364
+ self . any_replacement = true ;
365
+ continue ;
366
+ }
338
367
}
339
- } else {
340
- self . super_place ( place , ctxt , loc ) ;
368
+
369
+ break ;
341
370
}
342
371
}
343
372
0 commit comments