Skip to content

Commit

Permalink
Prereq4 for async drop - needs_async_drop query fixes and some cleanu…
Browse files Browse the repository at this point in the history
…p from previous async drop glue implementation
  • Loading branch information
azhogin committed Sep 7, 2024
1 parent d8c1a84 commit 2d5cad6
Show file tree
Hide file tree
Showing 29 changed files with 102 additions and 1,762 deletions.
9 changes: 5 additions & 4 deletions compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
Err(instance) => Some(instance),
}
}
InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => {
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
// it is `func returning noop future`
InstanceKind::DropGlue(_, None) => {
// empty drop glue - a nop.
let dest = target.expect("Non terminating drop_in_place_real???");
let ret_block = fx.get_block(dest);
Expand Down Expand Up @@ -675,9 +677,8 @@ pub(crate) fn codegen_drop<'tcx>(
let ty = drop_place.layout().ty;
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);

if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
drop_instance.def
{
// AsyncDropGlueCtorShim can't be here
if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def {
// we don't actually need to drop anything
} else {
match ty.kind() {
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,10 +852,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

let def = instance.map(|i| i.def);

if let Some(
ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None),
) = def
{
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
// it is `func returning noop future`
if let Some(ty::InstanceKind::DropGlue(_, None)) = def {
// Empty drop glue; a no-op.
let target = target.unwrap();
return helper.funclet_br(self, bx, target, mergeable_succ);
Expand Down
14 changes: 1 addition & 13 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,20 +179,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::Exact(0);
AsyncDestruct, sym::async_destruct, async_destruct_trait, Target::Trait, GenericRequirement::Exact(0);
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);
AsyncDropInPlacePoll, sym::async_drop_in_place_poll, async_drop_in_place_poll_fn, Target::Closure, GenericRequirement::Exact(1);
SurfaceAsyncDropInPlace, sym::surface_async_drop_in_place, surface_async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropSurfaceDropInPlace, sym::async_drop_surface_drop_in_place, async_drop_surface_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropSlice, sym::async_drop_slice, async_drop_slice_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropChain, sym::async_drop_chain, async_drop_chain_fn, Target::Fn, GenericRequirement::Exact(2);
AsyncDropNoop, sym::async_drop_noop, async_drop_noop_fn, Target::Fn, GenericRequirement::Exact(0);
AsyncDropDeferredDropInPlace, sym::async_drop_deferred_drop_in_place, async_drop_deferred_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropFuse, sym::async_drop_fuse, async_drop_fuse_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropDefer, sym::async_drop_defer, async_drop_defer_fn, Target::Fn, GenericRequirement::Exact(1);
AsyncDropEither, sym::async_drop_either, async_drop_either_fn, Target::Fn, GenericRequirement::Exact(3);

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 @@ -324,7 +313,6 @@ 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);
FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None;
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;

Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1);
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ pub(crate) fn check_legal_trait_for_method_call(
receiver: Option<Span>,
expr_span: Span,
trait_id: DefId,
body_id: DefId,
_body_id: DefId,
) -> Result<(), ErrorGuaranteed> {
if tcx.is_lang_item(trait_id, LangItem::Drop)
&& tcx.lang_items().fallback_surface_drop_fn() != Some(body_id)
{
if tcx.is_lang_item(trait_id, LangItem::Drop) {
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
errors::ExplicitDestructorCallSugg::Snippet {
lo: expr_span.shrink_to_lo(),
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,10 @@ rustc_queries! {
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value }
}
/// Query backing `Ty::is_async_drop`.
query is_async_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `AsyncDrop`", env.value }
}
/// Query backing `Ty::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value }
Expand Down Expand Up @@ -1412,6 +1416,14 @@ rustc_queries! {
cache_on_disk_if { true }
}

/// A list of types where the ADT requires async drop if and only if any of
/// those types require async drop. If the ADT is known to always need async drop
/// then `Err(AlwaysRequiresDrop)` is returned.
query adt_async_drop_tys(def_id: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
desc { |tcx| "computing when `{}` needs async drop", tcx.def_path_str(def_id) }
cache_on_disk_if { true }
}

/// A list of types where the ADT requires drop if and only if any of those types
/// has significant drop. A type marked with the attribute `rustc_insignificant_dtor`
/// is considered to not be significant. A drop is significant if it is implemented
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,6 @@ macro_rules! bidirectional_lang_item_map {

bidirectional_lang_item_map! {
// tidy-alphabetical-start
AsyncDestruct,
AsyncFn,
AsyncFnKindHelper,
AsyncFnKindUpvars,
Expand Down
126 changes: 1 addition & 125 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::iter;
use std::ops::{ControlFlow, Range};

use hir::def::{CtorKind, DefKind};
Expand All @@ -21,7 +20,7 @@ use rustc_target::spec::abi;
use rustc_type_ir::visit::TypeVisitableExt;
use rustc_type_ir::TyKind::*;
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
use ty::util::IntTypeExt;

use super::GenericParamDefKind;
use crate::infer::canonical::Canonical;
Expand Down Expand Up @@ -962,10 +961,6 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
fn discriminant_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.discriminant_ty(interner)
}

fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.async_destructor_ty(interner)
}
}

/// Type utilities
Expand Down Expand Up @@ -1477,125 +1472,6 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Returns the type of the async destructor of this type.
pub fn async_destructor_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.async_drop_glue_morphology(tcx) {
AsyncDropGlueMorphology::Noop => {
return Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop)
.instantiate_identity();
}
AsyncDropGlueMorphology::DeferredDropInPlace => {
let drop_in_place =
Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDeferredDropInPlace)
.instantiate(tcx, &[self.into()]);
return Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse)
.instantiate(tcx, &[drop_in_place.into()]);
}
AsyncDropGlueMorphology::Custom => (),
}

