rust-lang / rust · Issue No. 160553
A version of #155168 where the expected len of the array is an assoc const whose self ty is generic. #158587 fixes the case where the type can be normalized, but if T is a generic param, then <T as Trait>::LEN can't be normalized, causing us to ICE if the provided array is too long.
See https://github.com/rust-lang/rust/pull/158587#discussion_r3671288068.
//@ compile-flags: -Copt-level=0
#![allow(incomplete_features)]
#![feature(adt_const_params, min_generic_const_args, macroless_generic_const_args)]
#![feature(generic_const_parameter_types)]
trait Trait {
type const LEN: usize;
}
struct S;
impl Trait for S {
type const LEN: usize = 2;
}
fn foo<T: Trait, const A: [u8; <T as Trait>::LEN]>() -> [u8; <T as Trait>::LEN] {
A
}
fn bar<T: Trait>() -> [u8; <T as Trait>::LEN] {
foo::<T, { [1, 2, 3] }>()
}
fn main() {
bar::<S>();
}
Or if the array is too short, causes UB:
//@ compile-flags: -Copt-level=0
#![allow(incomplete_features)]
#![feature(adt_const_params, min_generic_const_args, macroless_generic_const_args)]
#![feature(generic_const_parameter_types)]
trait Trait {
type const LEN: usize;
}
struct S;
impl Trait for S {
type const LEN: usize = 2;
}
fn foo<T: Trait, const A: [u8; <T as Trait>::LEN]>() -> [u8; <T as Trait>::LEN] {
A
}
fn bar<T: Trait>() -> [u8; <T as Trait>::LEN] {
foo::<T, { [] }>()
}
fn main() {
println!("{:?}", bar::<S>());
}
rustc --version --verbose:
rustc 1.99.0-nightly (26ae60a9e 2026-07-28)
binary: rustc
commit-hash: 26ae60a9eeb20b4935be49d7a931a650fa1d2923
commit-date: 2026-07-28
host: x86_64-unknown-linux-gnu
release: 1.99.0-nightly
LLVM version: 22.1.8
also ICEs/has UB on #158587's stage1.
thread 'rustc' panicked at compiler/rustc_const_eval/src/const_eval/valtrees.rs:459:60:
called `Result::unwrap()` on an `Err` value: InterpErrorInfo(InterpErrorInfoInner { kind: UndefinedBehavior(BoundsCheckFailed { len: 2, index: 2 }), backtrace: InterpErrorBacktrace { backtrace: None } })
query stack during panic:
#0 [valtree_to_const_val] converting type-level constant value to MIR constant value
#1 [items_of_instance] collecting items used by `foo::<S, ValTree(Branch([ValTree(Leaf(0x01): u8), ValTree(Leaf(0x02): u8), ValTree(Leaf(0x03): u8)]): [u8; ValTree(Leaf(0x0000000000000002): usize)])>`
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack
Backtrace
thread 'rustc' (1013477) panicked at /rustc-dev/26ae60a9eeb20b4935be49d7a931a650fa1d2923/compiler/rustc_const_eval/src/const_eval/valtrees.rs:459:60:
called `Result::unwrap()` on an `Err` value: InterpErrorInfo(InterpErrorInfoInner { kind: UndefinedBehavior(BoundsCheckFailed { len: 2, index: 2 }), backtrace: InterpErrorBacktrace { backtrace: None } })
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::result::unwrap_failed
3: rustc_const_eval::const_eval::valtrees::valtree_into_mplace
4: rustc_const_eval::const_eval::valtrees::valtree_to_const_value
5: <rustc_const_eval::provide::{closure#1} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_middle::ty::consts::valtree::Value)>>::call_once
[... omitted 1 frame ...]
6: rustc_monomorphize::collector::items_of_instance
[... omitted 1 frame ...]
7: rustc_monomorphize::collector::collect_items_rec
8: rustc_monomorphize::collector::collect_items_rec
9: rustc_monomorphize::collector::collect_items_rec
10: rustc_monomorphize::collector::collect_crate_mono_items::{closure#1}::{closure#0}
11: rustc_monomorphize::partitioning::collect_and_partition_mono_items
[... omitted 1 frame ...]
12: rustc_codegen_ssa::base::codegen_crate::<rustc_codegen_llvm::LlvmCodegenBackend, rustc_codegen_llvm::ModuleLlvm>
13: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
14: <rustc_interface::queries::Linker>::codegen_and_build_linker
15: rustc_interface::interface::run_compiler::<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#2}
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.