diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f35b901633fcb..08f053a5c97c6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1007,20 +1007,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 5520b059f5678..5fd61451bce8e 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 4cb5465b5bbee..e6891dfa2866c 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 @@ -103,10 +103,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .emit_err(); } - // 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_err(); + // 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_err(); + } + ObligationCauseCode::ConstItemTy(ty) => { + return self + .report_const_param_not_wf(ty, obligation.cause.span, &obligation) + .emit_err(); + } + _ => {} } let bound_predicate = obligation.predicate.kind(); @@ -1422,11 +1435,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 32237e9f60ca3..bc9349967ed6a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3906,6 +3906,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 ba33270c2adba..8068ce00af21b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -185,6 +185,9 @@ pub fn clause_obligations<'tcx>( wf.add_wf_preds_for_term(ty.into()); } ty::ClauseKind::Projection(t) => { + if matches!(t.projection_term.kind, ty::AliasTermKind::ProjectionConst { .. }) { + wf.require_const_item_ty(t.projection_term.expect_ct()); + } wf.add_wf_preds_for_projection_term(t.projection_term); wf.add_wf_preds_for_term(t.term); } @@ -570,6 +573,32 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } + fn require_const_item_ty(&mut self, ct: ty::AliasConst<'tcx>) { + let ty = ct.type_of(self.tcx()).skip_norm_wip(); + + 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 +1055,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 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..fad24e1248bb5 --- /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..c9a4207afea05 --- /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/dyn-associated-const-issue-161100.rs b/tests/ui/const-generics/associated-const-bindings/dyn-associated-const-issue-161100.rs new file mode 100644 index 0000000000000..bb4a664543407 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-associated-const-issue-161100.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver=globally + +#![feature(generic_const_args, min_generic_const_args)] + +trait Trait { + const F: fn(); +} + +fn take(_: &dyn Trait) {} +//~^ ERROR using function pointers as const generic parameters is forbidden + +type TraitObject = dyn Trait; +//~^ ERROR using function pointers as const generic parameters is forbidden + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-associated-const-issue-161100.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-associated-const-issue-161100.stderr new file mode 100644 index 0000000000000..ee194c405a257 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-associated-const-issue-161100.stderr @@ -0,0 +1,15 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/dyn-associated-const-issue-161100.rs:9:13 + | +LL | fn take(_: &dyn Trait) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/dyn-associated-const-issue-161100.rs:12:1 + | +LL | type TraitObject = dyn Trait; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +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`.