Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, .. } => {
Expand Down
40 changes: 39 additions & 1 deletion compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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>) {
Expand Down Expand Up @@ -1013,8 +1044,13 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> 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
Expand Down Expand Up @@ -1076,6 +1112,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> 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()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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<F = { || {} }>;
//~^ ERROR using function pointers as const generic parameters is forbidden
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<F = { || {} }>;
| ^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0741`.
Original file line number Diff line number Diff line change
@@ -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<F = { core::direct_const_arg!(C) }>) {}
//~^ ERROR `S` must implement `ConstParamTy`

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<F = { core::direct_const_arg!(C) }>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
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`.
Original file line number Diff line number Diff line change
@@ -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<F = { || {} }>) {}
//~^ ERROR using function pointers as const generic parameters is forbidden

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<F = { || {} }>) {}
| ^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0741`.
Original file line number Diff line number Diff line change
@@ -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<X = { Foo::Unit }>) {}
//~^ ERROR `Foo` must implement `ConstParamTy`

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<X = { Foo::Unit }>) {}
| ^^^^^^^^^^^^^^^^^
|
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`.
Original file line number Diff line number Diff line change
@@ -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<T>() where T: Trait<F = { || {} }> {}
//~^ ERROR using function pointers as const generic parameters is forbidden

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<T>() where T: Trait<F = { || {} }> {}
| ^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0741`.
Loading