@@ -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 }
@@ -203,32 +208,33 @@ fn compute_replacement<'tcx>(
203208 // have been visited before.
204209 Rvalue :: Use ( Operand :: Copy ( place) | Operand :: Move ( place) )
205210 | Rvalue :: CopyForDeref ( place) => {
206- if let Some ( rhs) = place. as_local ( ) {
211+ if let Some ( rhs) = place. as_local ( ) && ssa . is_ssa ( rhs ) {
207212 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 ( ..) ) {
209216 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) ;
213219 }
214220 }
215221 }
216222 Rvalue :: Ref ( _, _, place) | Rvalue :: AddressOf ( _, place) => {
217223 let mut place = * place;
218224 // Try to see through `place` in order to collapse reborrow chains.
219225 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 ]
221227 // Only see through immutable reference and pointers, as we do not know yet if
222228 // mutable references are fully replaced.
223- && !refmut
229+ && !inner_needs_unique
224230 // Only collapse chain if the pointee is definitely live.
225231 && can_perform_opt ( target, location)
226232 {
227233 place = target. project_deeper ( & place. projection [ 1 ..] , tcx) ;
228234 }
229235 assert_ne ! ( place. local, local) ;
230236 if is_constant_place ( place) {
231- targets[ local] = Value :: Pointer ( place, ty . is_mutable_ptr ( ) ) ;
237+ targets[ local] = Value :: Pointer ( place, needs_unique ) ;
232238 }
233239 }
234240 // We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +282,35 @@ fn compute_replacement<'tcx>(
276282 return ;
277283 }
278284
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+ }
288311 }
312+
313+ break ;
289314 }
290315 }
291316 }
@@ -326,18 +351,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
326351 }
327352
328353 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+ }
338368 }
339- } else {
340- self . super_place ( place , ctxt , loc ) ;
369+
370+ break ;
341371 }
342372 }
343373
0 commit comments