match *self.kind() {
ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => {
let assoc_items = tcx
.associated_item_def_ids(tcx.require_lang_item(LangItem::AsyncDestruct, None));
Ty::new_projection(tcx, assoc_items[0], [self])
}

ty::Array(elem_ty, _) | ty::Slice(elem_ty) => {
let dtor = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropSlice)
.instantiate(tcx, &[elem_ty.into()]);
Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse)
.instantiate(tcx, &[dtor.into()])
}

ty::Adt(adt_def, args) if adt_def.is_enum() || adt_def.is_struct() => self
.adt_async_destructor_ty(
tcx,
adt_def.variants().iter().map(|v| v.fields.iter().map(|f| f.ty(tcx, args))),
),
ty::Tuple(tys) => self.adt_async_destructor_ty(tcx, iter::once(tys)),
ty::Closure(_, args) => {
self.adt_async_destructor_ty(tcx, iter::once(args.as_closure().upvar_tys()))
}
ty::CoroutineClosure(_, args) => self
.adt_async_destructor_ty(tcx, iter::once(args.as_coroutine_closure().upvar_tys())),

ty::Adt(adt_def, _) => {
assert!(adt_def.is_union());

let surface_drop = self.surface_async_dropper_ty(tcx).unwrap();

Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse)
.instantiate(tcx, &[surface_drop.into()])
}

ty::Bound(..)
| ty::Foreign(_)
| ty::Placeholder(_)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`async_destructor_ty` applied to unexpected type: {self:?}")
}

_ => bug!("`async_destructor_ty` is not yet implemented for type: {self:?}"),
}
}

fn adt_async_destructor_ty<I>(self, tcx: TyCtxt<'tcx>, variants: I) -> Ty<'tcx>
where
I: Iterator + ExactSizeIterator,
I::Item: IntoIterator<Item = Ty<'tcx>>,
{
debug_assert_eq!(self.async_drop_glue_morphology(tcx), AsyncDropGlueMorphology::Custom);

let defer = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDefer);
let chain = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain);

let noop =
Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity();
let either = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropEither);

let variants_dtor = variants
.into_iter()
.map(|variant| {
variant
.into_iter()
.map(|ty| defer.instantiate(tcx, &[ty.into()]))
.reduce(|acc, next| chain.instantiate(tcx, &[acc.into(), next.into()]))
.unwrap_or(noop)
})
.reduce(|other, matched| {
either.instantiate(tcx, &[other.into(), matched.into(), self.into()])
})
.unwrap();

let dtor = if let Some(dropper_ty) = self.surface_async_dropper_ty(tcx) {
Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain)
.instantiate(tcx, &[dropper_ty.into(), variants_dtor.into()])
} else {
variants_dtor
};

Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse)
.instantiate(tcx, &[dtor.into()])
}

fn surface_async_dropper_ty(self, tcx: TyCtxt<'tcx>) -> Option<Ty<'tcx>> {
let adt_def = self.ty_adt_def()?;
let dropper = adt_def
.async_destructor(tcx)
.map(|_| LangItem::SurfaceAsyncDropInPlace)
.or_else(|| adt_def.destructor(tcx).map(|_| LangItem::AsyncDropSurfaceDropInPlace))?;
Some(Ty::async_destructor_combinator(tcx, dropper).instantiate(tcx, &[self.into()]))
}

fn async_destructor_combinator(
tcx: TyCtxt<'tcx>,
lang_item: LangItem,
) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
tcx.fn_sig(tcx.require_lang_item(lang_item, None))
.map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
}

/// Returns the type of metadata for (potentially fat) pointers to this type,
/// or the struct tail if the metadata type cannot be determined.
pub fn ptr_metadata_ty_or_tail(
Expand Down
Loading

0 comments on commit 2d5cad6

Please sign in to comment.