AsyncDrop implementation using shim codegen of async_drop_in_place::{closure}, scoped async drop added.

This commit is contained in:
Andrew Zhogin 2024-08-26 16:45:15 +03:00
parent 52c1838fa7
commit c366756a85
116 changed files with 4054 additions and 1879 deletions

View file

@ -1,11 +0,0 @@
//@ known-bug: rust-lang/rust#128695
//@ edition: 2021
use core::pin::{pin, Pin};
fn main() {
let fut = pin!(async {
let async_drop_fut = pin!(core::future::async_drop(async {}));
(async_drop_fut).await;
});
}

View file

@ -68,14 +68,18 @@ yields ()
}
bb10: {
drop(_1) -> [return: bb11, unwind: bb12];
drop(_1) -> [return: bb11, unwind: bb13, drop: bb12];
}
bb11: {
return;
}
bb12 (cleanup): {
bb12: {
coroutine_drop;
}
bb13 (cleanup): {
resume;
}
}

View file

@ -51,14 +51,18 @@ yields ()
}
bb6: {
drop(_1) -> [return: bb7, unwind: bb8];
drop(_1) -> [return: bb7, unwind: bb9, drop: bb8];
}
bb7: {
return;
}
bb8 (cleanup): {
bb8: {
coroutine_drop;
}
bb9 (cleanup): {
resume;
}
}

View file

@ -34,14 +34,18 @@ yields ()
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
drop(_1) -> [return: bb1, unwind: bb3, drop: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
bb2: {
coroutine_drop;
}
bb3 (cleanup): {
resume;
}
}

View file

@ -34,14 +34,18 @@ yields ()
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
drop(_1) -> [return: bb1, unwind: bb3, drop: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
bb2: {
coroutine_drop;
}
bb3 (cleanup): {
resume;
}
}

View file

@ -34,14 +34,18 @@ yields ()
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
drop(_1) -> [return: bb1, unwind: bb3, drop: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
bb2: {
coroutine_drop;
}
bb3 (cleanup): {
resume;
}
}

View file

@ -34,14 +34,18 @@ yields ()
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
drop(_1) -> [return: bb1, unwind: bb3, drop: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
bb2: {
coroutine_drop;
}
bb3 (cleanup): {
resume;
}
}

View file

@ -0,0 +1,101 @@
//@ run-pass
//@ check-run-results
// Future `bar` with internal async drop `Foo` will have async drop itself.
// And we trying to drop this future in sync context (`block_on` func)
#![feature(async_drop)]
#![allow(incomplete_features)]
use std::mem::ManuallyDrop;
//@ edition: 2021
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,
};
println!("Foo::new({})", my_resource_handle);
out
}
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo::drop({})", self.my_resource_handle);
}
}
impl AsyncDrop for Foo {
async fn drop(self: Pin<&mut Self>) {
println!("Foo::async drop({})", self.my_resource_handle);
}
}
fn main() {
block_on(bar(10));
println!("done")
}
async fn baz(ident_base: usize) {
let mut _first = Foo::new(ident_base);
}
async fn bar(ident_base: usize) {
let mut _first = Foo::new(ident_base);
baz(ident_base + 1).await;
}
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)
}

View file

@ -0,0 +1,5 @@
Foo::new(10)
Foo::new(11)
Foo::async drop(11)
Foo::async drop(10)
done

View file

@ -0,0 +1,82 @@
//@ run-pass
//@ check-run-results
// Future `bar` with internal async drop `Foo` will have async drop itself.
// And we trying to drop this future in sync context (`block_on` func)
#![feature(async_drop)]
#![allow(incomplete_features)]
//@ edition: 2021
use std::{
future::{Future, 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,
};
println!("Foo::new({})", my_resource_handle);
out
}
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo::drop({})", self.my_resource_handle);
}
}
impl AsyncDrop for Foo {
async fn drop(self: Pin<&mut Self>) {
println!("Foo::async drop({})", self.my_resource_handle);
}
}
fn main() {
block_on(bar(10));
println!("done")
}
async fn bar(ident_base: usize) {
let mut _first = Foo::new(ident_base);
}
fn block_on<F>(fut: F) -> F::Output
where
F: Future,
{
let mut fut = pin!(fut);
let (waker, rx) = simple_waker();
let mut context = Context::from_waker(&waker);
loop {
match fut.as_mut().poll(&mut context) {
Poll::Ready(out) => break out,
// expect wake in polls
Poll::Pending => rx.try_recv().unwrap(),
}
}
}
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)
}

