Skip to content

Commit

Permalink
Async drop codegen (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
azhogin committed Apr 21, 2024
1 parent 5bd5d21 commit cdf91ab
Show file tree
Hide file tree
Showing 57 changed files with 1,740 additions and 143 deletions.
9 changes: 8 additions & 1 deletion compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,14 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(loc, (discr, span), flow_state);
}
TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
TerminatorKind::Drop {
place,
target: _,
unwind: _,
replace,
drop: _,
async_fut: _,
} => {
debug!(
"visit_terminator_drop \
loc: {:?} term: {:?} place: {:?} span: {:?}",
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(location, discr);
}
TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
TerminatorKind::Drop {
place: drop_place,
target: _,
unwind: _,
replace,
drop: _,
async_fut: _,
} => {
let write_kind =
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
self.access_place(
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1684,8 +1684,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
TerminatorKind::Unreachable => {}
TerminatorKind::Drop { target, unwind, .. }
| TerminatorKind::Assert { target, unwind, .. } => {
TerminatorKind::Drop { target, unwind, drop, .. } => {
self.assert_iscleanup(body, block_data, target, is_cleanup);
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
if let Some(drop) = drop {
self.assert_iscleanup(body, block_data, drop, is_cleanup);
}
}
TerminatorKind::Assert { target, unwind, .. } => {
self.assert_iscleanup(body, block_data, target, is_cleanup);
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
}
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,14 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
| TerminatorKind::CoroutineDrop => {
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
}
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
TerminatorKind::Drop {
place,
target,
unwind: _,
replace: _,
drop: _,
async_fut: _,
} => {
let drop_place = codegen_place(fx, *place);
crate::abi::codegen_drop(fx, source_info, drop_place);

Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,9 +1232,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MergingSucc::False
}

mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
}
mir::TerminatorKind::Drop {
place,
target,
unwind,
replace: _,
drop: _,
async_fut: _,
} => self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()),

mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
.codegen_assert_terminator(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind),
ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind),
ResumedAfterDrop(coroutine_kind) => ResumedAfterDrop(*coroutine_kind),
MisalignedPointerDereference { ref required, ref found } => {
MisalignedPointerDereference {
required: eval_to_int(required)?,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}

Drop { place, target, unwind, replace: _ } => {
Drop { place, target, unwind, replace: _, drop: _, async_fut: _ } => {
let frame = self.frame();
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
Expand Down Expand Up @@ -542,6 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| ty::InstanceDef::ReifyShim(..)
| ty::InstanceDef::ClosureOnceShim { .. }
| ty::InstanceDef::FnPtrShim(..)
| ty::InstanceDef::FutureDropPollShim(..)
| ty::InstanceDef::DropGlue(..)
| ty::InstanceDef::CloneShim(..)
| ty::InstanceDef::FnPtrAddrShim(..)
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
);
}
}
TerminatorKind::Drop { target, unwind, .. } => {
TerminatorKind::Drop { target, unwind, drop, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
self.check_unwind_edge(location, *unwind);
if let Some(drop) = drop {
self.check_edge(location, *drop, EdgeKind::Normal);
}
}
TerminatorKind::Call { args, destination, target, unwind, .. } => {
if let Some(target) = target {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ declare_features! (
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
/// Allows `async || body` closures.
(unstable, async_closure, "1.37.0", Some(62290)),
/// Allows implementing `AsyncDrop`.
(incomplete, async_drop, "CURRENT_RUSTC_VERSION", None),
/// Allows `#[track_caller]` on async functions.
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
/// Allows `for await` loops.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ language_item_table! {

Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::None;
AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
FutureDropPoll, sym::future_drop_poll, future_drop_poll_fn, Target::Fn, GenericRequirement::Exact(1);

CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
Expand Down Expand Up @@ -260,6 +263,7 @@ language_item_table! {

ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
DropInPlaceFuture, sym::drop_in_place_future,drop_in_place_future_fn, Target::Fn, GenericRequirement::Minimum(1);
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;

Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
middle_adjust_for_foreign_abi_error =
target architecture {$arch} does not support `extern {$abi}` ABI
middle_assert_async_resume_after_drop = `async fn` resumed after async drop
middle_assert_async_resume_after_panic = `async fn` resumed after panicking
middle_assert_async_resume_after_return = `async fn` resumed after completion
middle_assert_coroutine_resume_after_drop = coroutine resumed after async drop
middle_assert_coroutine_resume_after_panic = coroutine resumed after panicking
middle_assert_coroutine_resume_after_return = coroutine resumed after completion
middle_assert_divide_by_zero =
attempt to divide `{$val}` by zero
middle_assert_gen_resume_after_drop = `gen` fn or block cannot be further iterated on after it async dropped
middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked
middle_assert_misaligned_ptr_deref =
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ pub struct CoroutineInfo<'tcx> {
/// Coroutine drop glue.
pub coroutine_drop: Option<Body<'tcx>>,

/// Coroutine async drop glue.
pub coroutine_drop_async: Option<Body<'tcx>>,

/// The layout of a coroutine. Produced by the state transformation.
pub coroutine_layout: Option<CoroutineLayout<'tcx>>,

Expand All @@ -275,6 +278,7 @@ impl<'tcx> CoroutineInfo<'tcx> {
yield_ty: Some(yield_ty),
resume_ty: Some(resume_ty),
coroutine_drop: None,
coroutine_drop_async: None,
coroutine_layout: None,
}
}
Expand Down Expand Up @@ -578,6 +582,11 @@ impl<'tcx> Body<'tcx> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_drop.as_ref())
}

#[inline]
pub fn coroutine_drop_async(&self) -> Option<&Body<'tcx>> {
self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_drop_async.as_ref())
}

#[inline]
pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ impl<'tcx> CodegenUnit<'tcx> {
| InstanceDef::FnPtrShim(..)
| InstanceDef::Virtual(..)
| InstanceDef::ClosureOnceShim { .. }
| InstanceDef::FutureDropPollShim(..)
| InstanceDef::DropGlue(..)
| InstanceDef::CloneShim(..)
| InstanceDef::ThreadLocalShim(..)
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,13 @@ impl<'tcx> TerminatorKind<'tcx> {
Call { target: None, unwind: _, .. } => vec![],
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
Yield { drop: None, .. } => vec!["resume".into()],
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
Drop { unwind: UnwindAction::Cleanup(_), drop: Some(_), .. } => {
vec!["return".into(), "unwind".into(), "drop".into()]
}
Drop { unwind: UnwindAction::Cleanup(_), drop: None, .. } => {
vec!["return".into(), "unwind".into()]
}
Drop { unwind: _, drop: Some(_), .. } => vec!["return".into(), "drop".into()],
Drop { unwind: _, .. } => vec!["return".into()],
Assert { unwind: UnwindAction::Cleanup(_), .. } => {
vec!["success".into(), "unwind".into()]
Expand Down
31 changes: 30 additions & 1 deletion compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,35 @@ pub enum TerminatorKind<'tcx> {
/// The `replace` flag indicates whether this terminator was created as part of an assignment.
/// This should only be used for diagnostic purposes, and does not have any operational
/// meaning.
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
///
/// Async drop processing:
/// In compiler/rustc_mir_build/src/build/scope.rs we detect possible async drop:
/// drop of object implementing `AsyncDrop` trait or
/// drop of coroutine (or `Alias(Opaque(...))` of coroutine).
/// Async drop later, in StateTransform pass, may be expanded into additional yield-point
/// for poll-loop of async drop future.
/// So we need prepared 'drop' target block in the similar way as for `Yield` terminator
/// (see `drops.build_mir::<CoroutineDrop>` in scopes.rs).
/// In compiler/rustc_mir_transform/src/elaborate_drops.rs for object implementing `AsyncDrop` trait
/// we need to prepare async drop feature - resolve `AsyncDrop::drop` and codegen call.
/// `async_fut` is set to the corresponding local.
/// For coroutine drop we don't need this logic because coroutine drop works with the same
/// layout object as coroutine itself. So `async_fut` will be `None` for coroutine drop.
/// Both `drop` and `async_fut` fields are only used in compiler/rustc_mir_transform/src/coroutine.rs,
/// StateTransform pass. In `expand_async_drops` async drops are expanded
/// into one or two yield points with poll ready/pending switch.
/// When a coroutine has any internal async drop, the coroutine drop function will be async
/// (generated by `create_coroutine_drop_shim_async`, not `create_coroutine_drop_shim`).
Drop {
place: Place<'tcx>,
target: BasicBlock,
unwind: UnwindAction,
replace: bool,
/// Cleanup to be done if the coroutine is dropped at this suspend point (for async drop).
drop: Option<BasicBlock>,
/// Prepared async future local (for async drop)
async_fut: Option<Local>,
},

/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
/// the referred to function. The operand types must match the argument types of the function.
Expand Down Expand Up @@ -888,6 +916,7 @@ pub enum AssertKind<O> {
RemainderByZero(O),
ResumedAfterReturn(CoroutineKind),
ResumedAfterPanic(CoroutineKind),
ResumedAfterDrop(CoroutineKind),
MisalignedPointerDereference { required: O, found: O },
}

Expand Down
Loading

0 comments on commit cdf91ab

Please sign in to comment.