Skip to content
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

Closed
qwerty19106 opened this issue Dec 2, 2019 · 17 comments · Fixed by #67906 or #68388
Closed

Const generic ICE: constant in type had an ignored error: TooGeneric #66962

qwerty19106 opened this issue Dec 2, 2019 · 17 comments · Fixed by #67906 or #68388
Labels
A-const-generics Area: const generics (parameters and arguments) F-const_generics `#![feature(const_generics)]` glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@qwerty19106
Copy link

qwerty19106 commented Dec 2, 2019

Environment:

note: rustc 1.41.0-nightly (4007d4ef2 2019-12-01) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin

The code:

#![feature(const_generics)]

#[derive(PartialEq, Eq)]
struct Config {
    arr_size: usize
}

struct B<const CFG: Config> {
    arr: [u8; {CFG.arr_size}]
}

fn main() {
}

gives ICE:

error: internal compiler error: constant in type had an ignored error: TooGeneric

Playground

@Centril Centril added A-const-generics Area: const generics (parameters and arguments) F-const_generics `#![feature(const_generics)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-medium Medium priority I-nominated and removed requires-nightly This issue requires a nightly compiler in some way. labels Dec 3, 2019
@Centril
Copy link
Contributor

Centril commented Dec 3, 2019

Reproduces without the feature gate enabled.

@hellow554
Copy link
Contributor

hellow554 commented Dec 3, 2019

It is noteworthy (and probably a bug too), that it only works if you use #[derive(PartialEq, Eq)].

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() {}
error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq`
  --> src/main.rs:10:21
   |
10 | struct B<const CFG: Config> {
   |                     ^^^^^^ `Config` doesn't derive both `PartialEq` and `Eq`

Backtrace:

error: internal compiler error: constant in type had an ignored error: TooGeneric
  --> src/main.rs:12:5
   |
12 |     arr: [u8; {CFG.0}]
   |     ^^^^^^^^^^^^^^^^^^

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:347:17
stack backtrace:
   0:     0x7f63673e75d4 - backtrace::backtrace::libunwind::trace::hc586f95f659e6084
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1:     0x7f63673e75d4 - backtrace::backtrace::trace_unsynchronized::ha9827fdb593fd967
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2:     0x7f63673e75d4 - std::sys_common::backtrace::_print_fmt::h00c888c95e07165a
                               at src/libstd/sys_common/backtrace.rs:84
   3:     0x7f63673e75d4 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h8407ffb2d059bc74
                               at src/libstd/sys_common/backtrace.rs:61
   4:     0x7f636741fcec - core::fmt::write::h4165a12a3856465f
                               at src/libcore/fmt/mod.rs:1024
   5:     0x7f63673db937 - std::io::Write::write_fmt::h499a0566ceaa0048
                               at src/libstd/io/mod.rs:1428
   6:     0x7f63673eba7e - std::sys_common::backtrace::_print::h05fbb11587298e2b
                               at src/libstd/sys_common/backtrace.rs:65
   7:     0x7f63673eba7e - std::sys_common::backtrace::print::h8021a3ed2b5ff07e
                               at src/libstd/sys_common/backtrace.rs:50
   8:     0x7f63673eba7e - std::panicking::default_hook::{{closure}}::hd3a6326f5c6c149f
                               at src/libstd/panicking.rs:193
   9:     0x7f63673eb771 - std::panicking::default_hook::h7088fb00a0cb1faf
                               at src/libstd/panicking.rs:210
  10:     0x7f6367931833 - rustc_driver::report_ice::h7d5c1d6a7c4e3fb5
  11:     0x7f63673ec230 - std::panicking::rust_panic_with_hook::h6b223bff7721d4c1
                               at src/libstd/panicking.rs:475
  12:     0x7f63697c94f5 - std::panicking::begin_panic::h372a91a0f5e0855e
  13:     0x7f63697faa5c - <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop::h222594a5efabe6ee
  14:     0x7f63678ddd96 - core::ptr::real_drop_in_place::ha878bee8c6c3164e
  15:     0x7f63678e3843 - <alloc::rc::Rc<T> as core::ops::drop::Drop>::drop::h78a9ef975e0151c9
  16:     0x7f636790431c - core::ptr::real_drop_in_place::h126176f0f6835d28
  17:     0x7f63678f8860 - rustc_interface::interface::run_compiler_in_existing_thread_pool::h450b3e47e99b2a02
  18:     0x7f63678c8b72 - std::thread::local::LocalKey<T>::with::hc064f9c463ba87b1
  19:     0x7f63678c268e - scoped_tls::ScopedKey<T>::set::he618e0867346e071
  20:     0x7f636793c9a4 - syntax::with_globals::h05656a832d1edc4c
  21:     0x7f636793eb00 - std::sys_common::backtrace::__rust_begin_short_backtrace::hb45a6b809630e3e0
  22:     0x7f63673fcd0a - __rust_maybe_catch_panic
                               at src/libpanic_unwind/lib.rs:78
  23:     0x7f63678d9469 - core::ops::function::FnOnce::call_once{{vtable.shim}}::h0091d3870173b469
  24:     0x7f63673cd88f - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h9ef9eb6ec2ee6be0
                               at /rustc/fdc0011561c6365c596dfd8fa1ef388162bc89c7/src/liballoc/boxed.rs:969
  25:     0x7f63673fb730 - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::hc0fc46e9a64f076e
                               at /rustc/fdc0011561c6365c596dfd8fa1ef388162bc89c7/src/liballoc/boxed.rs:969
  26:     0x7f63673fb730 - std::sys_common::thread::start_thread::h4eee21a391e25c99
                               at src/libstd/sys_common/thread.rs:13
  27:     0x7f63673fb730 - std::sys::unix::thread::Thread::new::thread_start::h673f7c20aae94594
                               at src/libstd/sys/unix/thread.rs:80
  28:     0x7f636733a669 - start_thread
  29:     0x7f6367251323 - clone
  30:                0x0 - <unknown>

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.41.0-nightly (fdc001156 2019-12-02) running on x86_64-unknown-linux-gnu

query stack during panic:
end of query stack

@slightlyoutofphase
Copy link
Contributor

slightlyoutofphase commented Dec 3, 2019

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);
}

