Repository navigation
[ICE]: erroneous constant missed by mono item collection #162337
Description
Activity
- addedI-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.C-bugCategory: This is a bug.Category: This is a bug.
on Sep 5, 2026 - addedneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingF-gca_const_items`#![feature(gca_const_items)]` (previously: `generic_const_args`)`#![feature(gca_const_items)]` (previously: `generic_const_args`)F-gca_min_const_items`#![feature(gca_min_const_items)]` (previously: `min_generic_const_args`)`#![feature(gca_min_const_items)]` (previously: `min_generic_const_args`)
on Sep 5, 2026 I took a look at this one. The original snippet doesn't ICE on master anymore, but I think that's kind of by accident. After #162923 only trait consts get lowered as type system consts in MIR under
gca_const_items, andSelf::CONSThere is an inherent const, so it just goes the normal way now. (also the features got renamed in the meantime, so the snippet needsgca_min_const_itemsandgca_const_itemsnow)If you swap it for a trait assoc const it still crashes the same way on master
#![feature(gca_min_const_items, gca_const_items)] #![allow(incomplete_features)] trait MetaTrait {} impl MetaTrait for () {} trait HasConst { const CONST: &'static dyn MetaTrait; } impl<A: 'static> HasConst for Option<A> { const CONST: &'static dyn MetaTrait = &(); } fn get<T: HasConst>() -> &'static dyn MetaTrait { T::CONST } fn main() { let _ = get::<Option<u8>>(); }
From what I can tell the problem is that
T::CONSTends up as aConst::Tyin the MIR, so during mono we try to evaluate it through the type system, and that wants a valtree.&dyn MetaTraitcan't be a valtree. The code there assumes an error was already reported, so we just get the delayed bug, the const never gets evaluated, and then codegen blows up.fn()and unions do the same thing. AVec<u8>const (Vec::new()) hits a different one, the "shouldn't have created a ValTree for pattern_type" ICE, which looks like #162336.I get why it's lowered like that. An impl can implement a normal trait const with a
gca!(...)value, and that one has no MIR body, so a plainConst::Unevaluatedwouldn't have anything to evaluate. So just reverting that bit would break that case. I also don't think only doing it when the type isConstParamTyworks, because with something likeconst C: Self::Outthe caller can't really know.What I'd like to try is keeping
Const::Tyfor consts that are alwaysgca!and lowering everything else asConst::Unevaluatedagain, then dealing with it inconst_eval_resolve. Once the instance is resolved we know if the impl is agca!const (const_of_itemreturns something), and only then we go through the type system and turn the valtree back into a value. Everything else gets evaluated like any normal const. Personally I like this better because we'd only use valtrees when the impl really is agca!const, and those already have to beConstParamTy. It also means turning the feature on doesn't change how regular trait consts behave at runtime, which feels like what the FIXME in the MIR lowering is worried about anyway.I haven't written it yet, and I'd rather check with you two first. @khyperia you wrote the #162923 fix that made the lowering look like it does now, and @BoxyUwU you've been driving most of the GCA design. This would move the place where we decide if something is a
gca!const, and that FIXME already says it needs another look before stabilization, so I don't want to open a PR that goes against what you have planned for it. Does this sound like the direction you want, or do you have something else in mind? Happy to open a PR if it sounds ok.That is indeed the direction we want to go in, mostly! Prooobably want to lower all
ExprKind::NamedConsttoConst::Unevaluated, including things that are agca!const. (tl;drExprKind::NamedConstis a regular reference, not a typesystem reference, andConst::Unevaluatedmeans "this is a regular reference", andConst::Tymeans "this is a reference to a const that came from the type system")However, there are significant theoretical issues that we need to figure out and first, it's not just a matter of writing up a PR (if it was, I would have already done so, I have a draft on my local computer with the exact change you're describing!). I'm planning on writing up what will probably be an uncomfortably long document to share with various t-types people, and having several zulip meetings & calls over this topic.
Apologies for not linking these two issues together, yes, #162336 (comment) and this issue are basically the same issue. Sorry that you spent so long investigating that, I should have written things down better!
The original snippet doesn't ICE on master anymore, but I think that's kind of by accident
on a tangent, it was actually intentional, haha - several people on zulip were complaining about the usability of GCA due to running into this issue, so with #162937 I narrowed the things that trigger the issue down to the bare minimum of what actually needs to encounter the bug, which is projection consts. That PR's title probably gives you an idea, that lowering things to
Const::Tyis a hack~Also on another tangent, Boxy and I yapped in zulip quite a bit about
Const::Tyvs.Const::Unevaluatedin this zulip thread, if you're curious about learning more about this problem #project-const-generics > casual chat and support @ 💬 (no idea how coherent our yaps are, but at least they're in public...)See also this document Boxy wrote https://hackmd.io/1ZJgp6nSQj-8AgclcB2RAg
That is indeed the direction we want to go in, mostly! Prooobably want to lower all
ExprKind::NamedConsttoConst::Unevaluated, including things that are agca!const. (tl;drExprKind::NamedConstis a regular reference, not a typesystem reference, andConst::Unevaluatedmeans "this is a regular reference", andConst::Tymeans "this is a reference to a const that came from the type system")However, there are significant theoretical issues that we need to figure out and first, it's not just a matter of writing up a PR (if it was, I would have already done so, I have a draft on my local computer with the exact change you're describing!). I'm planning on writing up what will probably be an uncomfortably long document to share with various t-types people, and having several zulip meetings & calls over this topic.
Apologies for not linking these two issues together, yes, #162336 (comment) and this issue are basically the same issue. Sorry that you spent so long investigating that, I should have written things down better!
The original snippet doesn't ICE on master anymore, but I think that's kind of by accident
on a tangent, it was actually intentional, haha - several people on zulip were complaining about the usability of GCA due to running into this issue, so with #162937 I narrowed the things that trigger the issue down to the bare minimum of what actually needs to encounter the bug, which is projection consts. That PR's title probably gives you an idea, that lowering things to
Const::Tyis a hack~Also on another tangent, Boxy and I yapped in zulip quite a bit about
Const::Tyvs.Const::Unevaluatedin this zulip thread, if you're curious about learning more about this problem #project-const-generics > casual chat and support @ 💬 (no idea how coherent our yaps are, but at least they're in public...)See also this document Boxy wrote https://hackmd.io/1ZJgp6nSQj-8AgclcB2RAg
Ah okay, that makes a lot of sense, thanks for explaining! And no worries about the time, I learned a bunch about how this part works digging through it, so it wasn't wasted for me at all.
Lowering every NamedConst to Const::Unevaluated sounds cleaner to me too, honestly. Thinking of it as "a normal reference vs. something that came from the type system" makes the whole thing click way better than how I was looking at it. And fair point on #162937, I read the narrowing as a side effect, but a hack to get people unblocked makes total sense.
I'm going to read the zulip thread and Boxy's doc, and I'd be happy to follow along when you share the write up with t-types, even if it's just to lurk.
- removedneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
on Oct 7, 2026
snippet:
Version information
Possibly related line of code:
rust/compiler/rustc_codegen_ssa/src/mir/constant.rs
Lines 22 to 34 in 0f819a1
Command:
/home/matthias/.rustup/toolchains/master/bin/rustcProgram output
@rustbot label +F-min_generic_const_args +F-generic_const_args