From 33a1ed1f4b0e8d0f15eedae6d73fc1e081b3486f Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 20 Apr 2026 04:26:10 +0200 Subject: [PATCH] disallow non_exhaustive structs and enums with non_exhaustive variants from implementing `ConstParamTy` --- .../rustc_hir_analysis/src/check/wfcheck.rs | 1 + .../src/coherence/builtin.rs | 6 ++++ compiler/rustc_hir_analysis/src/errors.rs | 10 +++++++ .../rustc_trait_selection/src/traits/misc.rs | 17 ++++++++++- ...d-non_exhaustive-const-param-ty.min.stderr | 23 ++++++++++++++ .../forbid-non_exhaustive-const-param-ty.rs | 30 +++++++++++++++++++ 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.min.stderr create mode 100644 tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.rs diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 07ad2a79dc7ad..4a559e7fdd839 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -911,6 +911,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er // Can never implement `ConstParamTy`, don't suggest anything. Err( ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed + | ConstParamTyImplementationError::NonExhaustive(..) | ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..), ) => None, Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => { diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d1ce29b703eea..f23656c609e5e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -221,6 +221,12 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) } + Err(ConstParamTyImplementationError::NonExhaustive(attr_span)) => { + let defn_span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; + Err(tcx + .dcx() + .emit_err(errors::ConstParamTyImplOnNonExhaustive { defn_span, attr_span })) + } Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(infringing_fields_error( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f353ace0b3886..1bb54f27dcbdd 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -317,6 +317,16 @@ pub(crate) struct ConstParamTyImplOnNonAdt { pub span: Span, } +#[derive(Diagnostic)] +#[diag("the trait `ConstParamTy` may not be implemented for this type")] +pub(crate) struct ConstParamTyImplOnNonExhaustive { + #[primary_span] + #[label("non exhaustive const params are forbidden")] + pub defn_span: Span, + #[label("caused by this attribute")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag("the trait `ConstParamTy` may not be implemented for this struct")] pub(crate) struct ConstParamTyFieldVisMismatch { diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index bd0068c19886f..7a0062c503685 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -4,8 +4,9 @@ use hir::LangItem; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_middle::bug; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized}; -use rustc_span::sym; +use rustc_span::{Span, sym}; use crate::regions::InferCtxtRegionExt; use crate::traits::{self, FulfillmentError, Obligation, ObligationCause}; @@ -22,6 +23,7 @@ pub enum ConstParamTyImplementationError<'tcx> { InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>), InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdtOrBuiltinAllowed, + NonExhaustive(Span), } pub enum InfringingFieldsReason<'tcx> { @@ -124,6 +126,19 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( ty::Tuple(inner_tys) => inner_tys.into_iter().collect(), ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => { + if !tcx.features().adt_const_params() { + for variant in adt.variants() { + if variant.is_field_list_non_exhaustive() { + let attr_span = match hir::find_attr!(tcx, variant.def_id, hir::attrs::AttributeKind::NonExhaustive(span) => *span) + { + Some(sp) => sp, + None => bug!("non_exhaustive variant missing NonExhaustive attribute"), + }; + return Err(ConstParamTyImplementationError::NonExhaustive(attr_span)); + } + } + } + all_fields_implement_trait( tcx, param_env, diff --git a/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.min.stderr b/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.min.stderr new file mode 100644 index 0000000000000..196c3397742fe --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.min.stderr @@ -0,0 +1,23 @@ +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/forbid-non_exhaustive-const-param-ty.rs:13:12 + | +LL | #[non_exhaustive] + | ----------------- caused by this attribute +LL | #[derive(PartialEq, Eq, ConstParamTy)] + | ------------ in this derive macro expansion +LL | pub struct Miow; + | ^^^^ non exhaustive const params are forbidden + +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/forbid-non_exhaustive-const-param-ty.rs:17:10 + | +LL | #[derive(PartialEq, Eq, ConstParamTy)] + | ------------ in this derive macro expansion +LL | pub enum Enumiow { + | ^^^^^^^ non exhaustive const params are forbidden +LL | +LL | #[non_exhaustive] NonExhaustiveThingie, + | ----------------- caused by this attribute + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.rs b/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.rs new file mode 100644 index 0000000000000..978f6951b12e7 --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/forbid-non_exhaustive-const-param-ty.rs @@ -0,0 +1,30 @@ +//! Ensure that non exhaustive structs and enums with non exhaustive variants +//! aren't allowed to implement ConstParamTy under min_adt_const_params feature +//@ revisions: full min +//@[full] check-pass +#![cfg_attr(min, feature(min_adt_const_params))] +#![cfg_attr(full, feature(adt_const_params))] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[non_exhaustive] +#[derive(PartialEq, Eq, ConstParamTy)] +pub struct Miow; + //[min]~^ ERROR: the trait `ConstParamTy` may not be implemented for this type + +#[derive(PartialEq, Eq, ConstParamTy)] +pub enum Enumiow { + //[min]~^ ERROR: the trait `ConstParamTy` may not be implemented for this type + #[non_exhaustive] NonExhaustiveThingie, + ExhaustiveThingie, +} + +#[non_exhaustive] +#[derive(PartialEq, Eq, ConstParamTy)] +pub enum EnumiowButFine { + ExhaustiveThingie, + AlsoExhaustiveThingie, +} + +fn main() {}