Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 45 additions & 23 deletions compiler/rustc_mir_transform/src/elaborate_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,8 @@ where

fn build_drop(&mut self, bb: BasicBlock) {
let drop_ty = self.place_ty(self.place);
if self.tcx().features().async_drop()
&& self.elaborator.body().coroutine.is_some()
&& self.elaborator.allow_async_drops()
&& !self.elaborator.patch_ref().block(self.elaborator.body(), bb).is_cleanup
&& drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env())
if !self.elaborator.patch_ref().block(self.elaborator.body(), bb).is_cleanup
&& self.check_if_can_async_drop(drop_ty, false)
{
self.build_async_drop(
self.place,
Expand All @@ -452,6 +449,46 @@ where
}
}

/// Function to check if we can generate an async drop here
fn check_if_can_async_drop(&mut self, drop_ty: Ty<'tcx>, call_destructor_only: bool) -> bool {
let is_async_drop_feature_enabled = if self.tcx().features().async_drop() {
true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could do if self.tcx().features().staged_api() { span_bug!(some_span, "don't use async drop in libstd, it becomes insta-stable") } (and similarly at the other use of async_drop in adt_constructor

} else {
// Check if the type needing async drop comes from a dependency crate.
if let ty::Adt(adt_def, _) = drop_ty.kind() {
!adt_def.did().is_local() && adt_def.async_destructor(self.tcx()).is_some()
} else {
false
}
};

// Short-circuit before calling needs_async_drop/is_async_drop, as those
// require the `async_drop` lang item to exist (which may not be present
// in minimal/custom core environments like cranelift's mini_core).
if !is_async_drop_feature_enabled
|| !self.elaborator.body().coroutine.is_some()
|| !self.elaborator.allow_async_drops()
{
return false;
}

let needs_async_drop = if call_destructor_only {
drop_ty.is_async_drop(self.tcx(), self.elaborator.typing_env())
} else {
drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env())
};

// Async drop in libstd/libcore would become insta-stable — catch that mistake.
if needs_async_drop && self.tcx().features().staged_api() {
span_bug!(
self.source_info.span,
"don't use async drop in libstd, it becomes insta-stable"
);
}

needs_async_drop
}

/// This elaborates a single drop instruction, located at `bb`, and
/// patches over it.
///
Expand Down Expand Up @@ -1003,12 +1040,7 @@ where
) -> BasicBlock {
debug!("destructor_call_block({:?}, {:?})", self, succ);
let ty = self.place_ty(self.place);
if self.tcx().features().async_drop()
&& self.elaborator.body().coroutine.is_some()
&& self.elaborator.allow_async_drops()
&& !unwind.is_cleanup()
&& ty.is_async_drop(self.tcx(), self.elaborator.typing_env())
{
if !unwind.is_cleanup() && self.check_if_can_async_drop(ty, true) {
self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true)
} else {
self.destructor_call_block_sync((succ, unwind))
Expand Down Expand Up @@ -1078,12 +1110,7 @@ where
let loop_block = self.elaborator.patch().new_block(loop_block);

let place = tcx.mk_place_deref(ptr);
if self.tcx().features().async_drop()
&& self.elaborator.body().coroutine.is_some()
&& self.elaborator.allow_async_drops()
&& !unwind.is_cleanup()
&& ety.needs_async_drop(self.tcx(), self.elaborator.typing_env())
{
if !unwind.is_cleanup() && self.check_if_can_async_drop(ety, false) {
self.build_async_drop(
place,
ety,
Expand Down Expand Up @@ -1368,12 +1395,7 @@ where

fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let drop_ty = self.place_ty(self.place);
if self.tcx().features().async_drop()
&& self.elaborator.body().coroutine.is_some()
&& self.elaborator.allow_async_drops()
&& !unwind.is_cleanup()
&& drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env())
{
if !unwind.is_cleanup() && self.check_if_can_async_drop(drop_ty, false) {
self.build_async_drop(
self.place,
drop_ty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//@ edition: 2024
//@ run-pass
//@ compile-flags: -Z mir-opt-level=0
//@ aux-crate: async_drop_crate_dep=async-drop-crate-dep.rs

use std::{ //~ WARN found async drop types in dependency
pin::pin,
task::{Context, Waker},
};

extern crate async_drop_crate_dep;

fn main() {
let mut context = Context::from_waker(Waker::noop());
let future = pin!(async { async_drop_crate_dep::run().await });
// For some reason, putting this value into a variable is load-bearing.
let _x = future.poll(&mut context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: found async drop types in dependency `async_drop_crate_dep`, but async_drop feature is disabled for `async_drop_run_without_feature`
--> $DIR/async-drop-run-without-feature.rs:6:1
|
LL | use std::{
| ^
|
= help: if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used

warning: 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ edition: 2024
#![feature(async_drop)]
use std::future::AsyncDrop;
use std::pin::Pin;

pub async fn run() {
let _st = St;
}

struct St;

impl Drop for St {
fn drop(&mut self) {}
}

impl AsyncDrop for St {
async fn drop(self: Pin<&mut Self>) {
// Removing this line makes the program panic "normally" (not abort).
nothing().await;
}
}

async fn nothing() {}
Loading