diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 52b69e6050a32..83bf5fd531526 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1006,20 +1006,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 f88b7ff0f8a85..394c676f4a1d9 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 26d768e5b22e8..e435b02306be1 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 @@ -101,10 +101,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(); @@ -1420,11 +1433,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 8de0514b9ef27..cc344df0fe051 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3905,6 +3905,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 175183ce633ab..9eb303ddb2beb 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -484,6 +484,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()); + } + self.nominal_obligations(data.expect_projection_def_id(), data.args, |this, obligation| { this.out.push(obligation) }); @@ -570,6 +574,37 @@ 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::InherentImpl { .. } + | ty::AliasConstKind::Free { .. } => ct.type_of(self.tcx()).skip_norm_wip(), + ty::AliasConstKind::InherentSelf { .. } | ty::AliasConstKind::Anon { .. } => return, + }; + + if ct.kind.is_direct_const(self.tcx()) { + 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>) { @@ -1026,8 +1061,16 @@ 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 matches!( + projection_pred.projection_term.kind, + ty::AliasTermKind::ProjectionConst { .. } + ) { + 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 @@ -1089,6 +1132,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_direct_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..f2dc43e77354f --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/direct-const-item-associated-equality-issue-161100.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] + +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..b5df54af573c5 --- /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:12: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..32e7b4fde6b73 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/non-const-param-ty-associated-const-equality-issue-161100.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args)] +#![feature(min_generic_const_args)] + +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..62dc2045da0fa --- /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:15: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..16023eb66f209 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/where-clause-issue-161100.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] + +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..f5ee2c0bba6b9 --- /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:9:29 + | +LL | fn take() where T: Trait {} + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`.