From 6ce0885434861dc0ee9c9a503134370ee9cf0c0c Mon Sep 17 00:00:00 2001 From: YUZHEthefool <2804776511@qq.com> Date: Mon, 24 Aug 2026 08:44:21 +0000 Subject: [PATCH] Check associated const binding types --- .../rustc_hir_analysis/src/check/check.rs | 26 +++++++++--- compiler/rustc_middle/src/traits/mod.rs | 4 ++ .../traits/fulfillment_errors.rs | 25 ++++++++---- .../src/error_reporting/traits/suggestions.rs | 1 + .../rustc_trait_selection/src/traits/wf.rs | 40 ++++++++++++++++++- .../associated-type-bound-issue-161100.rs | 15 +++++++ .../associated-type-bound-issue-161100.stderr | 9 +++++ ...t-item-associated-equality-issue-161100.rs | 16 ++++++++ ...em-associated-equality-issue-161100.stderr | 15 +++++++ .../fn-ptr-const-param-issue-161100.rs | 13 ++++++ .../fn-ptr-const-param-issue-161100.stderr | 9 +++++ ...-associated-const-equality-issue-161100.rs | 20 ++++++++++ ...ociated-const-equality-issue-161100.stderr | 15 +++++++ .../where-clause-issue-161100.rs | 13 ++++++ .../where-clause-issue-161100.stderr | 9 +++++ 15 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 05328f107fbc8..44c6a2e688d8d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -987,20 +987,36 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), // HACK: We sometimes incidentally check that const arguments have the correct // type as a side effect of the anon const desugaring. To make this "consistent" // for users we explicitly check `ConstArgHasType` clauses so that const args - // that don't go through an anon const still have their types checked. + // that don't go through an anon const still have their types checked. We also + // check that the types of const items used in the type system implement + // `ConstParamTy`, while continuing to ignore ordinary nominal bounds. // // We use the unnormalized type as this mirrors the behaviour that we previously // would have had when all const arguments were anon consts. // // Changing this to normalized obligations is a breaking change: // `type Bar = [(); panic!()];` would become an error - if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty.skip_norm_wip()) + if let Some(unnormalized_obligations) = + wfcx.unnormalized_obligations(span, ty.skip_norm_wip()) { let filtered_obligations = unnormalized_obligations.into_iter().filter(|o| { - matches!(o.predicate.kind().skip_binder(), - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) - if matches!(ct.kind(), ty::ConstKind::Param(..))) + match o.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType( + ct, + _, + )) => matches!(ct.kind(), ty::ConstKind::Param(..)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + matches!( + *o.cause.code().peel_derives(), + ObligationCauseCode::ConstItemTy(_) + ) && tcx.is_lang_item( + pred.trait_ref.def_id, + LangItem::ConstParamTy, + ) + } + _ => false, + } }); wfcx.ocx.register_obligations(filtered_obligations) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 47b248f26c300..f7376b44a5432 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -415,6 +415,10 @@ pub enum ObligationCauseCode<'tcx> { /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy` ConstParam(Ty<'tcx>), + /// Requirement for the type of a const item used in the type system to implement + /// `ConstParamTy`. + ConstItemTy(Ty<'tcx>), + /// Obligations emitted during the normalization of a free type alias. TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 082c312c7c75e..02e69ff8b97b0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -102,10 +102,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .emit(); } - // Report a const-param specific error - if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives() - { - return self.report_const_param_not_wf(ty, &obligation).emit(); + // Report a `ConstParamTy`-specific error + match *obligation.cause.code().peel_derives() { + ObligationCauseCode::ConstParam(ty) => { + return self + .report_const_param_not_wf( + ty, + self.tcx.ty_span(obligation.cause.body_def_id), + &obligation, + ) + .emit(); + } + ObligationCauseCode::ConstItemTy(ty) => { + return self + .report_const_param_not_wf(ty, obligation.cause.span, &obligation) + .emit(); + } + _ => {} } let bound_predicate = obligation.predicate.kind(); @@ -1389,11 +1402,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn report_const_param_not_wf( &self, ty: Ty<'tcx>, + span: Span, obligation: &PredicateObligation<'tcx>, ) -> Diag<'a> { - let def_id = obligation.cause.body_def_id; - let span = self.tcx.ty_span(def_id); - let mut file = None; let ty_str = self.tcx.short_string(ty, &mut file); let mut diag = match ty.kind() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 01b3026ff4e5b..441a3625115b8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3634,6 +3634,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::AlwaysApplicableImpl | ObligationCauseCode::ConstParam(_) + | ObligationCauseCode::ConstItemTy(_) | ObligationCauseCode::ReferenceOutlivesReferent(..) | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index cf101a788d58b..f6363e724bb01 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -481,6 +481,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // `i32: Clone` // `i32: Copy` // ] + if matches!(data.kind, ty::AliasTermKind::ProjectionConst { .. }) { + self.require_const_item_ty(data.expect_ct()); + } + let obligations = self.nominal_obligations(data.expect_projection_def_id(), data.args); self.out.extend(obligations); @@ -558,6 +562,33 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } + fn require_const_item_ty(&mut self, ct: ty::AliasConst<'tcx>) { + let ty = match ct.kind { + ty::AliasConstKind::Projection { .. } + | ty::AliasConstKind::Inherent { .. } + | ty::AliasConstKind::Free { .. } => ct.type_of(self.tcx()).skip_norm_wip(), + ty::AliasConstKind::Anon { .. } => return, + }; + + if self.tcx().features().const_param_ty_unchecked() || ty.has_escaping_bound_vars() { + return; + } + + let cause = self.cause(ObligationCauseCode::ConstItemTy(ty)); + let trait_ref = ty::TraitRef::new( + self.tcx(), + self.tcx().require_lang_item(LangItem::ConstParamTy, cause.span), + [ty], + ); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(trait_ref), + )); + } + /// Pushes all the predicates needed to validate that `term` is WF into `out`. #[instrument(level = "debug", skip(self))] fn add_wf_preds_for_term(&mut self, term: Term<'tcx>) { @@ -1013,8 +1044,13 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { if !t.has_escaping_bound_vars() { for projection in data.projection_bounds() { + let projection = projection.with_self_ty(tcx, t); + let projection_pred = projection.skip_binder(); + if projection_pred.term.as_const().is_some() { + self.require_const_item_ty(projection_pred.projection_term.expect_ct()); + } + let pred_binder = projection - .with_self_ty(tcx, t) .map_bound(|p| { p.term.as_const().map(|ct| { let assoc_const_ty = tcx @@ -1076,6 +1112,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Alias(_, alias_const) => { if !c.has_escaping_bound_vars() { + self.require_const_item_ty(alias_const); + // Skip type consts as mGCA doesn't support evaluatable clauses if !alias_const.kind.is_type_const(tcx) && !tcx.features().generic_const_args() { diff --git a/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.rs new file mode 100644 index 0000000000000..4c479619c06d7 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] +#![allow(incomplete_features)] + +trait Trait { + const F: fn(); +} + +trait Nested { + type Out: Trait; + //~^ ERROR using function pointers as const generic parameters is forbidden +} + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.stderr new file mode 100644 index 0000000000000..873bcc26d6ea0 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/associated-type-bound-issue-161100.stderr @@ -0,0 +1,9 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/associated-type-bound-issue-161100.rs:11:21 + | +LL | type Out: Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.rs new file mode 100644 index 0000000000000..db1c77b7bb974 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] +#![allow(incomplete_features)] + +struct S; +const C: S = S; + +trait Trait { + const F: S; +} + +fn take(_: impl Trait) {} +//~^ ERROR `S` must implement `ConstParamTy` + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.stderr new file mode 100644 index 0000000000000..7131397ecbb43 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.stderr @@ -0,0 +1,15 @@ +error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter + --> $DIR/direct-const-item-associated-equality-issue-161100.rs:13:23 + | +LL | fn take(_: impl Trait) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct + | +LL + #[derive(ConstParamTy, PartialEq, Eq)] +LL | struct S; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.rs new file mode 100644 index 0000000000000..fabd5683a2904 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args)] +#![feature(min_generic_const_args)] + +trait Trait { + const F: fn(); +} + +fn take(_: impl Trait) {} +//~^ ERROR using function pointers as const generic parameters is forbidden + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.stderr new file mode 100644 index 0000000000000..803dbd7a04b84 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/fn-ptr-const-param-issue-161100.stderr @@ -0,0 +1,9 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-ptr-const-param-issue-161100.rs:10:23 + | +LL | fn take(_: impl Trait) {} + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.rs new file mode 100644 index 0000000000000..927bb79838a4e --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args)] +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +enum Foo { + Unit, + Function(fn()), +} + +trait Trait { + const X: Foo; +} + +fn unit(_: impl Trait) {} +//~^ ERROR `Foo` must implement `ConstParamTy` + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.stderr new file mode 100644 index 0000000000000..bd413e6a2c3a9 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.stderr @@ -0,0 +1,15 @@ +error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter + --> $DIR/non-const-param-ty-associated-const-equality-issue-161100.rs:17:23 + | +LL | fn unit(_: impl Trait) {} + | ^^^^^^^^^^^^^^^^^ + | +help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the enum + | +LL + #[derive(ConstParamTy, PartialEq, Eq)] +LL | enum Foo { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.rs new file mode 100644 index 0000000000000..975fac81af38a --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] +#![allow(incomplete_features)] + +trait Trait { + const F: fn(); +} + +fn take() where T: Trait {} +//~^ ERROR using function pointers as const generic parameters is forbidden + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.stderr new file mode 100644 index 0000000000000..1eb1d21cb5464 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.stderr @@ -0,0 +1,9 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/where-clause-issue-161100.rs:10:29 + | +LL | fn take() where T: Trait {} + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`.