diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 8998be26412d5..f273dad17e6b9 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -326,12 +326,23 @@ where const_: Const::zero_sized(pin_obj_new_unchecked_fn), })); + // Create an intermediate block that does StorageDead(fut) then jumps to succ. + // This is necessary because `succ` may differ from `self.succ` (e.g. when + // build_async_drop is called from drop_loop, `succ` is the loop header). + // Placing StorageDead directly at `self.succ` would miss the loop-back edge, + // causing StorageLive(fut) to fire again without a preceding StorageDead. + let succ_with_dead = self.new_block_with_statements( + unwind, + vec![Statement::new(self.source_info, StatementKind::StorageDead(fut.local))], + TerminatorKind::Goto { target: succ }, + ); + // #3:drop_term_bb let drop_term_bb = self.new_block( unwind, TerminatorKind::Drop { place, - target: succ, + target: succ_with_dead, unwind: unwind.into_action(), replace: false, drop: dropline, @@ -381,12 +392,6 @@ where fn_span: self.source_info.span, }, ); - - // StorageDead(fut) in self.succ block (at the begin) - self.elaborator.patch().add_statement( - Location { block: self.succ, statement_index: 0 }, - StatementKind::StorageDead(fut.local), - ); // StorageDead(fut) in unwind block (at the begin) if let Unwind::To(block) = unwind { self.elaborator.patch().add_statement( diff --git a/tests/mir-opt/async_drop_mir_pin.core.future-async_drop-async_drop_in_place-{closure#0}.[Foo;1].MentionedItems.after.mir b/tests/mir-opt/async_drop_mir_pin.core.future-async_drop-async_drop_in_place-{closure#0}.[Foo;1].MentionedItems.after.mir new file mode 100644 index 0000000000000..062db19216259 --- /dev/null +++ b/tests/mir-opt/async_drop_mir_pin.core.future-async_drop-async_drop_in_place-{closure#0}.[Foo;1].MentionedItems.after.mir @@ -0,0 +1,127 @@ +// MIR for `std::future::async_drop_in_place::{closure#0}` after MentionedItems + +fn async_drop_in_place::{closure#0}(_1: {async fn body of async_drop_in_place<[Foo; 1]>()}, _2: std::future::ResumeTy) -> () +yields () + { + let mut _0: (); + let mut _3: *mut [Foo; 1]; + let mut _4: *mut [Foo; 1]; + let mut _5: *mut [Foo]; + let mut _6: usize; + let mut _7: usize; + let mut _8: *mut Foo; + let mut _9: bool; + let mut _10: *mut Foo; + let mut _11: bool; + let mut _12: impl std::future::Future; + let mut _13: &mut Foo; + let mut _14: std::pin::Pin<&mut Foo>; + let mut _15: &mut Foo; + let mut _16: *mut Foo; + let mut _17: *mut Foo; + let mut _18: bool; + let mut _19: impl std::future::Future; + let mut _20: &mut Foo; + let mut _21: std::pin::Pin<&mut Foo>; + let mut _22: &mut Foo; + let mut _23: *mut Foo; + + bb0: { + _3 = move (_1.0: *mut [Foo; 1]); + goto -> bb17; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } + + bb3 (cleanup): { + _8 = &raw mut (*_5)[_7]; + _7 = Add(move _7, const 1_usize); + drop((*_8)) -> [return: bb4, unwind terminate(cleanup)]; + } + + bb4 (cleanup): { + StorageDead(_12); + StorageDead(_19); + _9 = Eq(copy _7, copy _6); + switchInt(move _9) -> [0: bb3, otherwise: bb2]; + } + + bb5: { + _10 = &raw mut (*_5)[_7]; + _7 = Add(move _7, const 1_usize); + _13 = &mut (*_10); + _14 = Pin::<&mut Foo>::new_unchecked(move _13) -> [return: bb9, unwind: bb4]; + } + + bb6: { + StorageDead(_19); + _11 = Eq(copy _7, copy _6); + switchInt(move _11) -> [0: bb5, otherwise: bb1]; + } + + bb7: { + StorageDead(_12); + goto -> bb6; + } + + bb8: { + async drop((*_10); poll=_12) -> [return: bb7, unwind: bb4]; + } + + bb9: { + _15 = copy (_14.0: &mut Foo); + _16 = &raw mut (*_15); + StorageLive(_12); + _12 = async_drop_in_place::(move _16) -> [return: bb8, unwind: bb4]; + } + + bb10: { + _17 = &raw mut (*_5)[_7]; + _7 = Add(move _7, const 1_usize); + _20 = &mut (*_17); + _21 = Pin::<&mut Foo>::new_unchecked(move _20) -> [return: bb14, unwind: bb4]; + } + + bb11: { + _18 = Eq(copy _7, copy _6); + switchInt(move _18) -> [0: bb10, otherwise: bb1]; + } + + bb12: { + StorageDead(_19); + goto -> bb11; + } + + bb13: { + async drop((*_17); poll=_19) -> [return: bb12, unwind: bb4, drop: bb6]; + } + + bb14: { + _22 = copy (_21.0: &mut Foo); + _23 = &raw mut (*_22); + StorageLive(_19); + _19 = async_drop_in_place::(move _23) -> [return: bb13, unwind: bb4]; + } + + bb15: { + _6 = PtrMetadata(copy _5); + _7 = const 0_usize; + goto -> bb11; + } + + bb16: { + goto -> bb15; + } + + bb17: { + _4 = &raw mut (*_3); + _5 = move _4 as *mut [Foo] (PointerCoercion(Unsize, Implicit)); + goto -> bb16; + } +} diff --git a/tests/mir-opt/async_drop_mir_pin.rs b/tests/mir-opt/async_drop_mir_pin.rs new file mode 100644 index 0000000000000..35626f13f8945 --- /dev/null +++ b/tests/mir-opt/async_drop_mir_pin.rs @@ -0,0 +1,27 @@ +//@edition: 2024 +//@ test-mir-pass: MentionedItems +// skip-filecheck +#![feature(async_drop)] +#![allow(incomplete_features)] +use std::future::AsyncDrop; +use std::pin::Pin; +struct Foo { + my_resource_handle: usize, +} +impl Foo { + fn new(my_resource_handle: usize) -> Self { + let out = Foo { my_resource_handle }; + out + } +} +impl Drop for Foo { + fn drop(&mut self) {} +} +// EMIT_MIR core.future-async_drop-async_drop_in_place-{closure#0}.[Foo;1].MentionedItems.after.mir +impl AsyncDrop for Foo { + async fn drop(self: Pin<&mut Self>) {} +} +fn main() {} +async fn bar() { + [Foo::new(3)]; +}