Skip to content

Commit 1a1e29a

Browse files
committed
feat: create an MVP for using Destruct for custom dtors
1 parent a3e96d8 commit 1a1e29a

11 files changed

Lines changed: 148 additions & 61 deletions

File tree

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ fn upstream_monomorphizations_provider(
403403

404404
let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
405405

406-
let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
406+
let drop_in_place_fn_def_id = tcx.lang_items().destruct_drop_in_place();
407407
let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn();
408408

409409
for &cnum in cnums.iter() {
@@ -465,7 +465,7 @@ fn upstream_drop_glue_for_provider<'tcx>(
465465
tcx: TyCtxt<'tcx>,
466466
args: GenericArgsRef<'tcx>,
467467
) -> Option<CrateNum> {
468-
let def_id = tcx.lang_items().drop_in_place_fn()?;
468+
let def_id = tcx.lang_items().destruct_drop_in_place()?;
469469
tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned()
470470
}
471471

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ language_item_table! {
183183

184184
Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
185185
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
186+
DestructDropInPlace, sym::destruct_drop_in_place, destruct_drop_in_place, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
186187
AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::None;
187188
AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
188189

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub enum InstanceKind<'tcx> {
147147
/// Proxy shim for async drop of future (def_id, proxy_cor_ty, impl_cor_ty)
148148
FutureDropPollShim(DefId, Ty<'tcx>, Ty<'tcx>),
149149

150-
/// `core::ptr::drop_in_place::<T>`.
150+
/// `Destruct::drop_in_place()`
151151
///
152152
/// The `DefId` is for `core::ptr::drop_in_place`.
153153
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
@@ -717,7 +717,7 @@ impl<'tcx> Instance<'tcx> {
717717
}
718718

719719
pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
720-
let def_id = tcx.require_lang_item(LangItem::DropInPlace, DUMMY_SP);
720+
let def_id = tcx.require_lang_item(LangItem::DestructDropInPlace, DUMMY_SP);
721721
let args = tcx.mk_args(&[ty.into()]);
722722
Instance::expect_resolve(
723723
tcx,
@@ -728,6 +728,16 @@ impl<'tcx> Instance<'tcx> {
728728
)
729729
}
730730

731+
pub fn try_resolve_drop_in_place(
732+
tcx: TyCtxt<'tcx>,
733+
typing_env: ty::TypingEnv<'tcx>,
734+
ty: Ty<'tcx>,
735+
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
736+
let def_id = tcx.require_lang_item(LangItem::DestructDropInPlace, DUMMY_SP);
737+
let args = tcx.mk_args(&[ty.into()]);
738+
Instance::try_resolve(tcx, typing_env, def_id, args)
739+
}
740+
731741
pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
732742
let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, DUMMY_SP);
733743
let args = tcx.mk_args(&[ty.into()]);

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,9 @@ fn visit_instance_use<'tcx>(
10451045
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
10461046
/// can just link to the upstream crate and therefore don't need a mono item.
10471047
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
1048+
if let ty::InstanceKind::DropGlue(_, Some(_)) = instance.def {
1049+
return instance.upstream_monomorphization(tcx).is_none();
1050+
}
10481051
let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
10491052
return true;
10501053
};

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -454,34 +454,47 @@ where
454454

