Reject implementing const Drop for types that are not const Destruct already

This commit is contained in:
Oli Scherer
2026-04-22 17:09:33 +02:00
parent 642ee63c22
commit 7dcedafff2
9 changed files with 168 additions and 27 deletions
@@ -11,7 +11,7 @@
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::span_bug;
use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
use rustc_trait_selection::regions::InferCtxtRegionExt;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -65,6 +65,8 @@ pub(crate) fn check_drop_impl(
adt_to_impl_args,
)?;
ensure_all_fields_are_const_destruct(tcx, drop_impl_did, adt_def.did())?;
ensure_impl_predicates_are_implied_by_item_defn(
tcx,
drop_impl_did,
@@ -173,6 +175,64 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>(
Err(err.emit())
}
fn ensure_all_fields_are_const_destruct<'tcx>(
tcx: TyCtxt<'tcx>,
impl_def_id: LocalDefId,
adt_def_id: DefId,
) -> Result<(), ErrorGuaranteed> {
if !tcx.is_conditionally_const(impl_def_id) {
return Ok(());
}
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let impl_span = tcx.def_span(impl_def_id.to_def_id());
let env =
ty::EarlyBinder::bind(tcx.param_env(impl_def_id)).instantiate_identity().skip_norm_wip();
let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
let destruct_trait = tcx.lang_items().destruct_trait().unwrap();
for field in tcx.adt_def(adt_def_id).all_fields() {
let field_ty = field.ty(tcx, args);
let cause = traits::ObligationCause::new(
tcx.def_span(field.did),
impl_def_id,
ObligationCauseCode::Misc,
);
ocx.register_obligation(traits::Obligation::new(
tcx,
cause,
env,
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
trait_ref: ty::TraitRef::new(tcx, destruct_trait, [field_ty]),
constness: ty::BoundConstness::Maybe,
}),
));
}
ocx.evaluate_obligations_error_on_ambiguity()
.into_iter()
.map(|error| {
let ty::ClauseKind::HostEffect(eff) =
error.root_obligation.predicate.expect_clause().kind().no_bound_vars().unwrap()
else {
unreachable!()
};
let field_ty = eff.trait_ref.self_ty();
let diag = struct_span_code_err!(
tcx.dcx(),
error.root_obligation.cause.span,
E0367,
"`{field_ty}` does not implement `[const] Destruct`",
)
.with_span_note(impl_span, "required for this `Drop` impl");
if field_ty.has_param() {
// FIXME: suggest adding `[const] Destruct` by teaching
// `suggest_restricting_param_bound` about const traits.
}
Err(diag.emit())
})
.collect()
}
/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
/// implied by the ADT being well formed.
@@ -1,6 +1,5 @@
#![feature(const_trait_impl)]
#![feature(const_destruct)]
//@ check-pass
use std::marker::Destruct;
@@ -11,12 +10,14 @@ fn drop(&mut self) {}
}
struct ConstDrop(NotConstDrop);
//~^ ERROR: `NotConstDrop` does not implement `[const] Destruct`
impl const Drop for ConstDrop {
fn drop(&mut self) {}
}
struct ConstDrop2<T>(T);
//~^ ERROR: `T` does not implement `[const] Destruct`
impl<T> const Drop for ConstDrop2<T> {
fn drop(&mut self) {}
@@ -0,0 +1,27 @@
error[E0367]: `NotConstDrop` does not implement `[const] Destruct`
--> $DIR/drop-impl-nonconst-drop-field.rs:12:18
|
LL | struct ConstDrop(NotConstDrop);
| ^^^^^^^^^^^^
|
note: required for this `Drop` impl
--> $DIR/drop-impl-nonconst-drop-field.rs:15:1
|
LL | impl const Drop for ConstDrop {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `T` does not implement `[const] Destruct`
--> $DIR/drop-impl-nonconst-drop-field.rs:19:22
|
LL | struct ConstDrop2<T>(T);
| ^
|
note: required for this `Drop` impl
--> $DIR/drop-impl-nonconst-drop-field.rs:22:1
|
LL | impl<T> const Drop for ConstDrop2<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0367`.
@@ -1,5 +1,17 @@
error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct`
--> $DIR/const-drop-fail.rs:19:30
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^
|
note: required for this `Drop` impl
--> $DIR/const-drop-fail.rs:22:1
|
LL | impl const Drop for ConstImplWithDropGlue {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:34:5
--> $DIR/const-drop-fail.rs:35:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +20,13 @@ LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:36:5
--> $DIR/const-drop-fail.rs:37:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
@@ -1,5 +1,17 @@
error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct`
--> $DIR/const-drop-fail.rs:19:30
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^
|
note: required for this `Drop` impl
--> $DIR/const-drop-fail.rs:22:1
|
LL | impl const Drop for ConstImplWithDropGlue {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:34:5
--> $DIR/const-drop-fail.rs:35:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +20,13 @@ LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:36:5
--> $DIR/const-drop-fail.rs:37:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
@@ -1,5 +1,17 @@
error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct`
--> $DIR/const-drop-fail.rs:19:30
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^
|
note: required for this `Drop` impl
--> $DIR/const-drop-fail.rs:22:1
|
LL | impl const Drop for ConstImplWithDropGlue {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:34:5
--> $DIR/const-drop-fail.rs:35:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +20,13 @@ LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:36:5
--> $DIR/const-drop-fail.rs:37:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
@@ -1,5 +1,17 @@
error[E0367]: `NonTrivialDrop` does not implement `[const] Destruct`
--> $DIR/const-drop-fail.rs:19:30
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^
|
note: required for this `Drop` impl
--> $DIR/const-drop-fail.rs:22:1
|
LL | impl const Drop for ConstImplWithDropGlue {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:34:5
--> $DIR/const-drop-fail.rs:35:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -8,13 +20,13 @@ LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:36:5
--> $DIR/const-drop-fail.rs:37:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
@@ -23,11 +35,12 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:25:19
--> $DIR/const-drop-fail.rs:26:19
|
LL | const fn check<T: [const] Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
@@ -17,6 +17,7 @@ fn drop(&mut self) {
}
struct ConstImplWithDropGlue(NonTrivialDrop);
//~^ ERROR: `NonTrivialDrop` does not implement `[const] Destruct`
impl const Drop for ConstImplWithDropGlue {
fn drop(&mut self) {}
@@ -19,7 +19,7 @@ const trait Foo {}
impl Foo for () {}
struct Conditional<T: Foo>(T);
impl<T> const Drop for Conditional<T> where T: [const] Foo {
impl<T> const Drop for Conditional<T> where T: [const] Foo + [const] Destruct {
fn drop(&mut self) {}
}