View file

@ -0,0 +1,3 @@
Foo::new(10)
Foo::async drop(10)
done

View file

@ -0,0 +1,112 @@
//@ run-pass
//@ check-run-results
// struct `Foo` has both sync and async drop.
// Struct `Complex` contains three `Foo` fields and has complex async drop glue.
#![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() {
{
let _ = Foo::new(7);
}
println!("Middle");
{
block_on(bar(10));
}
println!("Done")
}
async fn bar(ident_base: usize) {
let _vec: [Foo; 4] = [
Foo::new(ident_base),
Foo::new(ident_base + 1),
Foo::new(ident_base + 2),
Foo::new(ident_base + 3)
];
}
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)
}

View file

@ -0,0 +1,12 @@
Foo::new() : 7
Foo::drop() : 7
Middle
Foo::new() : 10
Foo::new() : 11
Foo::new() : 12
Foo::new() : 13
Foo::async drop() : 10
Foo::async drop() : 11
Foo::async drop() : 12
Foo::async drop() : 13
Done

View file

@ -0,0 +1,111 @@
//@ run-pass
//@ check-run-results
// struct `Foo` has both sync and async drop.
#![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() {
{
let _ = Foo::new(7);
}
println!("Middle");
{
block_on(bar(6, 10));
}
println!("Done")
}
async fn bar<T>(_arg: T, ident_base: usize) {
let _vec: [Foo; 4] = [
Foo::new(ident_base),
Foo::new(ident_base + 1),
Foo::new(ident_base + 2),
Foo::new(ident_base + 3)
];
}
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)
}

View file

@ -0,0 +1,12 @@
Foo::new() : 7
Foo::drop() : 7
Middle
Foo::new() : 10
Foo::new() : 11
Foo::new() : 12
Foo::new() : 13
Foo::async drop() : 10
Foo::async drop() : 11
Foo::async drop() : 12
Foo::async drop() : 13
Done

View file

@ -0,0 +1,124 @@
//@ run-pass
//@ check-run-results
// struct `Foo` has both sync and async drop.
// Struct `Complex` contains three `Foo` fields and has complex async drop glue.
#![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,
}
#[allow(dead_code)]
struct Complex {
field1: Foo,
field2: Foo,
field3: Foo,
}
impl Complex {
fn new(my_resource_handle: usize) -> Self {
myprintln("Complex::new()", my_resource_handle);
let field1 = Foo::new(my_resource_handle);
let field2 = Foo::new(my_resource_handle + 1);
let field3 = Foo::new(my_resource_handle + 2);
Complex { field1, field2, field3 }
}
}
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() {
{
let _ = Foo::new(7);
}
println!("Middle");
{
block_on(bar(10));
}
println!("Done")
}
async fn bar(ident_base: usize) {
let _complex = Complex::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)
}

View file

@ -0,0 +1,11 @@
Foo::new() : 7
Foo::drop() : 7
Middle
Complex::new() : 10
Foo::new() : 10
Foo::new() : 11
Foo::new() : 12
Foo::async drop() : 10
Foo::async drop() : 11
Foo::async drop() : 12
Done

View file

