-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Const generic ICE: constant in type had an ignored error: TooGeneric #66962
Comments
Reproduces without the feature gate enabled. |
It is noteworthy (and probably a bug too), that it only works if you use My code below does ICE on stable, but not on nightly, but emits an error: #![feature(const_generics)]
struct Config(usize);
impl std::cmp::Eq for Config {}
impl std::cmp::PartialEq for Config {
fn eq(&self, _: &Self) -> bool { false }
}
struct B<const CFG: Config> {
arr: [u8; {CFG.0}]
}
fn main() {}
Backtrace:
|
Just for the sake of maybe helping to drill down on the cause of the bug by way of comparison, here's an example of similar code that's somewhat more complex but that interestingly does work fine: #![allow(incomplete_features)]
#![feature(const_fn)]
#![feature(const_generics)]
#![feature(const_if_match)]
use std::fmt::{self, Debug, Formatter};
struct CFG<const OPT_A: char, const OPT_B: bool> {}
impl<const OPT_A: char, const OPT_B: bool> CFG<OPT_A, OPT_B> {
const LEN: usize = match OPT_A {
'A' => 64,
'B' => 128,
'C' => 256,
'D' => 512,
_ => 512,
};
const IS_TRUE: bool = OPT_B;
}
struct CFGBuilder<const A: char, const B: bool> {}
type Options = (usize, bool);
impl<const A: char, const B: bool> CFGBuilder<A, B> {
const RESULT: Options = (CFG::<A, B>::LEN, CFG::<A, B>::IS_TRUE);
}
const DEFAULT_CFG: Options = CFGBuilder::<'A', true>::RESULT;
const ALT_CFG: Options = CFGBuilder::<'B', false>::RESULT;
struct B1 {
arr: [u8; DEFAULT_CFG.0],
}
impl B1 {
const CAP: usize = DEFAULT_CFG.0;
const IS_TRUE: bool = DEFAULT_CFG.1;
const fn new(val: u8) -> Self {
Self {
arr: [val; Self::CAP],
}
}
}
impl Debug for B1 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "B1 IS_TRUE: {}\n{:?}", Self::IS_TRUE, unsafe {
// Not actually unsafe, because it can't go out of bounds.
self.arr.get_unchecked(..)
})
}
}
struct B2 {
arr: [u8; ALT_CFG.0],
}
impl B2 {
const CAP: usize = ALT_CFG.0;
const IS_TRUE: bool = ALT_CFG.1;
const fn new(val: u8) -> Self {
Self {
arr: [val; Self::CAP],
}
}
}
impl Debug for B2 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "B2 IS_TRUE: {}\n{:?}", Self::IS_TRUE, unsafe {
// Not actually unsafe, because it can't go out of bounds.
self.arr.get_unchecked(..)
})
}
}
const ONE: B1 = B1::new(1);
const TWO: B2 = B2::new(2);
fn main() {
println!("{:?}", ONE);
println!("{:?}", TWO);
} |
The backtrace is not too useful as it shows the reporting code rather than the code that raised the error. I did a little bit of debugging and I think crate fn eval_const_to_op(
&self,
val: &'tcx ty::Const<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let tag_scalar = |scalar| match scalar {
Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)),
Scalar::Raw { data, size } => Scalar::Raw { data, size },
};
// Early-return cases.
let val_val = match val.val {
ty::ConstKind::Param(_) =>
throw_inval!(TooGeneric), // <--------------------
... |
Adding some debug prints, I see that the |
|
I have the same panic struct MyStruct<const SIZE: usize> {
bitfield: [usize; SIZE / 64]
} Backtrace:
rustc version: |
i built a minimal test case. it seems like doing any calculation in array sizes causes that ICE. |
as a workaround you can do the calculations outside of the array and encapsulate the array in a different type, like in this example. |
This is a legitimate error, but it shouldn't have been ICEing. I'm sorry I didn't notice it earlier! The reason the original example shouldn't compile is because it can cause post-monomorphization const-eval failures! The |
Given the lack of const expression unification, this is what it would take: #![feature(const_generics)]
#[derive(PartialEq, Eq)]
struct Config {
arr_size: usize
}
type CfgArray<T, const CFG: Config> = [T; {CFG.arr_size}];
struct B<const CFG: Config>
where CfgArray<u8, CFG>:,
{
arr: CfgArray<u8, CFG>,
} Note that the This might require coordination with @rust-lang/wg-traits to make sure the WF semantics here are coherent with the rest of WF. |
Thanks for showing a way forward @eddyb So we need to construct a wrapper around the arr_size? i don't quite understand why/what that does. Is there somewhere to read up on it? just to avoid cargo culting. specifically whats the difference to #![feature(const_generics)]
type CfgArray<T, const N: usize> = [T; {N}];
struct B<const N: usize>
where CfgArray<u8, N>:,
{
arr: CfgArray<u8, N>,
} and what does the "empty" where clause do. |
@djugei So there's a few things going on:
|
I've opened an issue about the first observation (#68387), but there are definitely going to be learnability problems with the latter two until we address it properly. |
This issue should be addressed in #68388 (though the code in the original post will not be accepted). |
@eddyb |
Yes, this is #68257. These examples should all work (and hopefully will do soon!). |
Make `TooGeneric` error in WF checking a proper error `TooGeneric` is encountered during WF checking when we cannot determine that a constant involving a generic parameter will always be evaluated successfully (rather than resulting in an error). In these cases, the burden of proof should be with the caller, so that we can avoid post-monomorphisation tim errors (which was the previous previous behaviour). This commit ensures that this situation produces a proper compiler error, rather than silently ignoring it or ICEing. Fixes rust-lang#66962. r? @eddyb
Make `TooGeneric` error in WF checking a proper error `TooGeneric` is encountered during WF checking when we cannot determine that a constant involving a generic parameter will always be evaluated successfully (rather than resulting in an error). In these cases, the burden of proof should be with the caller, so that we can avoid post-monomorphisation tim errors (which was the previous previous behaviour). This commit ensures that this situation produces a proper compiler error, rather than silently ignoring it or ICEing. Fixes rust-lang#66962. r? @eddyb
Make `TooGeneric` error in WF checking a proper error `TooGeneric` is encountered during WF checking when we cannot determine that a constant involving a generic parameter will always be evaluated successfully (rather than resulting in an error). In these cases, the burden of proof should be with the caller, so that we can avoid post-monomorphisation tim errors (which was the previous previous behaviour). This commit ensures that this situation produces a proper compiler error, rather than silently ignoring it or ICEing. Fixes rust-lang#66962. r? @eddyb
Environment:
The code:
gives ICE:
Playground
The text was updated successfully, but these errors were encountered: