@@ -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