mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 01:05:39 +03:00
Fix multi-crate crash if dependency has enabled AsyncDrop
This commit is contained in:
@@ -133,7 +133,12 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor>
|
||||
}
|
||||
|
||||
fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
|
||||
tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl)
|
||||
let result = tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl);
|
||||
// Async drop in libstd/libcore would become insta-stable — catch that mistake.
|
||||
if result.is_some() && tcx.features().staged_api() {
|
||||
span_bug!(tcx.def_span(def_id), "don't use async drop in libstd, it becomes insta-stable");
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Given a `DefId` for an opaque type in return position, find its parent item's return
|
||||
|
||||
@@ -422,11 +422,8 @@ fn build_async_drop(
|
||||
|
||||
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,
|
||||
@@ -452,6 +449,46 @@ fn build_drop(&mut self, bb: BasicBlock) {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
} 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.
|
||||
///
|
||||
@@ -1003,12 +1040,7 @@ fn destructor_call_block(
|
||||
) -> 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))
|
||||
@@ -1078,12 +1110,7 @@ fn drop_loop(
|
||||
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,
|
||||
@@ -1368,12 +1395,7 @@ fn drop_block_simple(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBloc
|
||||
|
||||
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,
|
||||
|
||||
+18
@@ -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);
|
||||
}
|
||||
+10
@@ -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
|
||||
|
||||
+23
@@ -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() {}
|
||||
Reference in New Issue
Block a user