@ -52,21 +52,20 @@ fn main() {
let i = 13;
let fut = pin!(async {
test_async_drop(Int(0), 0).await;
// FIXME(#63818): niches in coroutines are disabled.
// Some of these sizes should be smaller, as indicated in comments.
test_async_drop(AsyncInt(0), /*104*/ 112).await;
test_async_drop([AsyncInt(1), AsyncInt(2)], /*152*/ 168).await;
test_async_drop((AsyncInt(3), AsyncInt(4)), /*488*/ 528).await;
test_async_drop(5, 0).await;
test_async_drop(Int(0), 16).await;
test_async_drop(AsyncInt(0), 32).await;
test_async_drop([AsyncInt(1), AsyncInt(2)], 104).await;
test_async_drop((AsyncInt(3), AsyncInt(4)), 120).await;
test_async_drop(5, 16).await;
let j = 42;
test_async_drop(&i, 0).await;
test_async_drop(&j, 0).await;
test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, /*1688*/ 1792).await;
test_async_drop(ManuallyDrop::new(AsyncInt(9)), 0).await;
test_async_drop(&i, 16).await;
test_async_drop(&j, 16).await;
test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, 168).await;
test_async_drop(ManuallyDrop::new(AsyncInt(9)), 16).await;
let foo = AsyncInt(10);
test_async_drop(AsyncReference { foo: &foo }, /*104*/ 112).await;
test_async_drop(AsyncReference { foo: &foo }, 32).await;
let _ = ManuallyDrop::new(foo);
let foo = AsyncInt(11);
test_async_drop(
@ -75,21 +74,22 @@ fn main() {
let foo = AsyncInt(10);
foo
},
/*120*/ 136,
48,
)
.await;
test_async_drop(AsyncEnum::A(AsyncInt(12)), /*680*/ 736).await;
test_async_drop(AsyncEnum::B(SyncInt(13)), /*680*/ 736).await;
test_async_drop(AsyncEnum::A(AsyncInt(12)), 104).await;
test_async_drop(AsyncEnum::B(SyncInt(13)), 104).await;
test_async_drop(SyncInt(14), /*16*/ 24).await;
test_async_drop(SyncInt(14), 16).await;
test_async_drop(
SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) },
/*3064*/ 3296,
120,
)
.await;
let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19)));
let mut ptr19 = mem::MaybeUninit::new(AsyncInt(19));
let async_drop_fut = pin!(unsafe { async_drop_in_place(ptr19.as_mut_ptr()) });
test_idempotency(async_drop_fut).await;
let foo = AsyncInt(20);
@ -101,11 +101,11 @@ fn main() {
black_box(core::future::ready(())).await;
foo
},
/*120*/ 136,
48,
)
.await;
test_async_drop(AsyncUnion { signed: 21 }, /*32*/ 40).await;
test_async_drop(AsyncUnion { signed: 21 }, 32).await;
});
let res = fut.poll(&mut cx);
assert_eq!(res, Poll::Ready(()));
@ -113,13 +113,14 @@ fn main() {
struct AsyncInt(i32);
impl Drop for AsyncInt {
fn drop(&mut self) {
println!("AsyncInt::drop: {}", self.0);
}
}
impl AsyncDrop for AsyncInt {
type Dropper<'a> = impl Future<Output = ()>;
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
async move {
println!("AsyncInt::Dropper::poll: {}", self.0);
}
async fn drop(self: Pin<&mut Self>) {
println!("AsyncInt::Dropper::poll: {}", self.0);
}
}
@ -148,13 +149,15 @@ struct AsyncReference<'a> {
foo: &'a AsyncInt,
}
impl AsyncDrop for AsyncReference<'_> {
type Dropper<'a> = impl Future<Output = ()> where Self: 'a;
impl Drop for AsyncReference<'_> {
fn drop(&mut self) {
println!("AsyncReference::drop: {}", self.foo.0);
}
}
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
async move {
println!("AsyncReference::Dropper::poll: {}", self.foo.0);
}
impl AsyncDrop for AsyncReference<'_> {
async fn drop(self: Pin<&mut Self>) {
println!("AsyncReference::Dropper::poll: {}", self.foo.0);
}
}
@ -166,13 +169,15 @@ struct AsyncStruct {
b: AsyncInt,
}
impl AsyncDrop for AsyncStruct {
type Dropper<'a> = impl Future<Output = ()>;
impl Drop for AsyncStruct {
fn drop(&mut self) {
println!("AsyncStruct::drop: {}", self.i);
}
}
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
async move {
println!("AsyncStruct::Dropper::poll: {}", self.i);
}
impl AsyncDrop for AsyncStruct {
async fn drop(self: Pin<&mut Self>) {
println!("AsyncStruct::Dropper::poll: {}", self.i);
}
}
@ -181,23 +186,34 @@ enum AsyncEnum {
B(SyncInt),
}
impl Drop for AsyncEnum {
fn drop(&mut self) {
let new_self = match self {
AsyncEnum::A(foo) => {
println!("AsyncEnum(A)::drop: {}", foo.0);
AsyncEnum::B(SyncInt(foo.0))
}
AsyncEnum::B(foo) => {
println!("AsyncEnum(B)::drop: {}", foo.0);
AsyncEnum::A(AsyncInt(foo.0))
}
};
mem::forget(mem::replace(&mut *self, new_self));
}
}
impl AsyncDrop for AsyncEnum {
type Dropper<'a> = impl Future<Output = ()>;
fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> {
async move {
let new_self = match &*self {
AsyncEnum::A(foo) => {
println!("AsyncEnum(A)::Dropper::poll: {}", foo.0);
AsyncEnum::B(SyncInt(foo.0))
}
AsyncEnum::B(foo) => {
println!("AsyncEnum(B)::Dropper::poll: {}", foo.0);
AsyncEnum::A(AsyncInt(foo.0))
}
};
mem::forget(mem::replace(&mut *self, new_self));
}
async fn drop(mut self: Pin<&mut Self>) {
let new_self = match &*self {
AsyncEnum::A(foo) => {
println!("AsyncEnum(A)::Dropper::poll: {}", foo.0);
AsyncEnum::B(SyncInt(foo.0))
}
AsyncEnum::B(foo) => {
println!("AsyncEnum(B)::Dropper::poll: {}", foo.0);
AsyncEnum::A(AsyncInt(foo.0))
}
};
mem::forget(mem::replace(&mut *self, new_self));
}
}
@ -207,16 +223,21 @@ union AsyncUnion {
unsigned: u32,
}
impl AsyncDrop for AsyncUnion {
type Dropper<'a> = impl Future<Output = ()>;
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
async move {
println!(
"AsyncUnion::Dropper::poll: {}, {}",
unsafe { self.signed },
unsafe { self.unsigned },
);
}
impl Drop for AsyncUnion {
fn drop(&mut self) {
println!(
"AsyncUnion::drop: {}, {}",
unsafe { self.signed },
unsafe { self.unsigned },
);
}
}
impl AsyncDrop for AsyncUnion {
async fn drop(self: Pin<&mut Self>) {
println!(
"AsyncUnion::Dropper::poll: {}, {}",
unsafe { self.signed },
unsafe { self.unsigned },
);
}
}

View file

@ -0,0 +1,110 @@
//@ run-pass
//@ check-run-results
// Test async drop of coroutine `bar` (with internal async drop),
// stopped at the middle of execution, with AsyncDrop object Foo active.
#![feature(async_drop)]
#![allow(incomplete_features)]
//@ edition: 2021
use std::mem::ManuallyDrop;
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,
};
println!("Foo::new({})", my_resource_handle);
out
}
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo::drop({})", self.my_resource_handle);
}
}
impl AsyncDrop for Foo {
async fn drop(self: Pin<&mut Self>) {
println!("Foo::async drop({})", self.my_resource_handle);
}
}
fn main() {
block_on_and_drop_in_the_middle(bar(10));
println!("done")
}
pub struct MiddleFuture {
first_call: bool,
}
impl Future for MiddleFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.first_call {
println!("MiddleFuture first poll");
self.first_call = false;
Poll::Pending
} else {
println!("MiddleFuture Ready");
Poll::Ready(())
}
}
}
async fn bar(ident_base: usize) {
let middle = MiddleFuture { first_call: true };
let mut _first = Foo::new(ident_base);
middle.await; // Hanging `bar` future before Foo drop
}
fn block_on_and_drop_in_the_middle<F>(fut_unpin: F) -> F::Output
where
F: Future<Output = ()>,
{
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 poll1 = fut.as_mut().poll(&mut context);
assert!(poll1.is_pending());
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(),
}
}
}
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)
}

