Skip to content

Commit 6f776fb

Browse files
committed
Auto merge of #123948 - azhogin:azhogin/async-drop, r=oli-obk
Async drop codegen Async drop implementation using templated coroutine for async drop glue generation. Scopes changes to generate `async_drop_in_place()` awaits, when async droppable objects are out-of-scope in async context. Implementation details: https://github.com/azhogin/posts/blob/main/async-drop-impl.md New fields in Drop terminator (drop & async_fut). Processing in codegen/miri must validate that those fields are empty (in full version async Drop terminator will be expanded at StateTransform pass or reverted to sync version). Changes in terminator visiting to consider possible new successor (drop field). ResumedAfterDrop messages for panic when coroutine is resumed after it is started to be async drop'ed. Lang item for generated coroutine for async function async_drop_in_place. `async fn async_drop_in_place<T>()::{{closure0}}`. Scopes processing for generate async drop preparations. Async drop is a hidden Yield, so potentially async drops require the same dropline preparation as for Yield terminators. Processing in StateTransform: async drops are expanded into yield-point. Generation of async drop of coroutine itself added. Shims for AsyncDropGlueCtorShim, AsyncDropGlue and FutureDropPoll. ```rust #[lang = "async_drop"] pub trait AsyncDrop { #[allow(async_fn_in_trait)] async fn drop(self: Pin<&mut Self>); } 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); } } ``` First async drop glue implementation re-worked to use the same drop elaboration code as for sync drop. `async_drop_in_place` changed to be `async fn`. So both `async_drop_in_place` ctor and produced coroutine have their lang items (`AsyncDropInPlace`/`AsyncDropInPlacePoll`) and shim instances (`AsyncDropGlueCtorShim`/`AsyncDropGlue`). ``` pub async unsafe fn async_drop_in_place<T: ?Sized>(_to_drop: *mut T) { } ``` AsyncDropGlue shim generation uses `elaborate_drops::elaborate_drop` to produce drop ladder (in the similar way as for sync drop glue) and then `coroutine::StateTransform` to convert function into coroutine poll. AsyncDropGlue coroutine's layout can't be calculated for generic T, it requires known final dropee type to be generated (in StateTransform). So, `templated coroutine` was introduced here (`templated_coroutine_layout(...)` etc). Such approach overrides the first implementation using mixing language-level futures in rust-lang/rust#121801.
2 parents 8136783 + 0bab49a commit 6f776fb

File tree

3 files changed

+104
-85
lines changed

3 files changed

+104
-85
lines changed

tests/pass/async-drop.rs

+66-49
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44

55
// WARNING: If you would ever want to modify this test,
66
// please consider modifying rustc's async drop test at
7-
// `tests/ui/async-await/async-drop.rs`.
7+
// `tests/ui/async-await/async-drop/async-drop-initial.rs`.
88

99
#![feature(async_drop, impl_trait_in_assoc_type)]
1010
#![allow(incomplete_features, dead_code)]
1111

1212
// FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests
13-
use core::future::{AsyncDrop, Future, async_drop_in_place};
13+
use core::future::{async_drop_in_place, AsyncDrop, Future};
1414
use core::hint::black_box;
1515
use core::mem::{self, ManuallyDrop};
16-
use core::pin::{Pin, pin};
16+
use core::pin::{pin, Pin};
1717
use core::task::{Context, Poll, Waker};
1818

1919
async fn test_async_drop<T>(x: T) {
@@ -68,7 +68,8 @@ fn main() {
6868
test_async_drop(SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) })
6969
.await;
7070

71-
let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19)));
71+
let mut ptr19 = mem::MaybeUninit::new(AsyncInt(19));
72+
let async_drop_fut = pin!(unsafe { async_drop_in_place(ptr19.as_mut_ptr()) });
7273
test_idempotency(async_drop_fut).await;
7374

7475
let foo = AsyncInt(20);
@@ -89,13 +90,14 @@ fn main() {
8990

9091
struct AsyncInt(i32);
9192

93+
impl Drop for AsyncInt {
94+
fn drop(&mut self) {
95+
println!("AsyncInt::drop: {}", self.0);
96+
}
97+
}
9298
impl AsyncDrop for AsyncInt {
93-
type Dropper<'a> = impl Future<Output = ()>;
94-
95-
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
96-
async move {
97-
println!("AsyncInt::Dropper::poll: {}", self.0);
98-
}
99+
async fn drop(self: Pin<&mut Self>) {
100+
println!("AsyncInt::async_drop: {}", self.0);
99101
}
100102
}
101103

@@ -124,16 +126,14 @@ struct AsyncReference<'a> {
124126
foo: &'a AsyncInt,
125127
}
126128

