@@ -85,7 +85,9 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
8585 let ssa = SsaLocals :: new ( body) ;
8686
8787 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) ;
8991
9092 replacer. visit_body_preserves_cfg ( body) ;
9193
@@ -190,8 +192,11 @@ fn compute_replacement<'tcx>(
190192 continue ;
191193 }
192194
195+ // Whether the current local is subject to the uniqueness rule.
196+ let needs_unique = ty. is_mutable_ptr ( ) ;
197+
193198 // 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) {
195200 debug ! ( "not fully replaceable" ) ;
196201 continue ;
197202 }
@@ -217,18 +222,18 @@ fn compute_replacement<'tcx>(
217222 let mut place = * place;
218223 // Try to see through `place` in order to collapse reborrow chains.
219224 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 ]
221226 // Only see through immutable reference and pointers, as we do not know yet if
222227 // mutable references are fully replaced.
223- && !refmut
228+ && !needs_unique
224229 // Only collapse chain if the pointee is definitely live.
225230 && can_perform_opt ( target, location)
226231 {
227232 place = target. project_deeper ( & place. projection [ 1 ..] , tcx) ;
228233 }
229234 assert_ne ! ( place. local, local) ;
230235 if is_constant_place ( place) {
231- targets[ local] = Value :: Pointer ( place, ty . is_mutable_ptr ( ) ) ;
236+ targets[ local] = Value :: Pointer ( place, needs_unique ) ;
232237 }
233238 }
234239 // We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +281,35 @@ fn compute_replacement<'tcx>(
276281 return ;
277282 }
278283
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+ }
288310 }
311+
312+ break ;
289313 }
290314 }
291315 }
@@ -326,18 +350,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
326350 }
327351
328352 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+ }
338367 }
339- } else {
340- self . super_place ( place , ctxt , loc ) ;
368+
369+ break ;
341370 }
342371 }
343372
0 commit comments