View file

@ -0,0 +1,4 @@
Foo::new(10)
MiddleFuture first poll
Foo::async drop(10)
done

View file

@ -0,0 +1,127 @@
//@ run-pass
//@ check-run-results
// struct `Foo` has both sync and async drop.
// Struct `Complex` contains three `Foo` fields and one of them is moved out.
#![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,
}
#[allow(dead_code)]
struct Complex {
field1: Foo,
field2: Foo,
field3: Foo,
}
impl Complex {
fn new(my_resource_handle: usize) -> Self {
myprintln("Complex::new()", my_resource_handle);
let field1 = Foo::new(my_resource_handle);
let field2 = Foo::new(my_resource_handle + 1);
let field3 = Foo::new(my_resource_handle + 2);
Complex { field1, field2, field3 }
}
}
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() {
{
let _ = Foo::new(7);
}
println!("Middle");
// Inside field1 and field3 of Complex must be dropped (as async drop)
// field2 must be dropped here (as sync drop)
{
let _field2 = block_on(bar(10));
}
println!("Done")
}
async fn bar(ident_base: usize) -> Foo {
let complex = Complex::new(ident_base);
complex.field2
}
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)
}

View file

@ -0,0 +1,11 @@
Foo::new() : 7
Foo::drop() : 7
Middle
Complex::new() : 10
Foo::new() : 10
Foo::new() : 11
Foo::new() : 12
Foo::async drop() : 10
Foo::async drop() : 12
Foo::drop() : 11
Done