129+
impl Drop for AsyncReference<'_> {
130+
fn drop(&mut self) {
131+
println!("AsyncReference::drop: {}", self.foo.0);
132+
}
133+
}
127134
impl AsyncDrop for AsyncReference<'_> {
128-
type Dropper<'a>
129-
= impl Future<Output = ()>
130-
where
131-
Self: 'a;
132-
133-
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
134-
async move {
135-
println!("AsyncReference::Dropper::poll: {}", self.foo.0);
136-
}
135+
async fn drop(self: Pin<&mut Self>) {
136+
println!("AsyncReference::async_drop: {}", self.foo.0);
137137
}
138138
}
139139

@@ -145,13 +145,14 @@ struct AsyncStruct {
145145
b: AsyncInt,
146146
}
147147

148+
impl Drop for AsyncStruct {
149+
fn drop(&mut self) {
150+
println!("AsyncStruct::drop: {}", self.i);
151+
}
152+
}
148153
impl AsyncDrop for AsyncStruct {
149-
type Dropper<'a> = impl Future<Output = ()>;
150-
151-
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
152-
async move {
153-
println!("AsyncStruct::Dropper::poll: {}", self.i);
154-
}
154+
async fn drop(self: Pin<&mut Self>) {
155+
println!("AsyncStruct::async_drop: {}", self.i);
155156
}
156157
}
157158

@@ -160,23 +161,34 @@ enum AsyncEnum {
160161
B(SyncInt),
161162
}
162163