455455
match assemble_from {
456456
AssembleCandidatesFrom::All => {
457-
self.assemble_builtin_impl_candidates(goal, &mut candidates);
458-
// For performance we only assemble impls if there are no candidates
459-
// which would shadow them. This is necessary to avoid hangs in rayon,
460-
// see trait-system-refactor-initiative#109 for more details.
461-
//
462-
// We always assemble builtin impls as trivial builtin impls have a higher
463-
// priority than where-clauses.
464-
//
465-
// We only do this if any such candidate applies without any constraints
466-
// as we may want to weaken inference guidance in the future and don't want
467-
// to worry about causing major performance regressions when doing so.
468-
// See trait-system-refactor-initiative#226 for some ideas here.
469-
let assemble_impls = match self.typing_mode() {
470-
TypingMode::Coherence => true,
471-
TypingMode::Analysis { .. }
472-
| TypingMode::Borrowck { .. }
473-
| TypingMode::PostBorrowckAnalysis { .. }
474-
| TypingMode::PostAnalysis => !candidates.iter().any(|c| {
475-
matches!(
476-
c.source,
477-
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
478-
| CandidateSource::AliasBound(_)
479-
) && has_no_inference_or_external_constraints(c.result)
480-
}),
481-
};
482-
if assemble_impls {
457+
let trait_def_id = goal.predicate.trait_def_id(self.cx());
458+
// Check if there are any user defined impls for Destruct. If there are,
459+
// use those, and fallback to builtin drop glue impl if none are present
460+
if self.cx().is_trait_lang_item(trait_def_id, SolverTraitLangItem::Destruct) {
483461
self.assemble_impl_candidates(goal, &mut candidates);
462+
let has_impl_candidate =
463+
candidates.iter().any(|c| matches!(c.source, CandidateSource::Impl(_)));
464+
if !has_impl_candidate {
465+
self.assemble_builtin_impl_candidates(goal, &mut candidates);
466+
}
484467
self.assemble_object_bound_candidates(goal, &mut candidates);
468+
} else {
469+
self.assemble_builtin_impl_candidates(goal, &mut candidates);
470+
// For performance we only assemble impls if there are no candidates
471+
// which would shadow them. This is necessary to avoid hangs in rayon,
472+
// see trait-system-refactor-initiative#109 for more details.
473+
//
474+
// We always assemble builtin impls as trivial builtin impls have a higher
475+
// priority than where-clauses.
476+
//
477+
// We only do this if any such candidate applies without any constraints
478+
// as we may want to weaken inference guidance in the future and don't want
479+
// to worry about causing major performance regressions when doing so.
480+
// See trait-system-refactor-initiative#226 for some ideas here.
481+
let assemble_impls = match self.typing_mode() {
482+
TypingMode::Coherence => true,
483+
TypingMode::Analysis { .. }
484+
| TypingMode::Borrowck { .. }
485+
| TypingMode::PostBorrowckAnalysis { .. }
486+
| TypingMode::PostAnalysis => !candidates.iter().any(|c| {
487+
matches!(
488+
c.source,
489+
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
490+
| CandidateSource::AliasBound(_)
491+
) && has_no_inference_or_external_constraints(c.result)
492+
}),
493+
};
494+
if assemble_impls {
495+
self.assemble_impl_candidates(goal, &mut candidates);
496+
self.assemble_object_bound_candidates(goal, &mut candidates);
497+
}
485498
}
486499
}
487500
AssembleCandidatesFrom::EnvAndBounds => {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ symbols! {
798798
derive_from,
799799
derive_smart_pointer,
800800
destruct,
801+
destruct_drop_in_place,
801802
destructuring_assignment,
802803
diagnostic,
803804
diagnostic_namespace,

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
113113
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
114114
}
115115
Some(LangItem::Destruct) => {
116-
self.assemble_const_destruct_candidates(obligation, &mut candidates);
116+
let before = candidates.vec.len();
117+
self.assemble_candidates_from_impls(obligation, &mut candidates);
118+
let added_impl =
119+
candidates.vec[before..].iter().any(|c| matches!(c, ImplCandidate(_)));
120+
if !added_impl {
121+
self.assemble_const_destruct_candidates(obligation, &mut candidates);
122+
}
117123
}
118124
Some(LangItem::TransmuteTrait) => {
119125
// User-defined transmutability impls are permitted.

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,7 @@ fn resolve_instance_raw<'tcx>(
3838
} else if tcx.is_lang_item(def_id, LangItem::DropInPlace) {
3939
let ty = args.type_at(0);
4040

41-
if ty.needs_drop(tcx, typing_env) {
42-
debug!(" => nontrivial drop glue");
43-
match *ty.kind() {
44-
ty::Coroutine(coroutine_def_id, ..) => {
45-
// FIXME: sync drop of coroutine with async drop (generate both versions?)
46-
// Currently just ignored
47-
if tcx.optimized_mir(coroutine_def_id).coroutine_drop_async().is_some() {
48-
ty::InstanceKind::DropGlue(def_id, None)
49-
} else {
50-
ty::InstanceKind::DropGlue(def_id, Some(ty))
51-
}
52-
}
53-
ty::Closure(..)
54-
| ty::CoroutineClosure(..)
55-
| ty::Tuple(..)
56-
| ty::Adt(..)
57-
| ty::Dynamic(..)
58-
| ty::Array(..)
59-
| ty::Slice(..)
60-
| ty::UnsafeBinder(..) => ty::InstanceKind::DropGlue(def_id, Some(ty)),
61-
// Drop shims can only be built from ADTs.
62-
_ => return Ok(None),
63-
}
64-
} else {
65-
debug!(" => trivial drop glue");
66-
ty::InstanceKind::DropGlue(def_id, None)
67-
}
41+
return ty::Instance::try_resolve_drop_in_place(tcx, typing_env, ty);
6842
} else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) {
6943
let ty = args.type_at(0);
7044

@@ -166,6 +140,20 @@ fn resolve_associated_item<'tcx>(
166140
if !eligible {
167141
return Ok(None);
168142
}
143+
if tcx.is_lang_item(trait_ref.def_id, LangItem::Destruct) {
144+
if !tcx.is_lang_item(trait_item_id, LangItem::DestructDropInPlace) {
145+
bug!(
146+
"unexpected associated item for built-in `{trait_ref}`: {}",
147+
tcx.item_name(trait_item_id)
148+
);
149+
}
150+
151+
debug!("Got user Destruct impl");
152+
return Ok(Some(Instance {
153+
def: ty::InstanceKind::Item(leaf_def.item.def_id),
154+
args: rcvr_args,
155+
}));
156+
}
169157

170158
let typing_env = typing_env.with_post_analysis_normalized(tcx);
171159
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
@@ -403,6 +391,46 @@ fn resolve_associated_item<'tcx>(
403391
} else {
404392
bug!("unexpected associated associated item")
405393
}
394+
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::Destruct) {
395+
debug!(
396+
"resolving Destruct for ImplSource::Builtin: {:?}, {:?}, {:?}",
397+
typing_env, trait_item_id, rcvr_args
398+
);
399+
if !tcx.is_lang_item(trait_item_id, LangItem::DestructDropInPlace) {
400+
bug!(
401+
"unexpected associated item for built-in `{trait_ref}`: {}",
402+
tcx.item_name(trait_item_id)
403+
);
404+
}
405+
406+
let self_ty = trait_ref.self_ty();
407+
408+
let def = if self_ty.needs_drop(tcx, typing_env) {
409+
match *self_ty.kind() {
410+
ty::Coroutine(coroutine_def_id, ..) => {
411+
if tcx.optimized_mir(coroutine_def_id).coroutine_drop_async().is_some()
412+
{
413+
ty::InstanceKind::DropGlue(trait_item_id, None)
414+
} else {
415+
ty::InstanceKind::DropGlue(trait_item_id, Some(self_ty))
416+
}
417+
}
418+
ty::Closure(..)
419+
| ty::CoroutineClosure(..)
420+
| ty::Tuple(..)
421+
| ty::Adt(..)
422+
| ty::Dynamic(..)
423+
| ty::Array(..)
424+
| ty::Slice(..)
425+
| ty::UnsafeBinder(..) => {
426+
ty::InstanceKind::DropGlue(trait_item_id, Some(self_ty))
427+
}
428+
_ => return Ok(None),
429+
}
430+
} else {
431+
ty::InstanceKind::DropGlue(trait_item_id, None)
432+
};
433+
Some(ty::Instance { def, args: rcvr_args })
406434
} else {
407435
Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
408436
}

library/core/src/marker.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,10 +1056,15 @@ marker_impls! {
10561056
#[unstable(feature = "const_destruct", issue = "133214")]
10571057
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
10581058
#[lang = "destruct"]
1059-
#[diagnostic::on_unimplemented(message = "can't drop `{Self}`")]
1060-
#[rustc_deny_explicit_impl]
1059+
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
10611060
#[rustc_dyn_incompatible_trait]
1062-
pub const trait Destruct: PointeeSized {}
1061+
pub const trait Destruct: PointeeSized {
1062+
/// Entrypoint for drop
1063+
///
1064+
/// Generated by default if not implemented manually.
1065+
#[lang = "destruct_drop_in_place"]
1066+
unsafe fn drop_in_place(_to_drop: *mut Self);
1067+
}
10631068

10641069
/// A marker for tuple types.
10651070
///
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ run-pass
2+
//@ check-stdout
3+
//@ check-run-results
4+
5+
#![feature(const_destruct)]
6+
use std::marker::Destruct;
7+
struct A {
8+
_a: String,
9+
}
10+
11+
impl Destruct for A {
12+
unsafe fn drop_in_place(_to_drop: *mut Self) {
13+
println!("Hey i was dropped");
14+
}
15+
}
16+
17+
fn main() {
18+
let _a = A { _a: String::new() };
19+
}

0 commit comments

Comments
 (0)