Skip to content

AsyncDrop not called when type is inside Box #143658

@beepster4096

Description

@beepster4096

I tried this code (modified tests\ui\async-await\async-drop\async-drop.rs):

#![feature(async_drop)] #![allow(incomplete_features)] use std::mem::ManuallyDrop; //@ edition: 2021 #[inline(never)] fn myprintln(msg: &str, my_resource_handle: usize) { println!("{} : {}", msg, my_resource_handle); } use std::{ future::{Future, async_drop_in_place, AsyncDrop}, pin::{pin, Pin}, sync::{mpsc, Arc}, task::{Context, Poll, Wake, Waker}, }; struct Foo { my_resource_handle: usize, } impl Foo { fn new(my_resource_handle: usize) -> Self { let out = Foo { my_resource_handle, }; myprintln("Foo::new()", my_resource_handle); out } } impl Drop for Foo { fn drop(&mut self) { myprintln("Foo::drop()", self.my_resource_handle); } } impl AsyncDrop for Foo { async fn drop(self: Pin<&mut Self>) { myprintln("Foo::async drop()", self.my_resource_handle); } } fn main() { { // added box here let _ = Box::new(Foo::new(7)); } println!("Middle"); block_on(bar(10)); println!("Done") } async fn bar(ident_base: usize) { // added box here let mut first = Box::new(Foo::new(ident_base)); } fn block_on<F>(fut_unpin: F) -> F::Output where F: Future, { let mut fut_pin = pin!(ManuallyDrop::new(fut_unpin)); let mut fut: Pin<&mut F> = unsafe { Pin::map_unchecked_mut(fut_pin.as_mut(), |x| &mut **x) }; let (waker, rx) = simple_waker(); let mut context = Context::from_waker(&waker); let rv = loop { match fut.as_mut().poll(&mut context) { Poll::Ready(out) => break out, // expect wake in polls Poll::Pending => rx.try_recv().unwrap(), } }; let drop_fut_unpin = unsafe { async_drop_in_place(fut.get_unchecked_mut()) }; let mut drop_fut: Pin<&mut _> = pin!(drop_fut_unpin); loop { match drop_fut.as_mut().poll(&mut context) { Poll::Ready(()) => break, Poll::Pending => rx.try_recv().unwrap(), } } rv } fn simple_waker() -> (Waker, mpsc::Receiver<()>) { struct SimpleWaker { tx: std::sync::mpsc::Sender<()>, } impl Wake for SimpleWaker { fn wake(self: Arc<Self>) { self.tx.send(()).unwrap(); } } let (tx, rx) = mpsc::channel(); (Waker::from(Arc::new(SimpleWaker { tx })), rx) }

I expected to see this happen: Test produces same output as before:

Foo::new() : 7 Foo::drop() : 7 Middle Foo::new() : 10 Foo::async drop() : 10 Done

Instead, this happened: Test produces different output; Foo's async drop is never called:

Foo::new() : 7 Foo::drop() : 7 Middle Foo::new() : 10 Foo::drop() : 10 Done

Meta

rustc --version --verbose:

rustc 1.90.0-nightly (a2d45f73c 2025-07-07) 

This has a knownbug test at tests/ui/async-await/async-drop/async-drop-box.rs as of #143672

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-boxArea: Our favorite opsem complicationC-bugCategory: This is a bug.F-async_drop`#![feature(async_drop)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions