@@ -547,6 +547,21 @@ fn save_as_intervals<'tcx>(
547547 }
548548 }
549549 } ;
550+ let second_half_visitor = |mark_reads| {
551+ VisitPlacesWith ( |place : Place < ' tcx > , ctxt| {
552+ if let Some ( relevant) = relevant. shrink [ place. local ] {
553+ match DefUse :: for_place ( place, ctxt) {
554+ DefUse :: Def | DefUse :: PartialWrite => {
555+ values. insert ( relevant, twostep) ;
556+ }
557+ DefUse :: Use if mark_reads => {
558+ values. insert ( relevant, twostep) ;
559+ }
560+ DefUse :: NonUse => { }
561+ }
562+ }
563+ } )
564+ } ;
550565
551566 // Iterate blocks in decreasing order, to visit locations in decreasing order. This
552567 // allows to use the more efficient `append` method to interval sets.
@@ -567,17 +582,7 @@ fn save_as_intervals<'tcx>(
567582 // the written-to locals as live in the second half of the statement.
568583 // We also ensure that operands read by terminators conflict with writes by that terminator.
569584 // For instance a function call may read args after having written to the destination.
570- VisitPlacesWith ( |place : Place < ' tcx > , ctxt| {
571- if let Some ( relevant) = relevant. shrink [ place. local ] {
572- match DefUse :: for_place ( place, ctxt) {
573- DefUse :: Def | DefUse :: Use | DefUse :: PartialWrite => {
574- values. insert ( relevant, twostep) ;
575- }
576- DefUse :: NonUse => { }
577- }
578- }
579- } )
580- . visit_terminator ( term, loc) ;
585+ second_half_visitor ( /* mark reads */ true ) . visit_terminator ( term, loc) ;
581586
582587 twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
583588 debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
@@ -590,24 +595,15 @@ fn save_as_intervals<'tcx>(
590595 twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
591596 debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: After ) ) ;
592597 append_at ( & mut values, & state, twostep) ;
593- // Ensure we have a non-zero live range even for dead stores. This is done by marking
594- // all the written-to locals as live in the second half of the statement.
598+ // Like terminators, ensure we have a non-zero live range even for dead stores.
599+ // Some rvalues interleave reads and writes, for instance `Rvalue::Aggregate`, see
600+ // https://github.com/rust-lang/rust/issues/146383. By precaution, treat statements
601+ // as behaving so by default.
602+ // We make an exception for simple assignments `_a.stuff = {copy|move} _b.stuff`,
603+ // as marking `_b` live here would prevent unification.
595604 let is_simple_assignment =
596605 matches ! ( stmt. kind, StatementKind :: Assign ( box ( _, Rvalue :: Use ( _) ) ) ) ;
597- VisitPlacesWith ( |place : Place < ' tcx > , ctxt| {
598- if let Some ( relevant) = relevant. shrink [ place. local ] {
599- match DefUse :: for_place ( place, ctxt) {
600- DefUse :: Def | DefUse :: PartialWrite => {
601- values. insert ( relevant, twostep) ;
602- }
603- DefUse :: Use if !is_simple_assignment => {
604- values. insert ( relevant, twostep) ;
605- }
606- DefUse :: Use | DefUse :: NonUse => { }
607- }
608- }
609- } )
610- . visit_statement ( stmt, loc) ;
606+ second_half_visitor ( /* mark reads */ is_simple_assignment) . visit_statement ( stmt, loc) ;
611607
612608 twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
613609 debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
0 commit comments