diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index faf41f1658b70..e8c13e6c128d4 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -347,18 +347,21 @@ where // Check the qualifs of the value of `const` items. let uneval = match constant.const_ { - Const::Ty(_, ct) - if matches!( - ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) - ) => - { - None - } - Const::Ty(_, c) => { - bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) - } + // Type-level constants that are already concrete or are params/errors: fall back to + // type-based qualifs below. + Const::Ty(_, ct) => match ct.kind() { + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) => None, + // A type-level unevaluated const (e.g., from generic const exprs). Treat like a + // MIR unevaluated const so we can look up qualifs on the referenced def. + ty::ConstKind::Unevaluated(uv) => Some(mir::UnevaluatedConst::new(uv.def, uv.args)), + // Any other kind should not reach this path in MIR const-checking. + other => { + bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", other) + } + }, + // A MIR unevaluated const: inspect its definition's qualifs below. Const::Unevaluated(uv, _) => Some(uv), + // Already a value: rely on type-based qualifs below. Const::Val(..) => None, }; diff --git a/tests/ui/const-generics/generic_const_exprs/ice-qualifs-unevaluated-operand.rs b/tests/ui/const-generics/generic_const_exprs/ice-qualifs-unevaluated-operand.rs new file mode 100644 index 0000000000000..a432b116c7b2a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/ice-qualifs-unevaluated-operand.rs @@ -0,0 +1,39 @@ +//@ check-pass +//@ revisions: full +// This is a regression test for an ICE in const qualifs where +// `Const::Ty` containing `ty::ConstKind::Unevaluated` was not handled. +// The pattern arises with `generic_const_exprs` and const fn using +// array lengths like `LEN * LEN` and repeat expressions. + +#![cfg_attr(full, feature(generic_const_exprs))] +#![cfg_attr(full, allow(incomplete_features))] + +trait One: Sized + Copy { + const ONE: Self; +} + +const fn noop(a: &mut T, b: &mut T) { + let _ = (a, b); +} + +struct Test([T; LEN * LEN]) +where + [u8; LEN * LEN]:; + +impl Test +where + [u8; LEN * LEN]:, +{ + const fn test() -> Self { + let mut a = Self([T::ONE; LEN * LEN]); + let mut i = 0; + while i < LEN { + let mut one = T::ONE; + noop(&mut one, &mut a.0[i * i + 1]); + i += 1; + } + a + } +} + +fn main() {}