164+
impl Drop for AsyncEnum {
165+
fn drop(&mut self) {
166+
let new_self = match self {
167+
AsyncEnum::A(foo) => {
168+
println!("AsyncEnum(A)::drop: {}", foo.0);
169+
AsyncEnum::B(SyncInt(foo.0))
170+
}
171+
AsyncEnum::B(foo) => {
172+
println!("AsyncEnum(B)::drop: {}", foo.0);
173+
AsyncEnum::A(AsyncInt(foo.0))
174+
}
175+
};
176+
mem::forget(mem::replace(&mut *self, new_self));
177+
}
178+
}
163179
impl AsyncDrop for AsyncEnum {
164-
type Dropper<'a> = impl Future<Output = ()>;
165-
166-
fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> {
167-
async move {
168-
let new_self = match &*self {
169-
AsyncEnum::A(foo) => {
170-
println!("AsyncEnum(A)::Dropper::poll: {}", foo.0);
171-
AsyncEnum::B(SyncInt(foo.0))
172-
}
173-
AsyncEnum::B(foo) => {
174-
println!("AsyncEnum(B)::Dropper::poll: {}", foo.0);
175-
AsyncEnum::A(AsyncInt(foo.0))
176-
}
177-
};
178-
mem::forget(mem::replace(&mut *self, new_self));
179-
}
180+
async fn drop(mut self: Pin<&mut Self>) {
181+
let new_self = match &*self {
182+
AsyncEnum::A(foo) => {
183+
println!("AsyncEnum(A)::async_drop: {}", foo.0);
184+
AsyncEnum::B(SyncInt(foo.0))
185+
}
186+
AsyncEnum::B(foo) => {
187+
println!("AsyncEnum(B)::async_drop: {}", foo.0);
188+
AsyncEnum::A(AsyncInt(foo.0))
189+
}
190+
};
191+
mem::forget(mem::replace(&mut *self, new_self));
180192
}
181193
}
182194

@@ -186,14 +198,19 @@ union AsyncUnion {
186198
unsigned: u32,
187199
}
188200

201+
impl Drop for AsyncUnion {
202+
fn drop(&mut self) {
203+
println!(
204+
"AsyncUnion::drop: {}, {}",
205+
unsafe { self.signed },
206+
unsafe { self.unsigned },
207+
);
208+
}
209+
}
189210
impl AsyncDrop for AsyncUnion {
190-
type Dropper<'a> = impl Future<Output = ()>;
191-
192-
fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> {
193-
async move {
194-
println!("AsyncUnion::Dropper::poll: {}, {}", unsafe { self.signed }, unsafe {
195-
self.unsigned
196-
});
197-
}
211+
async fn drop(self: Pin<&mut Self>) {
212+
println!("AsyncUnion::async_drop: {}, {}", unsafe { self.signed }, unsafe {
213+
self.unsigned
214+
});
198215
}
199216
}

tests/pass/async-drop.stack.stdout

+19-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
AsyncInt::Dropper::poll: 0
2-
AsyncInt::Dropper::poll: 1
3-
AsyncInt::Dropper::poll: 2
4-
AsyncInt::Dropper::poll: 3
5-
AsyncInt::Dropper::poll: 4
6-
AsyncStruct::Dropper::poll: 6
7-
AsyncInt::Dropper::poll: 7
8-
AsyncInt::Dropper::poll: 8
9-
AsyncReference::Dropper::poll: 10
10-
AsyncInt::Dropper::poll: 11
11-
AsyncEnum(A)::Dropper::poll: 12
1+
AsyncInt::async_drop: 0
2+
AsyncInt::async_drop: 1
3+
AsyncInt::async_drop: 2
4+
AsyncInt::async_drop: 3
5+
AsyncInt::async_drop: 4
6+
AsyncStruct::async_drop: 6
7+
AsyncInt::async_drop: 7
8+
AsyncInt::async_drop: 8
9+
AsyncReference::async_drop: 10
10+
AsyncInt::async_drop: 11
11+
AsyncEnum(A)::async_drop: 12
1212
SyncInt::drop: 12
13-
AsyncEnum(B)::Dropper::poll: 13
14-
AsyncInt::Dropper::poll: 13
13+
AsyncEnum(B)::async_drop: 13
14+
AsyncInt::async_drop: 13
1515
SyncInt::drop: 14
1616
SyncThenAsync::drop: 15
17-
AsyncInt::Dropper::poll: 16
17+
AsyncInt::async_drop: 16
1818
SyncInt::drop: 17
19-
AsyncInt::Dropper::poll: 18
20-
AsyncInt::Dropper::poll: 19
21-
AsyncInt::Dropper::poll: 20
22-
AsyncUnion::Dropper::poll: 21, 21
19+
AsyncInt::async_drop: 18
20+
AsyncInt::async_drop: 19
21+
AsyncInt::async_drop: 20
22+
AsyncUnion::async_drop: 21, 21
23+
AsyncInt::async_drop: 10

tests/pass/async-drop.tree.stdout

+19-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
AsyncInt::Dropper::poll: 0
2-
AsyncInt::Dropper::poll: 1
3-
AsyncInt::Dropper::poll: 2
4-
AsyncInt::Dropper::poll: 3
5-
AsyncInt::Dropper::poll: 4
6-
AsyncStruct::Dropper::poll: 6
7-
AsyncInt::Dropper::poll: 7
8-
AsyncInt::Dropper::poll: 8
9-
AsyncReference::Dropper::poll: 10
10-
AsyncInt::Dropper::poll: 11
11-
AsyncEnum(A)::Dropper::poll: 12
1+
AsyncInt::async_drop: 0
2+
AsyncInt::async_drop: 1
3+
AsyncInt::async_drop: 2
4+
AsyncInt::async_drop: 3
5+
AsyncInt::async_drop: 4
6+
AsyncStruct::async_drop: 6
7+
AsyncInt::async_drop: 7
8+
AsyncInt::async_drop: 8
9+
AsyncReference::async_drop: 10
10+
AsyncInt::async_drop: 11
11+
AsyncEnum(A)::async_drop: 12
1212
SyncInt::drop: 12
13-
AsyncEnum(B)::Dropper::poll: 13
14-
AsyncInt::Dropper::poll: 13
13+
AsyncEnum(B)::async_drop: 13
14+
AsyncInt::async_drop: 13
1515
SyncInt::drop: 14
1616
SyncThenAsync::drop: 15
17-
AsyncInt::Dropper::poll: 16
17+
AsyncInt::async_drop: 16
1818
SyncInt::drop: 17
19-
AsyncInt::Dropper::poll: 18
20-
AsyncInt::Dropper::poll: 19
21-
AsyncInt::Dropper::poll: 20
22-
AsyncUnion::Dropper::poll: 21, 21
19+
AsyncInt::async_drop: 18
20+
AsyncInt::async_drop: 19
21+
AsyncInt::async_drop: 20
22+
AsyncUnion::async_drop: 21, 21
23+
AsyncInt::async_drop: 10

0 commit comments

Comments
 (0)