View file

@ -0,0 +1,105 @@
//@ run-pass
//@ check-run-results
// struct `Foo` has both sync and async drop.
// Sync version is called in sync context, async version is called in async function.
#![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() {
{
let _ = Foo::new(7);
}
println!("Middle");
block_on(bar(10));
println!("Done")
}
async fn bar(ident_base: usize) {
let mut _first = 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)
}

View file

@ -0,0 +1,6 @@
Foo::new() : 7
Foo::drop() : 7
Middle
Foo::new() : 10
Foo::async drop() : 10
Done

View file

@ -1,6 +1,11 @@
//@ known-bug: #132103
//@ run-pass
//! This test used to ICE: rust-lang/rust#132103
//! Fixed when re-work async drop to shim drop glue coroutine scheme.
//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
//@ edition: 2018
#![feature(async_drop)]
#![allow(incomplete_features)]
use core::future::{async_drop_in_place, Future};
use core::mem::{self};
use core::pin::pin;
@ -18,5 +23,5 @@ fn main() {
let fut = pin!(async {
test_async_drop(test_async_drop(0)).await;
});
fut.poll(&mut cx);
let _ = fut.poll(&mut cx);
}

View file

@ -0,0 +1,13 @@
//! This test used to ICE: rust-lang/rust#128695
//! Fixed when re-work async drop to shim drop glue coroutine scheme.
//@ edition: 2021
use core::pin::{pin, Pin};
fn main() {
let fut = pin!(async {
let async_drop_fut = pin!(core::future::async_drop(async {})); //~ ERROR: expected function, found module `core::future::async_drop`
//~^ ERROR: module `async_drop` is private
(async_drop_fut).await;
});
}

View file

@ -0,0 +1,19 @@
error[E0423]: expected function, found module `core::future::async_drop`
--> $DIR/ex-ice1.rs:9:35
|
LL | let async_drop_fut = pin!(core::future::async_drop(async {}));
| ^^^^^^^^^^^^^^^^^^^^^^^^ not a function
error[E0603]: module `async_drop` is private
--> $DIR/ex-ice1.rs:9:49
|
LL | let async_drop_fut = pin!(core::future::async_drop(async {}));
| ^^^^^^^^^^ private module
|
note: the module `async_drop` is defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0423, E0603.
For more information about an error, try `rustc --explain E0423`.

View file

@ -0,0 +1,16 @@
//@ edition: 2021
use std::future::AsyncDrop; //~ ERROR use of unstable library feature `async_drop`
use std::pin::Pin;
struct Foo {}
impl Drop for Foo {
fn drop(&mut self) {}
}
impl AsyncDrop for Foo { //~ ERROR use of unstable library feature `async_drop`
async fn drop(self: Pin<&mut Self>) {} //~ ERROR use of unstable library feature `async_drop`
}
fn main() {}

View file

@ -0,0 +1,33 @@
error[E0658]: use of unstable library feature `async_drop`
--> $DIR/feature-gate-async-drop.rs:3:5
|
LL | use std::future::AsyncDrop;
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #126482 <https://github.com/rust-lang/rust/issues/126482> for more information
= help: add `#![feature(async_drop)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `async_drop`
--> $DIR/feature-gate-async-drop.rs:13:5
|
LL | async fn drop(self: Pin<&mut Self>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #126482 <https://github.com/rust-lang/rust/issues/126482> for more information
= help: add `#![feature(async_drop)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `async_drop`
--> $DIR/feature-gate-async-drop.rs:12:6
|
LL | impl AsyncDrop for Foo {
| ^^^^^^^^^
|
= note: see issue #126482 <https://github.com/rust-lang/rust/issues/126482> for more information
= help: add `#![feature(async_drop)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0658`.