@@ -293,10 +293,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> {
293293fn compute_copy_classes ( ssa : & mut SsaLocals , body : & Body < ' _ > ) {
294294 let mut direct_uses = std:: mem:: take ( & mut ssa. direct_uses ) ;
295295 let mut copies = IndexVec :: from_fn_n ( |l| l, body. local_decls . len ( ) ) ;
296- // We must not unify two locals that are borrowed. But this is fine if one is borrowed and
297- // the other is not. This bitset is keyed by *class head* and contains whether any member of
298- // the class is borrowed.
299- let mut borrowed_classes = ssa. borrowed_locals ( ) . clone ( ) ;
300296
301297 for ( local, rvalue, _) in ssa. assignments ( body) {
302298 let ( Rvalue :: Use ( Operand :: Copy ( place) | Operand :: Move ( place) )
@@ -322,8 +318,12 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
322318 // visited before `local`, and we just have to copy the representing local.
323319 let head = copies[ rhs] ;
324320
325- // Do not unify borrowed locals.
326- if borrowed_classes. contains ( local) || borrowed_classes. contains ( head) {
321+ // When propagating from `head` to `local` we need to ensure that changes to the address
322+ // are not observable, so at most one the locals involved can be borrowed. Additionally, we
323+ // need to ensure that the definition of `head` dominates all uses of `local`. When `local`
324+ // is borrowed, there might exist an indirect use of `local` that isn't dominated by the
325+ // definition, so we have to reject copy propagation.
326+ if ssa. borrowed_locals ( ) . contains ( local) {
327327 continue ;
328328 }
329329
@@ -339,21 +339,14 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
339339 * h = RETURN_PLACE ;
340340 }
341341 }
342- if borrowed_classes. contains ( head) {
343- borrowed_classes. insert ( RETURN_PLACE ) ;
344- }
345342 } else {
346343 copies[ local] = head;
347- if borrowed_classes. contains ( local) {
348- borrowed_classes. insert ( head) ;
349- }
350344 }
351345 direct_uses[ rhs] -= 1 ;
352346 }
353347
354348 debug ! ( ?copies) ;
355349 debug ! ( ?direct_uses) ;
356- debug ! ( ?borrowed_classes) ;
357350
358351 // Invariant: `copies` must point to the head of an equivalence class.
359352 #[ cfg( debug_assertions) ]
@@ -362,13 +355,6 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
362355 }
363356 debug_assert_eq ! ( copies[ RETURN_PLACE ] , RETURN_PLACE ) ;
364357
365- // Invariant: `borrowed_classes` must be true if any member of the class is borrowed.
366- #[ cfg( debug_assertions) ]
367- for & head in copies. iter ( ) {
368- let any_borrowed = ssa. borrowed_locals . iter ( ) . any ( |l| copies[ l] == head) ;
369- assert_eq ! ( borrowed_classes. contains( head) , any_borrowed) ;
370- }
371-
372358 ssa. direct_uses = direct_uses;
373359 ssa. copy_classes = copies;
374360}
0 commit comments