Fix Async Drop MIR bug with async_drop_in_place (Squashed)

This commit is contained in:
root
2026-02-24 00:04:33 -08:00
parent ef70767064
commit ce93a5335d
3 changed files with 166 additions and 7 deletions
@@ -326,12 +326,23 @@ fn build_async_drop(
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 @@ fn build_async_drop(
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(
@@ -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<Output = ()>;
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<Output = ()>;
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::<Foo>(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::<Foo>(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;
}
}
+27
View File
@@ -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)];
}