@@ -547,6 +547,21 @@ fn save_as_intervals<'tcx>(
547
547
}
548
548
}
549
549
} ;
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
+ } ;
550
565
551
566
// Iterate blocks in decreasing order, to visit locations in decreasing order. This
552
567
// allows to use the more efficient `append` method to interval sets.
@@ -567,17 +582,7 @@ fn save_as_intervals<'tcx>(
567
582
// the written-to locals as live in the second half of the statement.
568
583
// We also ensure that operands read by terminators conflict with writes by that terminator.
569
584
// 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) ;
581
586
582
587
twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
583
588
debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
@@ -590,24 +595,15 @@ fn save_as_intervals<'tcx>(
590
595
twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
591
596
debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: After ) ) ;
592
597
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.
595
604
let is_simple_assignment =
596
605
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) ;
611
607
612
608
twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
613
609
debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
0 commit comments