diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 757034fe30a5e..f95635370dc3b 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -325,6 +325,9 @@ impl<'tcx> Const<'tcx> { match c.kind() { ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))), + ConstKind::Expr(_) => { + bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") + } _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()), } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 17636d432aeed..fe90066b4e7e1 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -578,16 +578,28 @@ pub fn try_evaluate_const<'tcx>( (args, param_env) } } - } else { - // FIXME: We don't check anything on stable as the only way we can wind up with - // an unevaluated constant containing generic parameters is through array repeat - // expression counts which have a future compat lint for usage of generic parameters - // instead of a hard error. + } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() { + // FIXME: remove this when `const_evaluatable_unchecked` is a hard error. + // + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. // - // This codepath is however also reachable by `generic_const_exprs` and some other - // feature gates which allow constants in the type system to use generic parameters. - // In theory we should be checking for generic parameters here and returning an error - // in such cases. + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute succesfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + tcx.dcx().delayed_bug( + "Encountered anon const with inference variable args but no error reported", + ); + + let args = GenericArgs::identity_for_item(tcx, uv.def); + let param_env = tcx.param_env(uv.def); + (args, param_env) + } else { + // FIXME: This codepath is reachable under `associated_const_equality` and in the + // future will be reachable by `min_generic_const_args`. We should handle inference + // variables and generic parameters properly instead of doing nothing. (uv.args, param_env) }; let uv = ty::UnevaluatedConst::new(uv.def, args); diff --git a/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.rs b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.rs new file mode 100644 index 0000000000000..346ef64a8a6c1 --- /dev/null +++ b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.rs @@ -0,0 +1,21 @@ +// Regression test for #132955 checking that we handle anon consts with +// inference variables in their generic arguments correctly. +// +// This arose via diagnostics where we would have some failing goal such +// as `[u8; AnonConst]: PartialEq`, then as part of diagnostics +// we would replace all generic parameters with inference vars which would yield +// a self type of `[u8; AnonConst]` and then attempt to normalize `AnonConst`. + +pub trait T { + type A; + const P: Self::A; + + fn a() { + [0u8; std::mem::size_of::()] == Self::P; + //~^ ERROR: can't compare + //~| ERROR: constant expression depends on a generic parameter + //~| ERROR: constant expression depends on a generic parameter + } +} + +fn main() {} diff --git a/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr new file mode 100644 index 0000000000000..12de4f1dc3003 --- /dev/null +++ b/tests/ui/const-generics/failing_goal_with_repeat_expr_anon_const.stderr @@ -0,0 +1,31 @@ +error: constant expression depends on a generic parameter + --> $DIR/failing_goal_with_repeat_expr_anon_const.rs:14:15 + | +LL | [0u8; std::mem::size_of::()] == Self::P; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/failing_goal_with_repeat_expr_anon_const.rs:14:47 + | +LL | [0u8; std::mem::size_of::()] == Self::P; + | ^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0277]: can't compare `[u8; std::mem::size_of::()]` with `::A` + --> $DIR/failing_goal_with_repeat_expr_anon_const.rs:14:47 + | +LL | [0u8; std::mem::size_of::()] == Self::P; + | ^^ no implementation for `[u8; std::mem::size_of::()] == ::A` + | + = help: the trait `PartialEq<::A>` is not implemented for `[u8; std::mem::size_of::()]` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub trait T where [u8; std::mem::size_of::()]: PartialEq<::A> { + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`.