Make async drop code more consistent with regular drop code

Fixes #126573
This commit is contained in:
Daria Sukhonina 2024-06-17 17:00:45 +03:00
parent f873ae029e
commit af10880f6b
4 changed files with 67 additions and 14 deletions

View File

@ -371,7 +371,7 @@ fn exported_symbols_provider_local(
}) => { }) => {
// A little sanity-check // A little sanity-check
debug_assert_eq!( debug_assert_eq!(
args.non_erasable_generics(tcx, def_id).skip(1).next(), args.non_erasable_generics(tcx, def_id).next(),
Some(GenericArgKind::Type(ty)) Some(GenericArgKind::Type(ty))
); );
symbols.push(( symbols.push((
@ -422,10 +422,7 @@ fn upstream_monomorphizations_provider(
} }
ExportedSymbol::AsyncDropGlueCtorShim(ty) => { ExportedSymbol::AsyncDropGlueCtorShim(ty) => {
if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id { if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id {
( (async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
async_drop_in_place_fn_def_id,
tcx.mk_args(&[tcx.lifetimes.re_erased.into(), ty.into()]),
)
} else { } else {
// `drop_in_place` in place does not exist, don't try // `drop_in_place` in place does not exist, don't try
// to use it. // to use it.
@ -480,6 +477,17 @@ fn upstream_drop_glue_for_provider<'tcx>(
} }
} }
fn upstream_async_drop_glue_for_provider<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
) -> Option<CrateNum> {
if let Some(def_id) = tcx.lang_items().async_drop_in_place_fn() {
tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned())
} else {
None
}
}
fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
!tcx.reachable_set(()).contains(&def_id) !tcx.reachable_set(()).contains(&def_id)
} }
@ -491,6 +499,7 @@ pub fn provide(providers: &mut Providers) {
providers.upstream_monomorphizations = upstream_monomorphizations_provider; providers.upstream_monomorphizations = upstream_monomorphizations_provider;
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;
providers.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider;
providers.wasm_import_module_map = wasm_import_module_map; providers.wasm_import_module_map = wasm_import_module_map;
providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.extern_queries.upstream_monomorphizations_for = providers.extern_queries.upstream_monomorphizations_for =

View File

@ -1554,12 +1554,13 @@
} }
} }
/// The entire set of monomorphizations the local crate can safely link /// The entire set of monomorphizations the local crate can safely
/// to because they are exported from upstream crates. Do not depend on /// link to because they are exported from upstream crates. Do
/// this directly, as its value changes anytime a monomorphization gets /// not depend on this directly, as its value changes anytime
/// added or removed in any upstream crate. Instead use the narrower /// a monomorphization gets added or removed in any upstream
/// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even /// crate. Instead use the narrower `upstream_monomorphizations_for`,
/// better, `Instance::upstream_monomorphization()`. /// `upstream_drop_glue_for`, `upstream_async_drop_glue_for`, or,
/// even better, `Instance::upstream_monomorphization()`.
query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> { query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> {
arena_cache arena_cache
desc { "collecting available upstream monomorphizations" } desc { "collecting available upstream monomorphizations" }
@ -1601,6 +1602,26 @@
desc { "available upstream drop-glue for `{:?}`", args } desc { "available upstream drop-glue for `{:?}`", args }
} }
/// Returns the upstream crate that exports async-drop-glue for
/// the given type (`args` is expected to be a single-item list
/// containing the type one wants async-drop-glue for).
///
/// This is a subset of `upstream_monomorphizations_for` in order
/// to increase dep-tracking granularity. Otherwise adding or
/// removing any type with async-drop-glue in any upstream crate
/// would invalidate all functions calling async-drop-glue of an
/// upstream type.
///
/// You likely want to call `Instance::upstream_monomorphization()`
/// instead of invoking this query directly.
///
/// NOTE: This query could easily be extended to also support other
/// common functions that have are large set of monomorphizations
/// (like `Clone::clone` for example).
query upstream_async_drop_glue_for(args: GenericArgsRef<'tcx>) -> Option<CrateNum> {
desc { "available upstream async-drop-glue for `{:?}`", args }
}
/// Returns a list of all `extern` blocks of a crate. /// Returns a list of all `extern` blocks of a crate.
query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> { query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> {
arena_cache arena_cache

View File

@ -219,8 +219,9 @@ pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
InstanceKind::Item(def) => tcx InstanceKind::Item(def) => tcx
.upstream_monomorphizations_for(def) .upstream_monomorphizations_for(def)
.and_then(|monos| monos.get(&self.args).cloned()), .and_then(|monos| monos.get(&self.args).cloned()),
InstanceKind::DropGlue(_, Some(_)) | InstanceKind::AsyncDropGlueCtorShim(_, _) => { InstanceKind::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args),
tcx.upstream_drop_glue_for(self.args) InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => {
tcx.upstream_async_drop_glue_for(self.args)
} }
_ => None, _ => None,
} }
@ -256,7 +257,7 @@ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
match self { match self {
ty::InstanceKind::Item(def) => Some(def), ty::InstanceKind::Item(def) => Some(def),
ty::InstanceKind::DropGlue(def_id, Some(_)) ty::InstanceKind::DropGlue(def_id, Some(_))
| InstanceKind::AsyncDropGlueCtorShim(def_id, _) | InstanceKind::AsyncDropGlueCtorShim(def_id, Some(_))
| InstanceKind::ThreadLocalShim(def_id) => Some(def_id), | InstanceKind::ThreadLocalShim(def_id) => Some(def_id),
InstanceKind::VTableShim(..) InstanceKind::VTableShim(..)
| InstanceKind::ReifyShim(..) | InstanceKind::ReifyShim(..)
@ -267,6 +268,7 @@ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
| ty::InstanceKind::ConstructCoroutineInClosureShim { .. } | ty::InstanceKind::ConstructCoroutineInClosureShim { .. }
| ty::InstanceKind::CoroutineKindShim { .. } | ty::InstanceKind::CoroutineKindShim { .. }
| InstanceKind::DropGlue(..) | InstanceKind::DropGlue(..)
| InstanceKind::AsyncDropGlueCtorShim(..)
| InstanceKind::CloneShim(..) | InstanceKind::CloneShim(..)
| InstanceKind::FnPtrAddrShim(..) => None, | InstanceKind::FnPtrAddrShim(..) => None,
} }
@ -332,6 +334,26 @@ pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool {
.map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did)) .map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did))
}); });
} }
if let ty::InstanceKind::AsyncDropGlueCtorShim(.., Some(ty)) = *self {
// Async drop glue generally wants to be instantiated at
// every codegen unit, but without an #[inline] hint. We
// should make this available to normal end-users.
if tcx.sess.opts.incremental.is_none() {
return true;
}
// When compiling with incremental, we can generate a *lot* of
// codegen units. Including drop glue into all of them has a
// considerable compile time cost.
//
// We include enums without destructors to allow, say, optimizing
// drops of `Option::None` before LTO. We also respect the intent of
// `#[inline]` on `Drop::drop` implementations.
return ty.ty_adt_def().map_or(true, |adt_def| {
adt_def
.async_destructor(tcx)
.map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.ctor))
});
}
if let ty::InstanceKind::ThreadLocalShim(..) = *self { if let ty::InstanceKind::ThreadLocalShim(..) = *self {
return false; return false;
} }

View File

@ -288,6 +288,7 @@ pub fn transform_instance<'tcx>(
mut instance: Instance<'tcx>, mut instance: Instance<'tcx>,
options: TransformTyOptions, options: TransformTyOptions,
) -> Instance<'tcx> { ) -> Instance<'tcx> {
// FIXME: account for async-drop-glue
if (matches!(instance.def, ty::InstanceKind::Virtual(..)) if (matches!(instance.def, ty::InstanceKind::Virtual(..))
&& tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace)) && tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace))
|| matches!(instance.def, ty::InstanceKind::DropGlue(..)) || matches!(instance.def, ty::InstanceKind::DropGlue(..))