Skip to content

Commit 2e847a2

Browse files
committed
Expand async drops during drop elaboration.
1 parent c133e1c commit 2e847a2

32 files changed

Lines changed: 4773 additions & 2767 deletions

File tree

compiler/rustc_hir/src/hir.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,6 +2327,13 @@ impl CoroutineKind {
23272327
matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn))
23282328
}
23292329

2330+
pub fn is_async_desugaring(self) -> bool {
2331+
matches!(
2332+
self,
2333+
CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
2334+
)
2335+
}
2336+
23302337
pub fn to_plural_string(&self) -> String {
23312338
match self {
23322339
CoroutineKind::Desugared(d, CoroutineSource::Fn) => format!("{d:#}fn bodies"),

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,11 +624,7 @@ impl<'tcx> Operand<'tcx> {
624624
span: Span,
625625
) -> Self {
626626
let ty = Ty::new_fn_def(tcx, def_id, args);
627-
Operand::Constant(Box::new(ConstOperand {
628-
span,
629-
user_ty: None,
630-
const_: Const::Val(ConstValue::ZeroSized, ty),
631-
}))
627+
Operand::zero_sized_constant(ty, span)
632628
}
633629

634630
/// Convenience helper to make a constant that refers to the given `DefId` and args. Since this
@@ -643,6 +639,12 @@ impl<'tcx> Operand<'tcx> {
643639
Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
644640
}
645641

642+
/// Convenience helper to make a constant that refers to a zero-sized type.
643+
pub fn zero_sized_constant(ty: Ty<'tcx>, span: Span) -> Self {
644+
let const_ = Const::Val(ConstValue::ZeroSized, ty);
645+
Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
646+
}
647+
646648
pub fn is_move(&self) -> bool {
647649
matches!(self, Operand::Move(..))
648650
}

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -760,21 +760,16 @@ pub enum TerminatorKind<'tcx> {
760760
/// meaning.
761761
///
762762
/// Async drop processing:
763-
/// In compiler/rustc_mir_build/src/build/scope.rs we detect possible async drop:
764-
/// drop of object with `needs_async_drop`.
765-
/// Async drop later, in StateTransform pass, may be expanded into additional yield-point
766-
/// for poll-loop of async drop future.
767-
/// So we need prepared 'drop' target block in the similar way as for `Yield` terminator
768-
/// (see `drops.build_mir::<CoroutineDrop>` in scopes.rs).
769-
/// In compiler/rustc_mir_transform/src/elaborate_drops.rs for object implementing `AsyncDrop` trait
770-
/// we need to prepare async drop feature - resolve `AsyncDrop::drop` and codegen call.
771-
/// `async_fut` is set to the corresponding local.
772-
/// For coroutine drop we don't need this logic because coroutine drop works with the same
773-
/// layout object as coroutine itself. So `async_fut` will be `None` for coroutine drop.
774-
/// Both `drop` and `async_fut` fields are only used in compiler/rustc_mir_transform/src/coroutine.rs,
775-
/// StateTransform pass. In `expand_async_drops` async drops are expanded
776-
/// into one or two yield points with poll ready/pending switch.
777-
/// When a coroutine has any internal async drop, the coroutine drop function will be async
763+
/// MIR building detects possible async drops, and constructs a complete CFG. To correctly
764+
/// handle the coroutine being dropped while itself drops, we need a 'drop' target
765+
/// similar to `Yield` terminator (see `drops.build_mir::<CoroutineDrop>`).
766+
///
767+
/// Drop elaboration later refines the set of useful async drops. If there is no need for an
768+
/// async drop, it is downgraded to a sync drop by setting `drop` to `None` If this is an
769+
/// actual async drop, it is expanded to an `await` loop over the `async_drop_in_place` or
770+
/// `AsyncDrop::drop` coroutine.
771+
///
772+
/// When a coroutine has any internal async drop, the coroutine drop function will be async
778773
/// (generated by `create_coroutine_drop_shim_async`, not `create_coroutine_drop_shim`).
779774
Drop {
780775
place: Place<'tcx>,

compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ use std::ops;
5656

5757
pub(super) use by_move_body::coroutine_by_move_body_def_id;
5858
use drop::{
59-
cleanup_async_drops, create_coroutine_drop_shim, create_coroutine_drop_shim_async,
60-
create_coroutine_drop_shim_proxy_async, elaborate_coroutine_drops, expand_async_drops,
61-
has_expandable_async_drops, insert_clean_drop,
59+
create_coroutine_drop_shim, create_coroutine_drop_shim_async,
60+
create_coroutine_drop_shim_proxy_async, elaborate_coroutine_drops, has_async_drops,
61+
insert_clean_drop,
6262
};
6363
use itertools::izip;
6464
use rustc_abi::{FieldIdx, VariantIdx};
@@ -70,7 +70,6 @@ use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet};
7070
use rustc_index::{Idx, IndexVec, indexvec};
7171
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
7272
use rustc_middle::mir::*;
73-
use rustc_middle::ty::util::Discr;
7473
use rustc_middle::ty::{
7574
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
7675
};
@@ -82,8 +81,8 @@ use rustc_mir_dataflow::impls::{
8281
use rustc_mir_dataflow::{
8382
Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results,
8483
};
84+
use rustc_span::Span;
8585
use rustc_span::def_id::{DefId, LocalDefId};
86-
use rustc_span::{DUMMY_SP, Span, dummy_spanned};
8786
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
8887
use rustc_trait_selection::infer::TyCtxtInferExt as _;
8988
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
@@ -169,7 +168,7 @@ fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtx
169168
}
170169

171170
const SELF_ARG: Local = Local::arg(0);
172-
const CTX_ARG: Local = Local::arg(1);
171+
pub(crate) const CTX_ARG: Local = Local::arg(1);
173172

174173
/// A `yield` point in the coroutine.
175174
struct SuspensionPoint<'tcx> {
@@ -585,7 +584,7 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
585584
/// still using the `ResumeTy` indirection for the time being, and that indirection
586585
/// is removed here. After this transform, the coroutine body only knows about `&mut Context<'_>`.
587586
#[tracing::instrument(level = "trace", skip(tcx, body), ret)]
588-
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty<'tcx> {
587+
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
589588
let context_mut_ref = Ty::new_task_context(tcx);
590589

591590
// replace the type of the `resume` argument
@@ -615,7 +614,6 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty
615614
_ => {}
616615
}
617616
}
618-
context_mut_ref
619617
}
620618

621619
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
@@ -1522,24 +1520,12 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15221520
// (finally in open_drop_for_tuple) before async drop expansion.
15231521
// Async drops, produced by this drop elaboration, will be expanded,
15241522
// and corresponding futures kept in layout.
1525-
let has_async_drops = matches!(
1526-
coroutine_kind,
1527-
CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
1528-
) && has_expandable_async_drops(tcx, body, coroutine_ty);
1523+
let coroutine_is_async = coroutine_kind.is_async_desugaring();
1524+
let has_async_drops = has_async_drops(body);
15291525

15301526
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1531-
if matches!(
1532-
coroutine_kind,
1533-
CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
1534-
) {
1535-
let context_mut_ref = transform_async_context(tcx, body);
1536-
expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty);
1537-
1538-
if let Some(dumper) = MirDumper::new(tcx, "coroutine_async_drop_expand", body) {
1539-
dumper.dump_mir(body);
1540-
}
1541-
} else {
1542-
cleanup_async_drops(body);
1527+
if coroutine_is_async {
1528+
transform_async_context(tcx, body);
15431529
}
15441530

15451531
let always_live_locals = always_storage_live_locals(body);

0 commit comments

Comments
 (0)