Skip to content

Commit ed4537b

Browse files
authored
Rollup merge of #142347 - azhogin:azhogin/async-drop-storage-live-dead-fix, r=oli-obk
Async drop - fix for StorageLive/StorageDead codegen for pinned future Fixes: #140429, Fixes: #140531, Fixes: #141761, Fixes: #141409. StorageLive/StorageDead codegen is corrected for pinned async drop future.
2 parents afe03a1 + d6a9081 commit ed4537b

10 files changed

+387
-9
lines changed

compiler/rustc_mir_transform/src/coroutine/drop.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ fn build_poll_switch<'tcx>(
132132
body: &mut Body<'tcx>,
133133
poll_enum: Ty<'tcx>,
134134
poll_unit_place: &Place<'tcx>,
135+
fut_pin_place: &Place<'tcx>,
135136
ready_block: BasicBlock,
136137
yield_block: BasicBlock,
137138
) -> BasicBlock {
@@ -162,9 +163,11 @@ fn build_poll_switch<'tcx>(
162163
Rvalue::Discriminant(*poll_unit_place),
163164
))),
164165
};
166+
let storage_dead =
167+
Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) };
165168
let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable);
166169
body.basic_blocks_mut().push(BasicBlockData {
167-
statements: [discr_assign].to_vec(),
170+
statements: [storage_dead, discr_assign].to_vec(),
168171
terminator: Some(Terminator {
169172
source_info,
170173
kind: TerminatorKind::SwitchInt {
@@ -332,10 +335,17 @@ pub(super) fn expand_async_drops<'tcx>(
332335
kind: StatementKind::Assign(Box::new((context_ref_place, arg))),
333336
});
334337
let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
335-
let switch_block =
336-
build_poll_switch(tcx, body, poll_enum, &poll_unit_place, target, yield_block);
337338
let (pin_bb, fut_pin_place) =
338339
build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue);
340+
let switch_block = build_poll_switch(
341+
tcx,
342+
body,
343+
poll_enum,
344+
&poll_unit_place,
345+
&fut_pin_place,
346+
target,
347+
yield_block,
348+
);
339349
let call_bb = build_poll_call(
340350
tcx,
341351
body,
@@ -357,16 +367,17 @@ pub(super) fn expand_async_drops<'tcx>(
357367
body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)),
358368
);
359369
let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
370+
let (pin_bb2, fut_pin_place2) =
371+
build_pin_fut(tcx, body, fut_place, UnwindAction::Continue);
360372
let drop_switch_block = build_poll_switch(
361373
tcx,
362374
body,
363375
poll_enum,
364376
&poll_unit_place,
377+
&fut_pin_place2,
365378
drop.unwrap(),
366379
drop_yield_block,
367380
);
368-
let (pin_bb2, fut_pin_place2) =
369-
build_pin_fut(tcx, body, fut_place, UnwindAction::Continue);
370381
let drop_call_bb = build_poll_call(
371382
tcx,
372383
body,

compiler/rustc_mir_transform/src/elaborate_drop.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,20 @@ where
390390
Location { block: self.succ, statement_index: 0 },
391391
StatementKind::StorageDead(fut.local),
392392
);
393+
// StorageDead(fut) in unwind block (at the begin)
394+
if let Unwind::To(block) = unwind {
395+
self.elaborator.patch().add_statement(
396+
Location { block, statement_index: 0 },
397+
StatementKind::StorageDead(fut.local),
398+
);
399+
}
400+
// StorageDead(fut) in dropline block (at the begin)
401+
if let Some(block) = dropline {
402+
self.elaborator.patch().add_statement(
403+
Location { block, statement_index: 0 },
404+
StatementKind::StorageDead(fut.local),
405+
);
406+
}
393407

