From 9312bb0b15c79395e8c3eee358428b32ab44a3ed Mon Sep 17 00:00:00 2001 From: MilkBlock <2386925778@qq.com> Date: Mon, 27 Apr 2026 02:53:13 +0800 Subject: [PATCH 1/5] fix(coroutine): split overlapping state assignments --- compiler/rustc_mir_transform/src/coroutine.rs | 44 +++++++++++++++++++ tests/ui/coroutine/issue-149748.rs | 27 ++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tests/ui/coroutine/issue-149748.rs diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 652fd00d54d02..d17e6b3e59624 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -90,6 +90,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, Obliga use tracing::{debug, instrument, trace}; use crate::deref_separator::deref_finder; +use crate::patch::MirPatch; use crate::{abort_unwinding_calls, errors, pass_manager as pm, simplify}; pub(super) struct StateTransform; @@ -210,6 +211,10 @@ struct TransformVisitor<'tcx> { old_yield_ty: Ty<'tcx>, old_ret_ty: Ty<'tcx>, + + body_span: Span, + + patch: MirPatch<'tcx>, } impl<'tcx> TransformVisitor<'tcx> { @@ -383,6 +388,30 @@ impl<'tcx> TransformVisitor<'tcx> { (assign, temp) } + // Create a temporary assignment if the visited destination and RHS now + // refer to overlapping fields of the coroutine state. + // https://github.com/rust-lang/rust/issues/149748 + fn split_overlapping_assignment_if_needed( + &mut self, + dst: Place<'tcx>, + dst_ty: Option>, + rvalue: &mut Rvalue<'tcx>, + location: Location, + ) { + let Some(ty) = dst_ty else { return }; + let Rvalue::Use(operand) = rvalue else { return }; + let (Operand::Copy(src) | Operand::Move(src)) = *operand else { return }; + if dst.is_indirect() || src.is_indirect() || src.local != dst.local { + return; + } + + let temp = Place::from(self.patch.new_temp(ty, self.body_span)); + let temp_assign_stmt = + StatementKind::Assign(Box::new((temp, Rvalue::Use(operand.clone())))); + self.patch.add_statement(location, temp_assign_stmt); + *operand = Operand::Move(temp); + } + /// Swaps all references of `old_local` and `new_local`. #[tracing::instrument(level = "trace", skip(self, body))] fn replace_local(&mut self, old_local: Local, new_local: Local, body: &mut Body<'tcx>) { @@ -416,6 +445,18 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } } + fn visit_assign( + &mut self, + dst: &mut Place<'tcx>, + rvalue: &mut Rvalue<'tcx>, + location: Location, + ) { + let dst_ty = self.remap.get(dst.local).and_then(|entry| entry.map(|(ty, _, _)| ty)); + self.visit_place(dst, PlaceContext::MutatingUse(MutatingUseContext::Store), location); + self.visit_rvalue(rvalue, location); + self.split_overlapping_assignment_if_needed(*dst, dst_ty, rvalue, location); + } + #[tracing::instrument(level = "trace", skip(self, stmt), ret)] fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) { // Remove StorageLive and StorageDead statements for remapped locals @@ -1584,8 +1625,11 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { new_ret_local, old_ret_ty, old_yield_ty, + body_span: body.span, + patch: MirPatch::new(body), }; transform.visit_body(body); + std::mem::replace(&mut transform.patch, MirPatch::new(body)).apply(body); // Swap the actual `RETURN_PLACE` and the provisional `new_ret_local`. transform.replace_local(RETURN_PLACE, new_ret_local, body); diff --git a/tests/ui/coroutine/issue-149748.rs b/tests/ui/coroutine/issue-149748.rs new file mode 100644 index 0000000000000..97aa0e2f2d070 --- /dev/null +++ b/tests/ui/coroutine/issue-149748.rs @@ -0,0 +1,27 @@ +//@ edition:2024 +//@ compile-flags: -Zmir-enable-passes=+Inline,+ReferencePropagation -Zlint-mir +//@ check-pass + +#![feature(gen_blocks)] +#![allow(unused_variables, path_statements)] + +struct NonCopy(i32); + +gen fn refs<'a, 'b>(x: &'a i32, y: &'b i32, z: &'b i32) -> &'b i32 { + yield y; + z; +} + +gen fn moves(x: NonCopy, y: NonCopy, z: NonCopy) -> NonCopy { + yield y; + z; +} + +fn main() { + let z = 3; + let mut refs_iter = refs(&1, &2, &z); + assert_eq!(refs_iter.next(), Some(&3)); + + let mut moves_iter = moves(NonCopy(1), NonCopy(2), NonCopy(3)); + assert!(matches!(moves_iter.next(), Some(_))); +} From 4761ebd37b5972328af274eeeedf6c0d52bcf301 Mon Sep 17 00:00:00 2001 From: MilkBlock <2386925778@qq.com> Date: Mon, 27 Apr 2026 10:43:14 +0800 Subject: [PATCH 2/5] test(coroutine): use descriptive issue test name --- ...sue-149748.rs => overlapping-state-assignment-issue-149748.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/ui/coroutine/{issue-149748.rs => overlapping-state-assignment-issue-149748.rs} (100%) diff --git a/tests/ui/coroutine/issue-149748.rs b/tests/ui/coroutine/overlapping-state-assignment-issue-149748.rs similarity index 100% rename from tests/ui/coroutine/issue-149748.rs rename to tests/ui/coroutine/overlapping-state-assignment-issue-149748.rs From 245a028122bc6d676822e76c71c211ad10abcec5 Mon Sep 17 00:00:00 2001 From: MilkBlock <2386925778@qq.com> Date: Mon, 27 Apr 2026 11:30:53 +0800 Subject: [PATCH 3/5] test(mir-opt): bless coroutine state snapshots --- ...#0}.coroutine_drop_async.0.panic-abort.mir | 21 ++-- ...0}.coroutine_drop_async.0.panic-unwind.mir | 23 ++-- ...y.run2-{closure#0}.Inline.panic-abort.diff | 106 +++++++++-------- ....run2-{closure#0}.Inline.panic-unwind.diff | 110 +++++++++--------- 4 files changed, 135 insertions(+), 125 deletions(-) diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir index 435c1532895ca..34ef74321f624 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir @@ -2,7 +2,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _2; - debug x => ((*_20).0: T); + debug x => ((*_21).0: T); let mut _0: std::task::Poll<()>; let _3: T; let mut _4: impl std::future::Future; @@ -20,16 +20,17 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) let mut _16: std::pin::Pin<&mut impl std::future::Future>; let mut _17: isize; let mut _18: (); - let mut _19: u32; - let mut _20: &mut {async fn body of a()}; + let mut _19: T; + let mut _20: u32; + let mut _21: &mut {async fn body of a()}; scope 1 { - debug x => (((*_20) as variant#4).0: T); + debug x => (((*_21) as variant#4).0: T); } bb0: { - _20 = copy (_1.0: &mut {async fn body of a()}); - _19 = discriminant((*_20)); - switchInt(move _19) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; + _21 = copy (_1.0: &mut {async fn body of a()}); + _20 = discriminant((*_21)); + switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; } bb1: { @@ -45,13 +46,13 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) bb3: { _0 = Poll::<()>::Pending; - discriminant((*_20)) = 4; + discriminant((*_21)) = 4; return; } bb4: { StorageLive(_16); - _15 = &mut (((*_20) as variant#4).1: impl std::future::Future); + _15 = &mut (((*_21) as variant#4).1: impl std::future::Future); _16 = Pin::<&mut impl Future>::new_unchecked(move _15) -> [return: bb7, unwind unreachable]; } @@ -83,7 +84,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) } bb11: { - drop(((*_20).0: T)) -> [return: bb10, unwind unreachable]; + drop(((*_21).0: T)) -> [return: bb10, unwind unreachable]; } bb12: { diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir index 1dc1d08136290..ce188a23eaaa2 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir @@ -2,7 +2,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _2; - debug x => ((*_20).0: T); + debug x => ((*_21).0: T); let mut _0: std::task::Poll<()>; let _3: T; let mut _4: impl std::future::Future; @@ -20,16 +20,17 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) let mut _16: std::pin::Pin<&mut impl std::future::Future>; let mut _17: isize; let mut _18: (); - let mut _19: u32; - let mut _20: &mut {async fn body of a()}; + let mut _19: T; + let mut _20: u32; + let mut _21: &mut {async fn body of a()}; scope 1 { - debug x => (((*_20) as variant#4).0: T); + debug x => (((*_21) as variant#4).0: T); } bb0: { - _20 = copy (_1.0: &mut {async fn body of a()}); - _19 = discriminant((*_20)); - switchInt(move _19) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; + _21 = copy (_1.0: &mut {async fn body of a()}); + _20 = discriminant((*_21)); + switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; } bb1: { @@ -59,13 +60,13 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) bb6: { _0 = Poll::<()>::Pending; - discriminant((*_20)) = 4; + discriminant((*_21)) = 4; return; } bb7: { StorageLive(_16); - _15 = &mut (((*_20) as variant#4).1: impl std::future::Future); + _15 = &mut (((*_21) as variant#4).1: impl std::future::Future); _16 = Pin::<&mut impl Future>::new_unchecked(move _15) -> [return: bb10, unwind: bb15]; } @@ -97,11 +98,11 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) } bb14: { - drop(((*_20).0: T)) -> [return: bb13, unwind: bb4]; + drop(((*_21).0: T)) -> [return: bb13, unwind: bb4]; } bb15 (cleanup): { - discriminant((*_20)) = 2; + discriminant((*_21)) = 2; resume; } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index b5d0dc186293b..6e66f13836ba7 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -39,8 +39,9 @@ + let mut _28: &mut std::task::Context<'_>; + let mut _29: (); + let mut _30: (); -+ let mut _31: u32; -+ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _31: ActionPermit<'_, T>; ++ let mut _32: u32; ++ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 7 { + let mut _15: std::future::Ready<()>; + scope 8 { @@ -50,37 +51,37 @@ + scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 13 (inlined as Future>::poll) { -+ let mut _34: (); -+ let mut _35: std::option::Option<()>; -+ let mut _36: &mut std::option::Option<()>; -+ let mut _37: &mut std::future::Ready<()>; -+ let mut _38: &mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _35: (); ++ let mut _36: std::option::Option<()>; ++ let mut _37: &mut std::option::Option<()>; ++ let mut _38: &mut std::future::Ready<()>; ++ let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _39: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _40: *mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; ++ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _41: &mut &mut std::future::Ready<()>; ++ let mut _42: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } + } + } + scope 17 (inlined Option::<()>::take) { -+ let mut _42: std::option::Option<()>; ++ let mut _43: std::option::Option<()>; + scope 18 (inlined std::mem::replace::>) { + scope 19 { + } + } + } + scope 20 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _43: isize; -+ let mut _44: !; ++ let mut _44: isize; ++ let mut _45: !; + scope 21 { + } + } + } + } + scope 10 (inlined ready::<()>) { -+ let mut _33: std::option::Option<()>; ++ let mut _34: std::option::Option<()>; + } + scope 11 (inlined as IntoFuture>::into_future) { + } @@ -125,9 +126,10 @@ + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); -+ _32 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _31 = discriminant((*_32)); -+ switchInt(move _31) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5]; ++ StorageLive(_33); ++ _33 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _32 = discriminant((*_33)); ++ switchInt(move _32) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5]; } - bb3: { @@ -137,6 +139,7 @@ + } + + bb2: { ++ StorageDead(_33); + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); @@ -154,19 +157,20 @@ } + bb3: { -+ (((*_32) as variant#3).0: ActionPermit<'_, T>) = move ((*_32).0: ActionPermit<'_, T>); ++ _31 = move ((*_33).0: ActionPermit<'_, T>); ++ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move _31; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_33); -+ _33 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _33); -+ StorageDead(_33); ++ StorageLive(_34); ++ _34 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _34); ++ StorageDead(_34); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); -+ (((*_32) as variant#3).1: std::future::Ready<()>) = move _12; ++ (((*_33) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb4; + } + @@ -178,7 +182,7 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _21 = &mut (((*_32) as variant#3).1: std::future::Ready<()>); ++ _21 = &mut (((*_33) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); @@ -189,24 +193,24 @@ + _23 = move _24; + _22 = &mut (*_23); + StorageDead(_24); -+ StorageLive(_37); -+ StorageLive(_39); -+ StorageLive(_44); -+ StorageLive(_34); -+ StorageLive(_35); ++ StorageLive(_38); + StorageLive(_40); -+ _40 = &raw mut _19; -+ _39 = copy _40 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_40); -+ _37 = copy ((*_39).0: &mut std::future::Ready<()>); -+ StorageLive(_42); -+ _42 = Option::<()>::None; -+ _35 = copy ((*_37).0: std::option::Option<()>); -+ ((*_37).0: std::option::Option<()>) = move _42; -+ StorageDead(_42); ++ StorageLive(_45); ++ StorageLive(_35); ++ StorageLive(_36); ++ StorageLive(_41); ++ _41 = &raw mut _19; ++ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); ++ StorageDead(_41); ++ _38 = copy ((*_40).0: &mut std::future::Ready<()>); + StorageLive(_43); -+ _43 = discriminant(_35); -+ switchInt(move _43) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ _43 = Option::<()>::None; ++ _36 = copy ((*_38).0: std::option::Option<()>); ++ ((*_38).0: std::option::Option<()>) = move _43; ++ StorageDead(_43); ++ StorageLive(_44); ++ _44 = discriminant(_36); ++ switchInt(move _44) -> [0: bb11, 1: bb12, otherwise: bb5]; } + + bb5: { @@ -226,7 +230,7 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ discriminant((*_32)) = 3; ++ discriminant((*_33)) = 3; + goto -> bb2; + } + @@ -240,12 +244,12 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable]; ++ drop((((*_33) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable]; + } + + bb8: { + _7 = Poll::<()>::Ready(move _30); -+ discriminant((*_32)) = 1; ++ discriminant((*_33)) = 1; + goto -> bb2; + } + @@ -266,18 +270,18 @@ + } + + bb11: { -+ _44 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _45 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { -+ _34 = move ((_35 as Some).0: ()); -+ StorageDead(_43); -+ StorageDead(_35); -+ _18 = Poll::<()>::Ready(move _34); -+ StorageDead(_34); ++ _35 = move ((_36 as Some).0: ()); + StorageDead(_44); -+ StorageDead(_39); -+ StorageDead(_37); ++ StorageDead(_36); ++ _18 = Poll::<()>::Ready(move _35); ++ StorageDead(_35); ++ StorageDead(_45); ++ StorageDead(_40); ++ StorageDead(_38); + StorageDead(_22); + StorageDead(_19); + _25 = discriminant(_18); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index ffcb0014cec69..069a25ba1a595 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -39,8 +39,9 @@ + let mut _28: &mut std::task::Context<'_>; + let mut _29: (); + let mut _30: (); -+ let mut _31: u32; -+ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _31: ActionPermit<'_, T>; ++ let mut _32: u32; ++ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 7 { + let mut _15: std::future::Ready<()>; + scope 8 { @@ -50,37 +51,37 @@ + scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 13 (inlined as Future>::poll) { -+ let mut _34: (); -+ let mut _35: std::option::Option<()>; -+ let mut _36: &mut std::option::Option<()>; -+ let mut _37: &mut std::future::Ready<()>; -+ let mut _38: &mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _35: (); ++ let mut _36: std::option::Option<()>; ++ let mut _37: &mut std::option::Option<()>; ++ let mut _38: &mut std::future::Ready<()>; ++ let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _39: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _40: *mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; ++ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _41: &mut &mut std::future::Ready<()>; ++ let mut _42: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } + } + } + scope 17 (inlined Option::<()>::take) { -+ let mut _42: std::option::Option<()>; ++ let mut _43: std::option::Option<()>; + scope 18 (inlined std::mem::replace::>) { + scope 19 { + } + } + } + scope 20 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _43: isize; -+ let mut _44: !; ++ let mut _44: isize; ++ let mut _45: !; + scope 21 { + } + } + } + } + scope 10 (inlined ready::<()>) { -+ let mut _33: std::option::Option<()>; ++ let mut _34: std::option::Option<()>; + } + scope 11 (inlined as IntoFuture>::into_future) { + } @@ -125,9 +126,10 @@ + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); -+ _32 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _31 = discriminant((*_32)); -+ switchInt(move _31) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7]; ++ StorageLive(_33); ++ _33 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _32 = discriminant((*_33)); ++ switchInt(move _32) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7]; } - bb3: { @@ -145,6 +147,7 @@ + } + + bb4: { ++ StorageDead(_33); + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); @@ -165,19 +168,20 @@ - StorageDead(_2); - return; + bb5: { -+ (((*_32) as variant#3).0: ActionPermit<'_, T>) = move ((*_32).0: ActionPermit<'_, T>); ++ _31 = move ((*_33).0: ActionPermit<'_, T>); ++ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move _31; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_33); -+ _33 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _33); -+ StorageDead(_33); ++ StorageLive(_34); ++ _34 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _34); ++ StorageDead(_34); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); -+ (((*_32) as variant#3).1: std::future::Ready<()>) = move _12; ++ (((*_33) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb6; } @@ -189,7 +193,7 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _21 = &mut (((*_32) as variant#3).1: std::future::Ready<()>); ++ _21 = &mut (((*_33) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); @@ -200,24 +204,24 @@ + _23 = move _24; + _22 = &mut (*_23); + StorageDead(_24); -+ StorageLive(_37); -+ StorageLive(_39); -+ StorageLive(_44); -+ StorageLive(_34); -+ StorageLive(_35); ++ StorageLive(_38); + StorageLive(_40); -+ _40 = &raw mut _19; -+ _39 = copy _40 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_40); -+ _37 = copy ((*_39).0: &mut std::future::Ready<()>); -+ StorageLive(_42); -+ _42 = Option::<()>::None; -+ _35 = copy ((*_37).0: std::option::Option<()>); -+ ((*_37).0: std::option::Option<()>) = move _42; -+ StorageDead(_42); ++ StorageLive(_45); ++ StorageLive(_35); ++ StorageLive(_36); ++ StorageLive(_41); ++ _41 = &raw mut _19; ++ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); ++ StorageDead(_41); ++ _38 = copy ((*_40).0: &mut std::future::Ready<()>); + StorageLive(_43); -+ _43 = discriminant(_35); -+ switchInt(move _43) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ _43 = Option::<()>::None; ++ _36 = copy ((*_38).0: std::option::Option<()>); ++ ((*_38).0: std::option::Option<()>) = move _43; ++ StorageDead(_43); ++ StorageLive(_44); ++ _44 = discriminant(_36); ++ switchInt(move _44) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -239,7 +243,7 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ discriminant((*_32)) = 3; ++ discriminant((*_33)) = 3; + goto -> bb4; + } + @@ -253,12 +257,12 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12]; ++ drop((((*_33) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12]; + } + + bb10: { + _7 = Poll::<()>::Ready(move _30); -+ discriminant((*_32)) = 1; ++ discriminant((*_33)) = 1; + goto -> bb4; + } + @@ -270,11 +274,11 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)]; ++ drop((((*_33) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)]; + } + + bb12 (cleanup): { -+ discriminant((*_32)) = 2; ++ discriminant((*_33)) = 2; + goto -> bb2; + } + @@ -299,18 +303,18 @@ + } + + bb16: { -+ _44 = option::expect_failed(const "`Ready` polled after completion") -> bb11; ++ _45 = option::expect_failed(const "`Ready` polled after completion") -> bb11; + } + + bb17: { -+ _34 = move ((_35 as Some).0: ()); -+ StorageDead(_43); -+ StorageDead(_35); -+ _18 = Poll::<()>::Ready(move _34); -+ StorageDead(_34); ++ _35 = move ((_36 as Some).0: ()); + StorageDead(_44); -+ StorageDead(_39); -+ StorageDead(_37); ++ StorageDead(_36); ++ _18 = Poll::<()>::Ready(move _35); ++ StorageDead(_35); ++ StorageDead(_45); ++ StorageDead(_40); ++ StorageDead(_38); + StorageDead(_22); + StorageDead(_19); + _25 = discriminant(_18); From 4f6de412d29d52114678aa442f4d8712938b8511 Mon Sep 17 00:00:00 2001 From: MilkBlock <2386925778@qq.com> Date: Mon, 27 Apr 2026 23:44:44 +0800 Subject: [PATCH 4/5] beautify --- compiler/rustc_mir_transform/src/coroutine.rs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d17e6b3e59624..2dd0f0c2758c1 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -391,6 +391,11 @@ impl<'tcx> TransformVisitor<'tcx> { // Create a temporary assignment if the visited destination and RHS now // refer to overlapping fields of the coroutine state. // https://github.com/rust-lang/rust/issues/149748 + // trans + // _x.a = copy/move _x.b + // into + // _temp = copy/move _x.b + // _x.a = move _temp fn split_overlapping_assignment_if_needed( &mut self, dst: Place<'tcx>, @@ -398,18 +403,19 @@ impl<'tcx> TransformVisitor<'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) { - let Some(ty) = dst_ty else { return }; - let Rvalue::Use(operand) = rvalue else { return }; - let (Operand::Copy(src) | Operand::Move(src)) = *operand else { return }; - if dst.is_indirect() || src.is_indirect() || src.local != dst.local { - return; + if let (Operand::Copy(src) | Operand::Move(src)) = *operand + && !src.is_indirect() + && !dst.is_indirect() + && src.local == dst.local + && let Rvalue::Use(operand) = rvalue + && let Some(ty) = dst_ty + { + let temp = Place::from(self.patch.new_temp(ty, self.body_span)); + let temp_assign_stmt = + StatementKind::Assign(Box::new((temp, Rvalue::Use(operand.clone())))); + self.patch.add_statement(location, temp_assign_stmt); + *operand = Operand::Move(temp); } - - let temp = Place::from(self.patch.new_temp(ty, self.body_span)); - let temp_assign_stmt = - StatementKind::Assign(Box::new((temp, Rvalue::Use(operand.clone())))); - self.patch.add_statement(location, temp_assign_stmt); - *operand = Operand::Move(temp); } /// Swaps all references of `old_local` and `new_local`. From a34ac056e41520d7573c8f20c5d4e2a934de86f7 Mon Sep 17 00:00:00 2001 From: MilkBlock <2386925778@qq.com> Date: Mon, 27 Apr 2026 23:58:03 +0800 Subject: [PATCH 5/5] nit --- compiler/rustc_mir_transform/src/coroutine.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 2dd0f0c2758c1..b3d293f0bd1b4 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -403,11 +403,11 @@ impl<'tcx> TransformVisitor<'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) { - if let (Operand::Copy(src) | Operand::Move(src)) = *operand + if let Rvalue::Use(operand) = rvalue + && let Operand::Copy(src) | Operand::Move(src) = *operand && !src.is_indirect() && !dst.is_indirect() && src.local == dst.local - && let Rvalue::Use(operand) = rvalue && let Some(ty) = dst_ty { let temp = Place::from(self.patch.new_temp(ty, self.body_span));