@osa1
Copy link
Contributor

osa1 commented Dec 4, 2019

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 rustc_mir::interpret::operand raises the error in this code:

    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), // <--------------------
            ...

@osa1
Copy link
Contributor

osa1 commented Dec 4, 2019

Adding some debug prints, I see that the ParamConst is something like ParamConst { index: 0, name: "CFG" }. Is there a way to resolve this "CFG" to the actual const Config struct so that I can select the field?

@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Dec 18, 2019
@eddyb
Copy link
Member

eddyb commented Dec 19, 2019

TooGeneric shouldn't really cause an error, it should be silent and simply leave the constant unevaluated (until a later situation in which the const parameter is replaced with an actual value).

@sebastiencs
Copy link

sebastiencs commented Dec 23, 2019

I have the same panic constant in type had an ignored error: TooGeneric but with a different code:

struct MyStruct<const SIZE: usize> {
    bitfield: [usize; SIZE / 64]
}

Backtrace:

error: internal compiler error: constant in type had an ignored error: TooGeneric
  --> src/test_const.rs:27:5
   |
27 |     bitfields: [usize; SIZE / 64]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:347:17
stack backtrace:
   0:     0x7f6ac90892e4 - backtrace::backtrace::libunwind::trace::he29c1eef22099f24
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1:     0x7f6ac90892e4 - backtrace::backtrace::trace_unsynchronized::ha36b80e516498eae
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2:     0x7f6ac90892e4 - std::sys_common::backtrace::_print_fmt::hb70f67b9deb9591b
                               at src/libstd/sys_common/backtrace.rs:84
   3:     0x7f6ac90892e4 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hf6ea30c21a2e486e
                               at src/libstd/sys_common/backtrace.rs:61
   4:     0x7f6ac90c176c - core::fmt::write::hfd06ed55ab82c6c1
                               at src/libcore/fmt/mod.rs:1057
   5:     0x7f6ac907d717 - std::io::Write::write_fmt::h8c600764d032d6f3
                               at src/libstd/io/mod.rs:1426
   6:     0x7f6ac908d78e - std::sys_common::backtrace::_print::h2ccb403bde2af48d
                               at src/libstd/sys_common/backtrace.rs:65
   7:     0x7f6ac908d78e - std::sys_common::backtrace::print::hde1d2976285bb6d7
                               at src/libstd/sys_common/backtrace.rs:50
   8:     0x7f6ac908d78e - std::panicking::default_hook::{{closure}}::h5f8dbaddde324745
                               at src/libstd/panicking.rs:193
   9:     0x7f6ac908d481 - std::panicking::default_hook::h353c9f7e159c6169
                               at src/libstd/panicking.rs:210
  10:     0x7f6ac9610b23 - rustc_driver::report_ice::h1312d9253207031a
  11:     0x7f6abb348b88 - <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call::hd34b6e757f60fcb9
                               at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/liballoc/boxed.rs:1036
  12:     0x7f6abb34f204 - proc_macro::bridge::client::<impl proc_macro::bridge::Bridge>::enter::{{closure}}::{{closure}}::h78bcbeb91c63709f
                               at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/libproc_macro/bridge/client.rs:305
  13:     0x7f6ac908df40 - std::panicking::rust_panic_with_hook::h2106ae29891f5da1
                               at src/libstd/panicking.rs:475
  14:     0x7f6acb7a5a05 - std::panicking::begin_panic::h93fe85ac6a0e3437
  15:     0x7f6acb7d691c - <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop::h55cf2ea02b0742fd
  16:     0x7f6ac95dd986 - core::ptr::real_drop_in_place::h392a37dbd6e46951
  17:     0x7f6ac95f46f3 - core::ptr::real_drop_in_place::hea055a76d2f2dbd0
  18:     0x7f6ac95f417c - core::ptr::real_drop_in_place::he6fe08f725a1ff55
  19:     0x7f6ac95d7044 - rustc_interface::interface::run_compiler_in_existing_thread_pool::h73894470eb0ec5df
  20:     0x7f6ac95b46b2 - std::thread::local::LocalKey<T>::with::h495fb06c01f6023a
  21:     0x7f6ac95a620e - scoped_tls::ScopedKey<T>::set::h472b490a2228a3c9
  22:     0x7f6ac962e264 - syntax::with_globals::hc9ab57e6f4791057
  23:     0x7f6ac95a69a0 - std::sys_common::backtrace::__rust_begin_short_backtrace::h65d85a8a2939bf16
  24:     0x7f6ac909ea6a - __rust_maybe_catch_panic
                               at src/libpanic_unwind/lib.rs:78
  25:     0x7f6ac95beeb9 - core::ops::function::FnOnce::call_once{{vtable.shim}}::h603ca4a944c4f841
  26:     0x7f6ac906ef6f - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h480530d6a186f051
                               at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/liballoc/boxed.rs:1022
  27:     0x7f6ac909d490 - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h45ae71d65ffe3628
                               at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/liballoc/boxed.rs:1022
  28:     0x7f6ac909d490 - std::sys_common::thread::start_thread::h9d0d044e93c04e51
                               at src/libstd/sys_common/thread.rs:13
  29:     0x7f6ac909d490 - std::sys::unix::thread::Thread::new::thread_start::h59144ad61d4caeef
                               at src/libstd/sys/unix/thread.rs:80
  30:     0x7f6ac8fe64c0 - start_thread
  31:     0x7f6ac8f04553 - __clone
  32:                0x0 - <unknown>