394408
// #1:pin_obj_bb >>> call Pin<ObjTy>::new_unchecked(&mut obj)
395409
self.elaborator.patch().patch_terminator(
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// MIR for `a::{closure#0}` 0 coroutine_drop_async
2+
3+
fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> {
4+
debug _task_context => _19;
5+
debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T);
6+
let mut _0: std::task::Poll<()>;
7+
let _3: T;
8+
let mut _4: impl std::future::Future<Output = ()>;
9+
let mut _5: &mut T;
10+
let mut _6: std::pin::Pin<&mut T>;
11+
let mut _7: &mut T;
12+
let mut _8: *mut T;
13+
let mut _9: ();
14+
let mut _10: std::task::Poll<()>;
15+
let mut _11: &mut std::task::Context<'_>;
16+
let mut _12: &mut impl std::future::Future<Output = ()>;
17+
let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
18+
let mut _14: isize;
19+
let mut _15: &mut std::task::Context<'_>;
20+
let mut _16: &mut impl std::future::Future<Output = ()>;
21+
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
22+
let mut _18: isize;
23+
let mut _19: &mut std::task::Context<'_>;
24+
let mut _20: u32;
25+
scope 1 {
26+
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
27+
}
28+
29+
bb0: {
30+
_20 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
31+
switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14];
32+
}
33+
34+
bb1: {
35+
nop;
36+
nop;
37+
goto -> bb2;
38+
}
39+
40+
bb2: {
41+
_0 = Poll::<()>::Ready(const ());
42+
return;
43+
}
44+
45+
bb3: {
46+
_0 = Poll::<()>::Pending;
47+
discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 4;
48+
return;
49+
}
50+
51+
bb4: {
52+
StorageLive(_17);
53+
_16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
54+
_17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb7, unwind unreachable];
55+
}
56+
57+
bb5: {
58+
unreachable;
59+
}
60+
61+
bb6: {
62+
StorageDead(_17);
63+
_18 = discriminant(_10);
64+
switchInt(move _18) -> [0: bb1, 1: bb3, otherwise: bb5];
65+
}
66+
67+
bb7: {
68+
_10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb6, unwind unreachable];
69+
}
70+
71+
bb8: {
72+
_0 = Poll::<()>::Ready(const ());
73+
return;
74+
}
75+
76+
bb9: {
77+
goto -> bb11;
78+
}
79+
80+
bb10: {
81+
goto -> bb8;
82+
}
83+
84+
bb11: {
85+
drop(((*(_1.0: &mut {async fn body of a<T>()})).0: T)) -> [return: bb10, unwind unreachable];
86+
}
87+
88+
bb12: {
89+
goto -> bb4;
90+
}
91+
92+
bb13: {
93+
goto -> bb4;
94+
}
95+
96+
bb14: {
97+
_0 = Poll::<()>::Ready(const ());
98+
return;
99+
}
100+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// MIR for `a::{closure#0}` 0 coroutine_drop_async
2+
3+
fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> {
4+
debug _task_context => _19;
5+
debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T);
6+
let mut _0: std::task::Poll<()>;
7+
let _3: T;
8+
let mut _4: impl std::future::Future<Output = ()>;
9+
let mut _5: &mut T;
10+
let mut _6: std::pin::Pin<&mut T>;
11+
let mut _7: &mut T;
12+
let mut _8: *mut T;
13+
let mut _9: ();
14+
let mut _10: std::task::Poll<()>;
15+
let mut _11: &mut std::task::Context<'_>;
16+
let mut _12: &mut impl std::future::Future<Output = ()>;
17+
let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
18+
let mut _14: isize;
19+
let mut _15: &mut std::task::Context<'_>;
20+
let mut _16: &mut impl std::future::Future<Output = ()>;
21+
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
22+
let mut _18: isize;
23+
let mut _19: &mut std::task::Context<'_>;
24+
let mut _20: u32;
25+
scope 1 {
26+
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
27+
}
28+
29+
bb0: {
30+
_20 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
31+
switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19];
32+
}
33+
34+
bb1: {
35+
nop;
36+
nop;
37+
goto -> bb2;
38+
}
39+
40+
bb2: {
41+
_0 = Poll::<()>::Ready(const ());
42+
return;
43+
}
44+
45+
bb3 (cleanup): {
46+
nop;
47+
nop;
48+
goto -> bb5;
49+
}
50+
51+
bb4 (cleanup): {
52+
goto -> bb15;
53+
}
54+
55+
bb5 (cleanup): {
56+
goto -> bb4;
57+
}
58+
59+
bb6: {
60+
_0 = Poll::<()>::Pending;
61+
discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 4;
62+
return;
63+
}
64+
65+
bb7: {
66+
StorageLive(_17);
67+
_16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
68+
_17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb10, unwind: bb15];
69+
}
70+
71+
bb8: {
72+
unreachable;
73+
}
74+
75+
bb9: {
76+
StorageDead(_17);
77+
_18 = discriminant(_10);
78+
switchInt(move _18) -> [0: bb1, 1: bb6, otherwise: bb8];
79+
}
80+
81+
bb10: {
82+
_10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb9, unwind: bb3];
83+
}
84+
85+
bb11: {
86+
_0 = Poll::<()>::Ready(const ());
87+
return;
88+
}
89+
90+
bb12: {
91+
goto -> bb14;
92+
}
93+
94+
bb13: {
95+
goto -> bb11;
96+
}
97+
98+
bb14: {
99+
drop(((*(_1.0: &mut {async fn body of a<T>()})).0: T)) -> [return: bb13, unwind: bb4];
100+
}
101+
102+
bb15 (cleanup): {
103+
discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 2;
104+
resume;
105+
}
106+
107+
bb16: {
108+
goto -> bb7;
109+
}
110+
111+
bb17: {
112+
goto -> bb7;
113+
}
114+
115+
bb18: {
116+
assert(const false, "`async fn` resumed after panicking") -> [success: bb18, unwind continue];
117+
}
118+
119+
bb19: {
120+
_0 = Poll::<()>::Ready(const ());
121+
return;
122+
}
123+
}

tests/mir-opt/async_drop_live_dead.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ edition:2024
2+
// skip-filecheck
3+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
4+
5+
#![feature(async_drop)]
6+
#![allow(incomplete_features)]
7+
8+
// EMIT_MIR async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.mir
9+
async fn a<T>(x: T) {}
10+
11+
fn main() {}

tests/ui/async-await/async-drop/async-drop-initial.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn main() {
6262
test_async_drop(&j, 16).await;
6363
test_async_drop(
6464
AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 },
65-
if cfg!(panic = "unwind") { 168 } else { 136 },
65+
136,
6666
).await;
6767
test_async_drop(ManuallyDrop::new(AsyncInt(9)), 16).await;
6868

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
//@ known-bug: #140429
1+
// ex-ice: #140429
22
//@ compile-flags: -Zlint-mir --crate-type lib
33
//@ edition:2024
4+
//@ check-pass
45

56
#![feature(async_drop)]
7+
#![allow(incomplete_features)]
8+
69
async fn a<T>(x: T) {}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
//@ known-bug: #140531
2-
//@compile-flags: -Zlint-mir --crate-type lib
1+
// ex-ice: #140531
2+
//@ compile-flags: -Zlint-mir --crate-type lib
33
//@ edition:2024
4+
//@ check-pass
5+
46
#![feature(async_drop)]
7+
#![allow(incomplete_features)]
8+
59
async fn call_once(f: impl AsyncFnOnce()) {
610
let fut = Box::pin(f());
711
}

0 commit comments

Comments
 (0)