diff options
| author | bors <bors@rust-lang.org> | 2025-09-16 09:18:32 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-09-16 09:18:32 +0000 |
| commit | eec6bd9d69832f57341c6de6a93fa7b9f47e2111 (patch) | |
| tree | 6b90ee6ad95a4fbf6530666e50692b3105358cf5 /compiler | |
| parent | 8a1b39995e5b630c5872f5de5079f1f569bd5ac2 (diff) | |
| parent | d58061e6131f6141985faadb6794af540f81b1db (diff) | |
| download | rust-eec6bd9d69832f57341c6de6a93fa7b9f47e2111.tar.gz rust-eec6bd9d69832f57341c6de6a93fa7b9f47e2111.zip | |
Auto merge of #146516 - cjgillot:dest-prop-aggregate, r=Amanieu
DestinationPropagation: avoid creating overlapping assignments. r? `@Amanieu` Fixes https://github.com/rust-lang/rust/issues/146383
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_mir_transform/src/dest_prop.rs | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 9ba2d274691..c57483a6811 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -567,13 +567,15 @@ fn save_as_intervals<'tcx>( // the written-to locals as live in the second half of the statement. // We also ensure that operands read by terminators conflict with writes by that terminator. // For instance a function call may read args after having written to the destination. - VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) { - DefUse::Def | DefUse::Use | DefUse::PartialWrite => { - if let Some(relevant) = relevant.shrink[place.local] { - values.insert(relevant, twostep); + VisitPlacesWith(|place: Place<'tcx>, ctxt| { + if let Some(relevant) = relevant.shrink[place.local] { + match DefUse::for_place(place, ctxt) { + DefUse::Def | DefUse::Use | DefUse::PartialWrite => { + values.insert(relevant, twostep); + } + DefUse::NonUse => {} } } - DefUse::NonUse => {} }) .visit_terminator(term, loc); @@ -588,15 +590,32 @@ fn save_as_intervals<'tcx>( twostep = TwoStepIndex::from_u32(twostep.as_u32() + 1); debug_assert_eq!(twostep, two_step_loc(loc, Effect::After)); append_at(&mut values, &state, twostep); - // Ensure we have a non-zero live range even for dead stores. This is done by marking - // all the written-to locals as live in the second half of the statement. - VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) { - DefUse::Def | DefUse::PartialWrite => { - if let Some(relevant) = relevant.shrink[place.local] { - values.insert(relevant, twostep); + // Like terminators, ensure we have a non-zero live range even for dead stores. + // Some rvalues interleave reads and writes, for instance `Rvalue::Aggregate`, see + // https://github.com/rust-lang/rust/issues/146383. By precaution, treat statements + // as behaving so by default. + // We make an exception for simple assignments `_a.stuff = {copy|move} _b.stuff`, + // as marking `_b` live here would prevent unification. + let is_simple_assignment = match stmt.kind { + StatementKind::Assign(box ( + lhs, + Rvalue::CopyForDeref(rhs) + | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + )) => lhs.projection == rhs.projection, + _ => false, + }; + VisitPlacesWith(|place: Place<'tcx>, ctxt| { + if let Some(relevant) = relevant.shrink[place.local] { + match DefUse::for_place(place, ctxt) { + DefUse::Def | DefUse::PartialWrite => { + values.insert(relevant, twostep); + } + DefUse::Use if !is_simple_assignment => { + values.insert(relevant, twostep); + } + DefUse::Use | DefUse::NonUse => {} } } - DefUse::Use | DefUse::NonUse => {} }) .visit_statement(stmt, loc); |