rustc version:
rustc 1.42.0-nightly (9b98af84c 2019-12-22) running on x86_64-unknown-linux-gnu

@djugei
Copy link
Contributor

djugei commented Dec 31, 2019

i built a minimal test case. it seems like doing any calculation in array sizes causes that ICE.

@djugei
Copy link
Contributor

djugei commented Dec 31, 2019

as a workaround you can do the calculations outside of the array and encapsulate the array in a different type, like in this example.

@eddyb
Copy link
Member

eddyb commented Jan 18, 2020

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 struct should have a bound which effectively forces all use sites to evaluate the constant and ensure it has no errors (but this is not yet implemented - the syntax where [u8; {CFG.arr_size}]:, should do this).

@eddyb eddyb reopened this Jan 18, 2020
@eddyb
Copy link
Member

eddyb commented Jan 18, 2020

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 where bound doesn't need to use u8 as the element type, as long as it passes the same Config parameter as the actual use in a field type.

This might require coordination with @rust-lang/wg-traits to make sure the WF semantics here are coherent with the rest of WF.

@djugei
Copy link
Contributor

djugei commented Jan 20, 2020

Thanks for showing a way forward @eddyb
The previous pull request did in fact not resolve the issue for me.

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.

@eddyb
Copy link
Member

eddyb commented Jan 20, 2020

@djugei So there's a few things going on:

  • we have a bit of a messaging issue (cc @varkor @yodaldevoid), you never have to write braces around the array length expression, [T; N] works just as well (the braces aren't for const generic params specifically, they're for expressions in paths, e.g. Foo<T, {N+M}>)
  • [T; N] (or [T; {N}], same thing) and Foo<T, {N}>, where N is a const generic parameter name, will not rely on a const expression, but let the typesystem see that a const parameter is used there, so CfgArray in your example isn't useful
  • OTOH, an expression like N+1 or CFG.arr_size is currently treated opaquely (because we have no algorithm to unify two such expressions), so if you write it twice, the compiler doesn't know it's the same one, hence using a type alias to write it only once

@varkor
Copy link
Member

varkor commented Jan 20, 2020

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.

@varkor
Copy link
Member

varkor commented Jan 20, 2020

This issue should be addressed in #68388 (though the code in the original post will not be accepted).

@djugei
Copy link
Contributor

djugei commented Jan 20, 2020

@eddyb
so its kinda like my workaround example?
the rules around when you need to be using brackets are kinda... inconsistent, but thats probably a different issue all together.

@varkor
Copy link
Member

varkor commented Jan 20, 2020

the rules around when you need to be using brackets are kinda... inconsistent, but thats probably a different issue all together.

Yes, this is #68257. These examples should all work (and hopefully will do soon!).

tmandry added a commit to tmandry/rust that referenced this issue Jan 22, 2020
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
tmandry added a commit to tmandry/rust that referenced this issue Jan 22, 2020
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
tmandry added a commit to tmandry/rust that referenced this issue Jan 22, 2020
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
@bors bors closed this as completed in bd090c9 Jan 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-generics Area: const generics (parameters and arguments) F-const_generics `#![feature(const_generics)]` glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
10 participants