C++ Logo

std-discussion

Advanced search

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

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Sun, 5 Apr 2026 12:32:14 -0500
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 17:32:32