C++ Logo

std-discussion

Advanced search

Re: Stateful reflection functions and const variables that are lifted to constexpr

From: Keenan Horrigan <friedkeenan_at_[hidden]>
Date: Sun, 05 Apr 2026 18:00:51 +0000
Dang. That would seem to me a really sharp corner with reflection, then. It was... not the easiest to figure out where my actual code was going wrong.

And I would say that there's a problem even when you do actually want the variable as constexpr, since, as mentioned, even in a template context GCC will eagerly evaluate the expression, before the template is ever instantiated, if there are no dependent names involved. And that still seems at least somewhat unideal.

Maybe there could be some sort of marker placed on "stateful" consteval functions such as is_complete_type, has_identifier, members_of, etc. that then the compiler could look at and delay evaluation for? I'm not sure that that would work though, since it would need to propagate through to user-defined functions too I think.

To further clarify how I came upon this, I figured out a way with current-day GCC to track whether friend-injection has taken place to use with my 'consteval_state' machinery (which was shown off [here](https://friedkeenan.github.io/posts/2026/03/08/exploring-mutable-consteval-state/)), which is now exposing that code to more GCC behavior.

With that code it's obviously clear that stateful things are happening, but I would worry that these stateful functions are still going to be used in more typical code, and that this issue could very much cause unintuitive behavior for people.

But yeah, I'm not at all sure what the best way to fix it would be.

Thanks

On Sunday, April 5th, 2026 at 12:32 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:

> On Sun, Apr 5, 2026, 12:13 PM Keenan Horrigan via Std-Discussion <std-discussion_at_[hidden]> wrote:
>
>> Hello,
>>
>> Yesterday I ran into really annoying behavior with GCC with this sort of code:
>>
>> consteval bool is_defined() {
>> const auto is_complete = is_complete_type(^^to_define);
>>
>> return is_complete;
>> }
>>
>> consteval {
>> define_aggregate(^^to_define, {});
>> }
>>
>> static_assert(is_complete_type(^^to_define));
>>
>> static_assert(is_defined());
>>
>> With the experimental Clang reflection branch, both static asserts succeed, but with GCC, then the final one does not: https://godbolt.org/z/TdsxWs3PW
>>
>> It does, however, succeed if you leave the 'const' off of the 'is_complete' variable.
>>
>> GCC seems to me to be taking advantage of the "potentially usable in constant expressions" (https://eel.is/c++draft/expr.const#def:potentially_usable_in_constant_expressions) feature and lifting the `is_complete` variable to be effectively 'constexpr', and evaluating 'is_complete_type(^^to_define)' right away. This will happen even in a template because GCC can see that the expression doesn't rely on any dependent names, and so will still eagerly evaluate it.
>>
>> But in short, I'm wondering if this is at all standard behavior? It really really feels like it should be a bug, that something so innocuous as a 'const' specifier could so starkly change the behavior of your program. The problem is that I'm not sure that it is actually a bug in GCC.
>>
>> Any clarification towards that would be greatly appreciated.
>>
>> Thank you
>
> Far from this being a gcc bug, I think the standard mandates gcc's behavior.
>
> This is the legacy hack that allows this to work, before we had constexpr:
>
> const int x = 42;
> C<x> c;
>
> And because the code doesn't express intentionality, we have this other legacy hack called trial evaluation. Now we have constexpr and constinit, but before we needed that same behavior, so the rules are that we try to constant-evaluate and if that works, great, and if doesn't, we just pretend we never tried.
>
> The const rule is for integral and enumeration types, and includes bool. So when you write
>
> const bool v = E;
>
> We try to constant-evaluate E. If that succeeds, then it's as if you wrote constexpr instead of const.
>
> Which of course isn't what you actually want here. I suppose we could exclude variables declared within consteval functions, since surely if you're writing a consteval function you can declare your variable constexpr if that's what you actually want. But that doesn't seem great to me either.
>
> Barry
>
>>

Received on 2026-04-05 18:01:01