Bug 120775 - [C++26] P2996R13 - Reflection
Summary: [C++26] P2996R13 - Reflection
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 16.0
: P3 enhancement
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords: c++26
Depends on:
Blocks: c++26-core
  Show dependency treegraph
 
Reported: 2025-06-23 09:02 UTC by Jakub Jelinek
Modified: 2026-01-15 18:49 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2025-06-23 00:00:00


Attachments
gcc16-p3394r4-wip.patch (4.72 KB, patch)
2025-09-03 11:53 UTC, Jakub Jelinek
Details | Diff
pack expansion containing a splice expression, containing a range indexed by a pack of size_t (164.17 KB, text/plain)
2025-11-24 03:07 UTC, Boris Staletic
Details
splice expression value category (166.68 KB, text/plain)
2025-11-24 03:13 UTC, Boris Staletic
Details

Note You need to log in before you can comment on or make changes to this bug.
Comment 1 Andrew Pinski 2025-06-23 09:26:23 UTC
.
Comment 2 Marek Polacek 2025-06-23 14:25:04 UTC
WIP: <https://forge.sourceware.org/marek/gcc/src/branch/reflection>
Comment 3 Jakub Jelinek 2025-06-23 15:27:13 UTC
https://wg21.link/P3491R3 part moved to PR120783.
Comment 4 GCC Commits 2025-07-31 14:40:56 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:d46d8267b5a55e3194e879e691aeee1bc0648bed

commit r16-2687-gd46d8267b5a55e3194e879e691aeee1bc0648bed
Author: Marek Polacek <polacek@redhat.com>
Date:   Mon Jul 14 17:24:18 2025 -0400

    c++: consteval blocks
    
    This patch implements consteval blocks, as specified by P2996.
    They aren't very useful without define_aggregate, but having
    a reviewed implementation on trunk would be great.
    
    consteval {} can be anywhere where a member-declaration or
    block-declaration can be.  The expression corresponding to it is:
    
      [] -> void static consteval compound-statement ()
    
    and it must be a constant expression.
    
    I've used cp_parser_lambda_expression to take care of most of the
    parsing.  Since a consteval block can find itself in a template, we
    need a vehicle to carry the block for instantiation.  Rather than
    inventing a new tree, I'm using STATIC_ASSERT.
    
    A consteval block can't return a value but that is checked by virtue
    of the lambda having a void return type.
    
            PR c++/120775
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_outermost_constant_expr): Use
            extract_call_expr.
            * cp-tree.h (CONSTEVAL_BLOCK_P, LAMBDA_EXPR_CONSTEVAL_BLOCK_P): Define.
            (finish_static_assert): Adjust declaration.
            (current_nonlambda_function): Likewise.
            * lambda.cc (current_nonlambda_function): New parameter.  Only keep
            iterating if the function represents a consteval block.
            * parser.cc (cp_parser_lambda_expression): New parameter for
            consteval blocks.  Use it.  Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P.
            (cp_parser_lambda_declarator_opt): Likewise.
            (build_empty_string): New.
            (cp_parser_next_tokens_are_consteval_block_p): New.
            (cp_parser_consteval_block): New.
            (cp_parser_block_declaration): Handle consteval blocks.
            (cp_parser_static_assert): Use build_empty_string.
            (cp_parser_member_declaration): Handle consteval blocks.
            * pt.cc (tsubst_stmt): Adjust a call to finish_static_assert.
            * semantics.cc (finish_fname): Warn for consteval blocks.
            (finish_static_assert): New parameter for consteval blocks.  Set
            CONSTEVAL_BLOCK_P.  Evaluate consteval blocks specially.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp26/consteval-block1.C: New test.
            * g++.dg/cpp26/consteval-block2.C: New test.
            * g++.dg/cpp26/consteval-block3.C: New test.
            * g++.dg/cpp26/consteval-block4.C: New test.
            * g++.dg/cpp26/consteval-block5.C: New test.
            * g++.dg/cpp26/consteval-block6.C: New test.
            * g++.dg/cpp26/consteval-block7.C: New test.
            * g++.dg/cpp26/consteval-block8.C: New test.
    
    Reviewed-by: Jason Merrill <jason@redhat.com>
Comment 5 Jakub Jelinek 2025-09-03 11:53:13 UTC
Created attachment 62293 [details]
gcc16-p3394r4-wip.patch

Untested partial implementation of P3394R4, in particular the one which doesn't depend on the reflection branch stuff, so parsing of annotations and making sure it appertains to the right entities etc.
Obviously, std::meta::is_annotation, std::meta::annotations_of and std::meta::annotations_of_with_type can't be implemented without the reflection stuff, and only when e.g. std::meta::reflect_constant is implemented.
One thing not implemented in the patch (xfailed in the test) is that the paper allows annotations also on base-specifiers.  This is novel to GCC, we ignore all attributes for those (with warning if any non-ignorable), and it is unclear on what tree to store those.
Comment 6 Marek Polacek 2025-10-31 15:15:23 UTC
TODO:

The test from https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3293r3.html still 
ICEs:

base.C: In function ‘constexpr int f()’:
base.C:15:81: internal compiler error: in cp_parser_splice_expression, at cp/parser.cc:6279
   15 |   B& b = d.[: std::meta::bases_of(^^D, std::meta::access_context::current())[0] :];
      |                                                                                 ^~
0x3011536 internal_error(char const*, ...)
	/home/mpolacek/src/forge/gcc/gcc/diagnostic-global-context.cc:787
0x301fe23 fancy_abort(char const*, int, char const*)
	/home/mpolacek/src/forge/gcc/gcc/diagnostics/context.cc:1806
0x6edd93 cp_parser_splice_expression
	/home/mpolacek/src/forge/gcc/gcc/cp/parser.cc:6279
Comment 7 Jakub Jelinek 2025-10-31 17:04:44 UTC
(In reply to Marek Polacek from comment #6)
> TODO:
> 
> The test from
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3293r3.html still 
> ICEs:
> 
> base.C: In function ‘constexpr int f()’:
> base.C:15:81: internal compiler error: in cp_parser_splice_expression, at
> cp/parser.cc:6279
>    15 |   B& b = d.[: std::meta::bases_of(^^D,
> std::meta::access_context::current())[0] :];
>       |                                                                     
> ^~
> 0x3011536 internal_error(char const*, ...)
> 	/home/mpolacek/src/forge/gcc/gcc/diagnostic-global-context.cc:787
> 0x301fe23 fancy_abort(char const*, int, char const*)
> 	/home/mpolacek/src/forge/gcc/gcc/diagnostics/context.cc:1806
> 0x6edd93 cp_parser_splice_expression
> 	/home/mpolacek/src/forge/gcc/gcc/cp/parser.cc:6279

We should error on splicing reflections satisfying is_base, is_function_parameter, is_constructor, is_destructor etc.
Comment 8 Desmond Gold 2025-11-03 04:06:01 UTC
The following testcase ICEs on constexpr variable of consteval-only type inside
a runtime-evaluated function

using info = decltype(^^::);

// OK
constexpr info A {};
constexpr info B = ^^::;
inline constexpr info C = ^^::;

template <typename T>
struct S {
    // OK
    static constexpr info B {^^T};

    // wont ICE during template definition
    // but ICE during template instantiation
    // (1)
    void wow() {
        constexpr info D {^^T};
    }
};

consteval void foo() {
    info A = ^^::;
    constexpr info B = ^^::;
}

constexpr void bar() {
    constexpr info A = ^^::;
    static constexpr info B = ^^::;
}

constexpr void tux() {
    if consteval {
        constexpr info A = ^^::;
        // static constexpr info B = ^^::;
    }
}

void qux() {
    // ICE
    // constexpr info A {};
    // constexpr info B = ^^::;
    // static constexpr info C = ^^::;

    // OK: since it is constant evaluated
    foo();
    consteval { bar(); }
    consteval { tux(); }

    // OK: since the runtime evaluation doesn't contain
    //     the consteval branch
    tux();

    // ICE
    // bar();
}

// triggers ICE on (1)
// template struct S <int>;

When uncommenting the lines that are labeled ICE, each line will have the same following ICE output:
<source>:LL:CC: internal compiler error: Segmentation fault
   57 | }
      | ^
0x291e078 diagnostics::context::diagnostic_impl(rich_location*, diagnostics::metadata const*, diagnostics::option_id, char const*, __va_list_tag (*) [1], diagnostics::kind)
	???:0
0x2912e6b internal_error(char const*, ...)
	???:0

I run the testcase using https://godbolt.org/z/d8EY1TPdK. I don't know if this has been fixed since the branch is based on gcc-reflection-trunk-20251031.
Comment 9 Desmond Gold 2025-11-03 05:08:24 UTC
I tried to wrap the declarations using "if not consteval { ... }" which seems to silence the ICE:

using info = decltype(^^::);

consteval info identity(info i) { return i; }
consteval int something_of(info) { return 10; }
consteval void do_something(info) {}

void fox() {
  if not consteval {
    constexpr info X {};
    constexpr info A = ^^::;
    constexpr info B = identity(A);
    static constexpr info D = ^^::;

    static_assert(X == info{});
    static_assert(A == ^^::);
    static_assert(B == ^^::);
    static_assert(D == ^^::);

    consteval { 
      do_something(X);
      do_something(A);
      int H = something_of(A);
      constexpr int I = something_of(A);
    }
  }
}

However, the ICE resurfaces when referencing the constexpr variable of a consteval-only type:

using info = decltype(^^::);

consteval info identity(info i) { return i; }
consteval int something_of(info) { return 10; }
consteval void do_something(info) {}

void fox() {
  if not consteval {
    constexpr info X {};
    constexpr info A = ^^::;
    constexpr info B = identity(A);
    static constexpr info D = ^^::;

    static_assert(X == info{});
    static_assert(A == ^^::);
    static_assert(B == ^^::);
    static_assert(D == ^^::);

    consteval { 
      do_something(X);
      do_something(A);
      int H = something_of(A);
      constexpr int I = something_of(A);
    }

    // ICE
    // do_something(X);
    // do_something(A);
    // do_something_runtime<X>();
    // do_something_runtime<A>();
    // int C = something_of(A);
    // constexpr int E = something_of(A);
    // identity(A);
    // identity(B);
  }
}

Uncommenting the line one at a time will produce an ICE output 

https://godbolt.org/z/9xWhbYhbz
Comment 10 Jakub Jelinek 2025-11-03 12:09:42 UTC
Another thing to do is mangling.
#include <meta>

template <std::meta::info I>
void foo ();

void
bar ()
{
  foo <^^::> ();
  foo <^^std::meta> ();
  //foo <std::meta::info {}> ();
  foo <std::meta::reflect_constant (42)> ();
}
The Bloomberg clang++ branch mangles these as
_Z3fooIMn$EEvv
_Z3fooIMnNSt3__14metaE$EEvv
_Z3fooIMvLi42EEEvv
where using $ in the mangled names is certainly wrong.
GCC mangles it as
_Z3fooIXL_Z2::EEEvv
_Z3fooIXL_ZSt4metaEEEvv
_Z3fooIXLi42EEEvv
which is obviously wrong too, :: in a mangled name can't appear, and reflect_constant (42) argument shouldn't be mangled as a merge 42 constant IMHO.
Plus on the commented out case we ICE.
Comment 11 Jakub Jelinek 2025-11-03 18:49:39 UTC
The #c8 ICE can be reduced to

constexpr void foo () { if consteval { static constexpr auto a = ^^::; } }
auto bar () { return &foo; }

or

template <typename T> struct S { static constexpr auto s = ^^T; void foo () { constexpr auto s = ^^T; } };
template struct S <int>;

The first ICE is during mangling, where we try to mangle the foo::a static variable, the second ICE is trying to output the S<int>::s variable.
Comment 12 Marek Polacek 2025-11-03 18:52:12 UTC
(In reply to Jakub Jelinek from comment #11)
> The #c8 ICE can be reduced to
> 
> constexpr void foo () { if consteval { static constexpr auto a = ^^::; } }
> auto bar () { return &foo; }
> 
> or
> 
> template <typename T> struct S { static constexpr auto s = ^^T; void foo ()
> { constexpr auto s = ^^T; } };
> template struct S <int>;
> 
> The first ICE is during mangling, where we try to mangle the foo::a static
> variable, the second ICE is trying to output the S<int>::s variable.

I'll take a look at the latter now.
Comment 13 Marek Polacek 2025-11-03 23:37:11 UTC
Desmond, thanks a lot for reporting these bugs.  I believe I fixed all the crashes, although this area is fraught with peril.  The mangling part is still largely unresolved.

The fix should propagate to Compiler Explorer before long.
Comment 14 Marek Polacek 2025-11-04 02:01:22 UTC
Indeed, I found more ICEs:

```
using info = decltype (^^int);
void fn (info) {}
```

which results in 
internal compiler error: in adjust_one_expanded_partition_var, at cfgexpand.cc:1898
and is actually not so easy to fix.  It should be rejected.  But e.g., our own std::meta::exception::what() is also of consteval-only type and not an immediate function and it cannot be escalated and we shouldn't error on it.

Then there's

```
template<typename T>
int fn (T) { return 4; }
const int a = fn (^^int);
```

internal compiler error: in gimplify_expr, at gimplify.cc:21216
Comment 15 Jakub Jelinek 2025-11-04 10:24:13 UTC
Had a quick look at g++.dg/reflect/p2996-17.C (the commented out stuff in there).
The reason it doesn't work is that the reflect_constant and latest calls in
  static consteval void increment ()
  {
    define_aggregate (substitute (^^Helper,
                                  { std::meta::reflect_constant (latest ()) }),
                      {});
  }
aren't evaluated when evaluating the increment call at all, instead they are evaluated
when we finish_compound_literal when parsing that function when trying to convert the initializer_list to some reflection_range usable in substitute.
std::meta::reflect_constant (latest ()) is a constant expression and
finish_compound_literal -> digest_init_flags -> digest_init_r -> process_init_constructor -> process_init_constructor_array -> massage_init_elt -> fold_non_dependent_init folds it to a reflection of constant 0.
Now, this is mce_unknown evaluation.  Shall all metafunctions be only handled if mce_true or mce_false (and define_aggregate/access_context::current only if mce_true as already done?)?


diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d6fe01ead1f..7ddb4b652cc 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3845,6 +3845,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          *non_constant_p = true;
          return t;
        }
+      /* Don't evaluate metafunctions at all when mce_unknown, otherwise we
+        might fold those prematurely.  See g++.dg/reflect/p2996-17.C.  */
+      if (ctx->manifestly_const_eval == mce_unknown)
+       {
+         *non_constant_p = true;
+         return t;
+       }
       ctx->global->metafns_called = true;
       tree e = process_metafunction (ctx, fun, t, non_constant_p, overflow_p,
                                     jump_target);
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-17.C b/gcc/testsuite/g++.dg/reflect/p2996-17.C
index 6c2c6e31996..e9dabb0d799 100644
--- a/gcc/testsuite/g++.dg/reflect/p2996-17.C
+++ b/gcc/testsuite/g++.dg/reflect/p2996-17.C
@@ -25,10 +25,8 @@ struct TU_Ticket {
 constexpr int x = TU_Ticket::latest ();  // x initialized to 0.
 consteval { TU_Ticket::increment (); }
 constexpr int y = TU_Ticket::latest ();  // y initialized to 1.
-// TODO: This one still doesn't work, doesn't call latest () again
-// but uses cached 0 value.
-//consteval { TU_Ticket::increment (); }
-//constexpr int z = TU_Ticket::latest ();  // z initialized to 2.
+consteval { TU_Ticket::increment (); }
+constexpr int z = TU_Ticket::latest ();  // z initialized to 2.
 static_assert (x == 0);
 static_assert (y == 1);
-//static_assert (z == 2);
+static_assert (z == 2);

fixes it.  Do we want to do that?  Doesn't regress anything else in the testsuite.
https://forge.sourceware.org/marek/gcc/pulls/81 has it but haven't merged this yet.
Comment 16 Jakub Jelinek 2025-11-04 10:33:32 UTC
(In reply to Jakub Jelinek from comment #10)
> The Bloomberg clang++ branch mangles these as
> _Z3fooIMn$EEvv
> _Z3fooIMnNSt3__14metaE$EEvv
> _Z3fooIMvLi42EEEvv
> where using $ in the mangled names is certainly wrong.
> GCC mangles it as
> _Z3fooIXL_Z2::EEEvv
> _Z3fooIXL_ZSt4metaEEEvv
> _Z3fooIXLi42EEEvv
> which is obviously wrong too, :: in a mangled name can't appear, and
> reflect_constant (42) argument shouldn't be mangled as a merge 42 constant
> IMHO.

Regarding mangling, we really need some agreed on mangling for the constants with std::meta::info type.
Because
#include <meta>

template <auto A>
void
foo ()
{
}

int v;

void
bar ()
{
  foo <42> ();
  foo <std::meta::reflect_constant (42)> ();
  foo <^^::> ();
  foo <std::meta::info {}> ();
  foo <^^int> ();
  foo <^^v> ();
}
is I think all valid and needs to mangle differently each time.  And it needs to be a mangling that mangles the reflections which compare equal the same and those which compare differently using different strings.
Comment 17 Jakub Jelinek 2025-11-04 10:37:01 UTC
The really hard part will be e.g. how to mangle annotations, guess that one needs to be nth annotation of something, presumably direct base relationship could be similarly mangled as nth direct base of something, data member specification needs to mangle all 5 properties somehow, etc.
Comment 18 Jakub Jelinek 2025-11-04 11:57:12 UTC
I've filed https://github.com/itanium-cxx-abi/cxx-abi/issues/208 for the mangling.
Comment 19 Marek Polacek 2025-11-04 13:21:44 UTC
(In reply to Jakub Jelinek from comment #15)
> Had a quick look at g++.dg/reflect/p2996-17.C (the commented out stuff in
> there).
> The reason it doesn't work is that the reflect_constant and latest calls in
>   static consteval void increment ()
>   {
>     define_aggregate (substitute (^^Helper,
>                                   { std::meta::reflect_constant (latest ())
> }),
>                       {});
>   }
> aren't evaluated when evaluating the increment call at all, instead they are
> evaluated
> when we finish_compound_literal when parsing that function when trying to
> convert the initializer_list to some reflection_range usable in substitute.
> std::meta::reflect_constant (latest ()) is a constant expression and
> finish_compound_literal -> digest_init_flags -> digest_init_r ->
> process_init_constructor -> process_init_constructor_array ->
> massage_init_elt -> fold_non_dependent_init folds it to a reflection of
> constant 0.
> Now, this is mce_unknown evaluation.  Shall all metafunctions be only
> handled if mce_true or mce_false (and
> define_aggregate/access_context::current only if mce_true as already done?)?
> 
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index d6fe01ead1f..7ddb4b652cc 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -3845,6 +3845,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
> tree t,
>           *non_constant_p = true;
>           return t;
>         }
> +      /* Don't evaluate metafunctions at all when mce_unknown, otherwise we
> +        might fold those prematurely.  See g++.dg/reflect/p2996-17.C.  */
> +      if (ctx->manifestly_const_eval == mce_unknown)
> +       {
> +         *non_constant_p = true;
> +         return t;
> +       }
>        ctx->global->metafns_called = true;
>        tree e = process_metafunction (ctx, fun, t, non_constant_p,
> overflow_p,
>                                      jump_target);
> diff --git a/gcc/testsuite/g++.dg/reflect/p2996-17.C
> b/gcc/testsuite/g++.dg/reflect/p2996-17.C
> index 6c2c6e31996..e9dabb0d799 100644
> --- a/gcc/testsuite/g++.dg/reflect/p2996-17.C
> +++ b/gcc/testsuite/g++.dg/reflect/p2996-17.C
> @@ -25,10 +25,8 @@ struct TU_Ticket {
>  constexpr int x = TU_Ticket::latest ();  // x initialized to 0.
>  consteval { TU_Ticket::increment (); }
>  constexpr int y = TU_Ticket::latest ();  // y initialized to 1.
> -// TODO: This one still doesn't work, doesn't call latest () again
> -// but uses cached 0 value.
> -//consteval { TU_Ticket::increment (); }
> -//constexpr int z = TU_Ticket::latest ();  // z initialized to 2.
> +consteval { TU_Ticket::increment (); }
> +constexpr int z = TU_Ticket::latest ();  // z initialized to 2.
>  static_assert (x == 0);
>  static_assert (y == 1);
> -//static_assert (z == 2);
> +static_assert (z == 2);
> 
> fixes it.  Do we want to do that?  Doesn't regress anything else in the
> testsuite.
> https://forge.sourceware.org/marek/gcc/pulls/81 has it but haven't merged
> this yet.

Yeah, it may be the right thing.  Please go ahead; if anything crops up, we'll address it.

(You could merge it with the uid_sensitive_constexpr_evaluation_p case above.)
Comment 20 Desmond Gold 2025-11-08 07:27:27 UTC
I discovered another bug which involves initializing reflection type with null reflection within template body or during template instantiation:

using info = decltype(^^int);

inline constexpr info Ag {}; // ok

consteval info return_null() {
    return info{};
}

template <typename>
struct S {
    static constexpr info Bt {^^::}; // ok
    static constexpr info Ct {}; // error during template definition
    static constexpr info Dt = return_null(); // error upon instantiation
};

template struct S<int>; // this triggers error on S<int>::Dt

int main() {
    template for (auto _ : {0}) {
        constexpr info A {}; // error upon immediate expansion
    }
}

Although it didn't ICE, it results in an error:
<source>:12:31: error: insufficient contextual information to determine type [-Wtemplate-body]
   12 |     static constexpr info Ct {}; // error during template definition
      |                               ^
<source>: In instantiation of 'constexpr const info S<int>::Dt':
required from here
<source>:16:17:   
   16 | template struct S<int>;
      |                 ^~~~~~
<source>:13:43: error: insufficient contextual information to determine type
   13 |     static constexpr info Dt = return_null(); // error upon instantiation
      |                                ~~~~~~~~~~~^~
<source>: In function 'int main()':
<source>:20:27: error: insufficient contextual information to determine type
   20 |         constexpr info A {}; // error upon immediate expansion
      |                           ^

https://godbolt.org/z/cfc3f47M6

There is no error in Clang Reflection Branch when compiling this code.
Comment 21 Desmond Gold 2025-11-08 08:06:11 UTC
Bug #2: results in an error when using a constexpr structured binding to a constexpr object whose subobjects are consteval-only (reflection value).

using info = decltype(^^int);

struct Point {
    int x;
    int y;
};

struct Info {
    info i;
    info j;
};

struct Mixed {
    int x;
    info j;
};

void foo() {
    constexpr Point p {3, 4};
    constexpr auto [px, py] = p;
    static_assert(px == 3);
    static_assert(py == 4);

    constexpr Info i {^^::, ^^int};
    constexpr auto [i1, i2] = i;
    static_assert(i.i == ^^::);
    static_assert(i.j == ^^int);
    static_assert(i1 == ^^::); // error
    static_assert(i2 == ^^int); // error

    constexpr Mixed m {4, ^^::};
    // constexpr auto [m1, m2] = m; (another ICE :<)

    constexpr int arr[] {6, 7};
    constexpr auto [arr0, arr1] = arr;
    static_assert(arr0 == 6);
    static_assert(arr1 == 7);

    constexpr info info_arr[] {^^::, ^^int};
    constexpr auto [ii1, ii2] = info_arr;
    static_assert(info_arr[0] == ^^::);
    static_assert(info_arr[1] == ^^int);
    static_assert(ii1 == ^^::); // error
    static_assert(ii2 == ^^int); // error
}

<source>: In function 'void foo()':
<source>:29:22: error: non-constant condition for static assertion
   29 |     static_assert(i1 == ^^::);
      |                   ~~~^~~~~~~
<source>:29:19: error: the value of 'i1' is not usable in a constant expression
   29 |     static_assert(i1 == ^^::);
      |                   ^~
<source>:25:21: note: 'i1' used in its own initializer
   25 |     constexpr auto [i1, i2] = i;
      |                     ^~
<source>:30:22: error: non-constant condition for static assertion
   30 |     static_assert(i2 == ^^int);
      |                   ~~~^~~~~~~~
<source>:30:19: error: the value of 'i2' is not usable in a constant expression
   30 |     static_assert(i2 == ^^int);
      |                   ^~
<source>:25:25: note: 'i2' used in its own initializer
   25 |     constexpr auto [i1, i2] = i;
      |                         ^~
<source>:45:23: error: non-constant condition for static assertion
   45 |     static_assert(ii1 == ^^::);
      |                   ~~~~^~~~~~~
<source>:45:19: error: the value of 'ii1' is not usable in a constant expression
   45 |     static_assert(ii1 == ^^::);
      |                   ^~~
<source>:41:21: note: 'ii1' used in its own initializer
   41 |     constexpr auto [ii1, ii2] = info_arr;
      |                     ^~~
<source>:46:23: error: non-constant condition for static assertion
   46 |     static_assert(ii2 == ^^int);
      |                   ~~~~^~~~~~~~
<source>:46:19: error: the value of 'ii2' is not usable in a constant expression
   46 |     static_assert(ii2 == ^^int);
      |                   ^~~
<source>:41:26: note: 'ii2' used in its own initializer
   41 |     constexpr auto [ii1, ii2] = info_arr;
      |                    

https://godbolt.org/z/hq1rf7aKv
Comment 22 Desmond Gold 2025-11-08 08:16:50 UTC
another one:

template <typename>
void foo() {
    constexpr int i = [:reflect_constant(5):];
    constexpr info f = reflect_constant_array(
        std::vector{1, 2, 3}
    );
    constexpr auto& arr = [:f:];
    constexpr auto& arr2 = [:reflect_constant_array(
        std::vector{1, 2, 3}
    ):];
}

void bar() {
    constexpr auto& arr = [:reflect_constant_array(
        std::vector{1, 2, 3}
    ):];   
}

results in ICE when splicing 'reflect_constant_array(...)' inside template definition (initializing 'arr2' inside 'foo'):

<source>: In function 'void foo()':
<source>:11:52: internal compiler error: in get_range_elts, at cp/reflect.cc:355
   11 |     constexpr auto& arr2 = [:reflect_constant_array(
      |                              ~~~~~~~~~~~~~~~~~~~~~~^
   12 |         std::vector{1, 2, 3}
      |         ~~~~~~~~~~~~~~~~~~~~                        
   13 |     ):];
      |     ~                                               
0x29213e8 diagnostics::context::diagnostic_impl(rich_location*, diagnostics::metadata const*, diagnostics::option_id, char const*, __va_list_tag (*) [1], diagnostics::kind)
	???:0
0x29161db internal_error(char const*, ...)
	???:0
0xb13bf4 fancy_abort(char const*, int, char const*)
	???:0
0xdd40ec process_metafunction(constexpr_ctx const*, tree_node*, tree_node*, bool*, bool*, tree_node**)
	???:0
0xb80a41 cxx_eval_constant_expression(constexpr_ctx const*, tree_node*, value_cat, bool*, bool*, tree_node**)
	???:0
0xb92743 cxx_constant_value(tree_node*, tree_node*, int)
	???:0
0xdc5c7c splice(tree_node*)
	???:0
0xd502d3 c_parse_file()
	???:0
0xed74c9 c_common_parse_file()
	???:0

https://godbolt.org/z/qP8988P5b
Comment 23 Marek Polacek 2025-11-11 15:59:03 UTC
Thanks again.  #20 and #21 are now fixed; #22 not yet.
Comment 24 Jakub Jelinek 2025-11-11 16:02:56 UTC
(In reply to Desmond Gold from comment #22)
> https://godbolt.org/z/qP8988P5b

#include <meta>

using namespace std::meta;

template <typename>
void
foo ()
{
  constexpr int i = [: reflect_constant (5) :];
  constexpr info f = reflect_constant_array (std::vector { 1, 2, 3 });
  constexpr auto &arr = [: f :];
  constexpr auto &arr2 = [: reflect_constant_array (std::vector { 1, 2, 3 }) :];
}

void
bar ()
{
  constexpr auto &arr = [: reflect_constant_array (std::vector { 1, 2, 3 }) :];   
}

int
main ()
{
}

splice calls cxx_constant_value when processing_template_decl, that looks unexpected, I think normally we'd call fold_non_dependent_expr instead when processing_template_decl.
Anyway, the ICE is because get_range_elts sees the processing_template_decl specific trees like CAST_EXPR with std::vector <int> type instead of the expected const std::vector <int> &&.
Comment 25 Marek Polacek 2025-11-11 16:07:47 UTC
(In reply to Jakub Jelinek from comment #24)
> (In reply to Desmond Gold from comment #22)
> > https://godbolt.org/z/qP8988P5b
> 
> #include <meta>
> 
> using namespace std::meta;
> 
> template <typename>
> void
> foo ()
> {
>   constexpr int i = [: reflect_constant (5) :];
>   constexpr info f = reflect_constant_array (std::vector { 1, 2, 3 });
>   constexpr auto &arr = [: f :];
>   constexpr auto &arr2 = [: reflect_constant_array (std::vector { 1, 2, 3 })
> :];
> }
> 
> void
> bar ()
> {
>   constexpr auto &arr = [: reflect_constant_array (std::vector { 1, 2, 3 })
> :];   
> }
> 
> int
> main ()
> {
> }
> 
> splice calls cxx_constant_value when processing_template_decl, that looks
> unexpected, I think normally we'd call fold_non_dependent_expr instead when
> processing_template_decl.
> Anyway, the ICE is because get_range_elts sees the processing_template_decl
> specific trees like CAST_EXPR with std::vector <int> type instead of the
> expected const std::vector <int> &&.

Yes, but I got a crash on the
  gcc_checking_assert (TYPE_REF_P (type));
even when I do tsubst the arg, which is why I haven't fixed this yet :(
Comment 26 Jakub Jelinek 2025-11-11 16:16:23 UTC
https://forge.sourceware.org/marek/gcc/pulls/96 seems to fix that, shall I merge that or do you want something else?
Comment 27 Marek Polacek 2025-11-11 16:49:58 UTC
(In reply to Jakub Jelinek from comment #26)
> https://forge.sourceware.org/marek/gcc/pulls/96 seems to fix that, shall I
> merge that or do you want something else?

Could we do just

-  refl = cxx_constant_value (refl);
+  refl = fold_non_dependent_expr (refl, tf_warning_or_error,
+                 /*manifestly_const_eval=*/true);

?
Comment 28 Jakub Jelinek 2025-11-11 16:57:08 UTC
(In reply to Marek Polacek from comment #27)
> (In reply to Jakub Jelinek from comment #26)
> > https://forge.sourceware.org/marek/gcc/pulls/96 seems to fix that, shall I
> > merge that or do you want something else?
> 
> Could we do just
> 
> -  refl = cxx_constant_value (refl);
> +  refl = fold_non_dependent_expr (refl, tf_warning_or_error,
> +                 /*manifestly_const_eval=*/true);
> 
> ?

I think we can't.  One, I think we need to handle the processing_template_decl case more carefully, if it isn't constant, just revert to building SPLICE_EXPR, while for !processing_template_decl we want to error.  And fold_non_dependent_expr calls maybe_constant_value instead of cxx_constant_value, so while it is mce_true as well, it doesn't report errors, just silently returns non-constant.
Comment 29 Marek Polacek 2025-11-11 17:26:34 UTC
If REFL is non-dependent, then I think we should error even in a template, because there won't be a valid instantiation?

Fair enough on the second point, but that could be fixed by adding

  if (require_constant_expression (refl))
    cxx_constant_value (refl);
  
maybe?
Comment 30 Jakub Jelinek 2025-11-11 17:48:58 UTC
Playing around, just pure
-  refl = cxx_constant_value (refl);
+  refl = fold_non_dependent_expr (refl, tf_warning_or_error, true);
fixes the testcase too (and nothing in testsuite fails), but I'd think I'd still prefer
-  refl = cxx_constant_value (refl);
+  if (processing_template_decl)
+    refl = fold_non_dependent_expr (refl, tf_warning_or_error, true);
+  else
+    refl = cxx_constant_value (refl);
because it can give better diagnostics outside of template.
Comment 31 Marek Polacek 2025-11-11 17:50:42 UTC
OK, I'm fine with #30.  Thanks.
Comment 32 friedkeenan 2025-11-12 10:36:49 UTC
Not sure if this is already a known bug (I don't think it's listed here at least, but if I'm wrong, then I apologize), but the following code currently causes an ICE:

#include <meta>

template<typename T>
void func() {
    constexpr auto ctx = std::meta::access_context::unprivileged();
}

Godbolt link: https://godbolt.org/z/r1xE6b6Yx


The ICE also occurs with ::unchecked() in place of ::unprivileged(), but not with ::current().

The ICE only occurs when the function is a template function, and only when the ctx variable is constexpr, whether it's static or not.

(Also thank you all for your work, it is both very impressive and very appreciated!)
Comment 33 Jakub Jelinek 2025-11-12 12:28:33 UTC
(In reply to friedkeenan from comment #32)
> Not sure if this is already a known bug (I don't think it's listed here at
> least, but if I'm wrong, then I apologize), but the following code currently
> causes an ICE:
> 
> #include <meta>
> 
> template<typename T>
> void func() {
>     constexpr auto ctx = std::meta::access_context::unprivileged();
> }

Doesn't actually need anything from <meta> in that case,
struct S {
  using info = decltype (^^int);
  consteval S (info x) noexcept : a {x} { }
  consteval S (const S &) = default;
  static consteval S bar () noexcept { return S { info {} }; }
  info a;
};

template <typename T>
void foo ()
{
  constexpr auto ctx = S::bar ();
}
ICEs too.
Commenting out the defaulted copy constructor fixes this.

And, it doesn't need reflection either,
struct S {
  consteval S (int x) noexcept : a {x} { }
  consteval S (const S &) = default;
  static consteval S bar () noexcept { return S { int {} }; }
  int a;
};

template <typename T>
void
foo ()
{
  constexpr auto s = S::bar ();
}
ICEs too and doesn't need reflection branch, so let me file that separately.
Comment 34 friedkeenan 2025-11-12 12:35:08 UTC
(In reply to Jakub Jelinek from comment #33)
> And, it doesn't need reflection either,
> struct S {
>   consteval S (int x) noexcept : a {x} { }
>   consteval S (const S &) = default;
>   static consteval S bar () noexcept { return S { int {} }; }
>   int a;
> };
> 
> template <typename T>
> void
> foo ()
> {
>   constexpr auto s = S::bar ();
> }
> ICEs too and doesn't need reflection branch, so let me file that separately.

Ah, strange. I guess it might be out of scope of the reflection branch then, yeah. Thanks for taking a look!
Comment 35 Jakub Jelinek 2025-11-12 12:37:31 UTC
I've moved #c32/#c33/#c34 to PR122658.
Comment 36 Boris Staletic 2025-11-14 18:37:53 UTC
I've gone through all of the examples in P2996 and found five errors preventing Marek's fork from compiling all of them.

See: https://godbolt.org/z/chYM1zPbh

To elaborate:

- The first error is not related to reflections, but has to do with constexpr reference to local.
- The second error, I'm not sure, but could also be outside of the scope of reflections and more to do with expansion statements.
- The third error is finicky. Changing the formatting can make it go away. It prevents, sometimes, expressions like `obj.[:members[Is]:]...`, where `Is` is a pack from an index sequence.
- The fourth says `obj.[:member_refl:]` is ambiguous when `obj` has multiple members named `_`. According to P2996, name lookup shouldn't be performed.
- Finally, there's an ICE when trying to call `access_context::unchecked()` from inside a template.

Regarding "no name lookup", P2996 says this:

> Note that a “member access splice” like s.[:member_number(1):] is a more direct
> member access mechanism than the traditional syntax. It doesn’t involve member
> name lookup, access checking, or — if the spliced reflection value represents a
> member function — overload resolution.

I also have a library that relies on C++26 reflections, but I have not yet tried to compile it with Marek's fork, as patterns like those that trigger the second and third error above do show up in my library.
Either way, the library is available at: https://codeberg.org/bstaletic/pymetabind
Comment 37 Jakub Jelinek 2025-11-14 19:30:30 UTC
(In reply to Boris Staletic from comment #36)
> I've gone through all of the examples in P2996 and found five errors
> preventing Marek's fork from compiling all of them.
> 
> See: https://godbolt.org/z/chYM1zPbh
> 
> To elaborate:
> 
> - The first error is not related to reflections, but has to do with
> constexpr reference to local.
> - The second error, I'm not sure, but could also be outside of the scope of
> reflections and more to do with expansion statements.
> - The third error is finicky. Changing the formatting can make it go away.
> It prevents, sometimes, expressions like `obj.[:members[Is]:]...`, where
> `Is` is a pack from an index sequence.
> - The fourth says `obj.[:member_refl:]` is ambiguous when `obj` has multiple
> members named `_`. According to P2996, name lookup shouldn't be performed.
> - Finally, there's an ICE when trying to call `access_context::unchecked()`
> from inside a template.
> 
> Regarding "no name lookup", P2996 says this:
> 
> > Note that a “member access splice” like s.[:member_number(1):] is a more direct
> > member access mechanism than the traditional syntax. It doesn’t involve member
> > name lookup, access checking, or — if the spliced reflection value represents a
> > member function — overload resolution.
> 
> I also have a library that relies on C++26 reflections, but I have not yet
> tried to compile it with Marek's fork, as patterns like those that trigger
> the second and third error above do show up in my library.
> Either way, the library is available at:
> https://codeberg.org/bstaletic/pymetabind

The ICE in tsubst_expr is likely PR122658.  
Regarding some cases of expansion statements, there is
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700380.html
patch waiting for review, but more importantly expansion statements are known not to work with define_static_array directly in the current expansion statement definition, see https://github.com/cplusplus/CWG/issues/805
I have a patch in testing for that but I think the CWG needs to decide first what they want.  A workaround that works for me is template for (constexpr auto m : (const std::span <const ...> define_static_array (...)).
The "_" case is a known issue, see e.g. https://forge.sourceware.org/marek/gcc/src/branch/reflection/gcc/testsuite/g++.dg/reflect/member15.C mentioning it or
the https://forge.sourceware.org/marek/gcc/commit/c9bc89c30bd7ade9e9c7d5d908c0d3272675ec08 commit message for details, I hope we'll work on that next week.
Comment 38 Boris Staletic 2025-11-14 20:06:54 UTC
Jakub, thanks for the quick reply.

So, the ICE, the the expansion statements and the `_`-named members aside (as those are known and being worked on), I see that I failed to provide a repro for error 3 from my previous comment.
I don't know what happened and why it started working...
Anyway, that error was supposed to be distilled from P2996's "struct to tuple" example.

Here's the actual error: https://godbolt.org/z/dW4vbdKeM

If the line is changed from

        return std::make_tuple(t.[:members:]...);
to
        return std::make_tuple(t.*&[:members:]...);

The error changes to "lvalue required as unary '&' operand".

If this is known as well and there's a workaround, I can try the gcc reflection impl on my library over the weekend.
Comment 39 Marek Polacek 2025-11-15 00:42:14 UTC
Patches posted:
<https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700733.html>
Comment 40 Jakub Jelinek 2025-11-22 10:25:22 UTC
Regarding https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120775#c38 that testcase doesn't fail on godbolt now.
For expansion statements, there are patches posted and awaiting review:
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700380.html
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700703.html
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700762.html
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/701644.html
although the 3rd one only implements part of the https://wg21.link/cwg3131 proposed resolution.
And for _, https://forge.sourceware.org/marek/gcc/pulls/110 WIP implements hopefully the right handling for [expr.ref] splicing for data members, but not yet for member functions (and likely neither for static data member templates).
Comment 41 Boris Staletic 2025-11-24 03:00:01 UTC
> Regarding https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120775#c38 that testcase doesn't fail on godbolt now.

True. I can't repro it either. Though the "lvalue required as unary '&' operand" in case of `t.*&[:member:]` still remains.

I managed to reduce the testcase further:

```
#include <meta>

struct S { int x; };

template<typename T>
auto test_address_of_spliced_member(T) {
    &[:nonstatic_data_members_of(^^T, std::meta::access_context::current())[0]:];
}

int main() {
    test_address_of_spliced_member(S{});
}
```

I have also ran into a new problem:

```
#include <meta>

template<size_t...Is>
void test1() {
    static constexpr std::meta::info types[]{^^int};
    [](typename[:types[Is]:]... args) {};
}
```

The error says "expansion pattern '[: types[Is] :]' contains no parameter packs".
I will attach both test cases as preprocessed files.
Comment 42 Boris Staletic 2025-11-24 03:07:54 UTC
Created attachment 62890 [details]
pack expansion containing a splice expression, containing a range indexed by a pack of size_t

Without `static` in `types` declaration, the error is:

```
foo.cpp:6:18: error: use of local variable with automatic storage from containing function [-Wtemplate-body]
    6 |     [](typename[:types[Is]:]... args) {};
      |                  ^~~~~
foo.cpp:5:31: note: 'constexpr const std::meta::info types [1]' declared here
    5 |     constexpr std::meta::info types[]{^^int};
      |                               ^~~~~
foo.cpp:6:29: error: reflection not usable in a splice type before '...' token [-Wtemplate-body]
    6 |     [](typename[:types[Is]:]... args) {};
      |                             ^~~
```

With `static` in the declaration of `types`, the error becomes

```
foo.cpp:6:33: error: expansion pattern '[: types[Is] :]' contains no parameter packs [-Wtemplate-body]
    6 |     [](typename[:types[Is]:]... args) {};
      |                                 ^~~~
```
Comment 43 Boris Staletic 2025-11-24 03:13:04 UTC
Created attachment 62891 [details]
splice expression value category

Error from the value category testcase:

```
bar.cpp: In instantiation of 'auto test_address_of_spliced_member(T) [with T = S]':
required from here
bar.cpp:11:35:
   11 |     test_address_of_spliced_member(S{});
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
bar.cpp:7:5: error: lvalue required as unary '&' operand
    7 |     &[:nonstatic_data_members_of(^^T, std::meta::access_context::current())[0]:];
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
Comment 44 Marek Polacek 2025-11-24 15:18:03 UTC
Thanks a lot for the test cases!  We should be able to take care of them once Reflection is merged (I don't want to change the branch when it's under review).
Comment 45 GCC Commits 2026-01-15 15:25:23 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:4b0e94b394fa38cdc3431f3cfb333b85373bd948

commit r16-6808-g4b0e94b394fa38cdc3431f3cfb333b85373bd948
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Jan 14 11:37:39 2026 -0500

    c++: C++26 Reflection [PR120775]
    
    This patch implements C++26 Reflection as specified by P2996R13, which allows
    users to perform magic.  This patch also implements related papers:
    Annotations for Reflection (P3394R4),
    Splicing a base class subobject (P3293R3),
    define_static_{string,object,array} (P3491R3),
    Function Parameter Reflection (P3096R12).
    (I already implemented consteval blocks back in July.)
    (We do not yet implement P3795.)
    
    We also implemented some CWG issues that had been approved in Kona;
    e.g., CWG 3101, 3109, 3111, 3115, 3117.
    
    All metafunctions are implemented in this patch.
    
    The feature needs to be enabled by -std=c++26 -freflection.
    
    Some stats: the v1 patch was over 51,200 LOC which were written in ~335
    commits.  It came with over 400 tests with 11,722 static_asserts.  We still
    had about 50 TODOs and FIXMEs in the code.
    v2 consists of about 56,000 LOC which were created in 440 commits.  We
    now have 446 tests with 40 TODOs remaining.
    v3 brought another 77 commits, mostly clean-ups and various bug fixes.
    
    I'd like to thank:
    Jakub Jelinek, whose efforts can only be described as heroic and who
    never ceases to amaze me even after nearly 15 years of working together,
    he implemented many difficult metafunctions, annotations, mangling,
    converted our metafunction dispatch to using gperf, and so on and on;
    Jonathan Wakely for his libstdc++ patch review and generous & impeccable
    advice even at odd hours; Dan Katz for his work on the Reflection papers,
    writing Reflection tests for clang++ (many of which I've stolen^Wused),
    for his advice, bug reports, and generally cheering me on; Jason Merrill
    for his guidance, patch review, and, in fact, encouraging me to take on
    this project in the first place; Michael Levine, Valentyn Yukhymenko, and
    Alex Yesmanchyk for their nice contributions to Reflection; and Tomasz
    KamiÅski for providing test cases, finding bugs, and answering my C++
    questions.
    
            PR c++/120775
            PR c++/123081
            PR c++/122634
    
    gcc/ChangeLog:
    
            * attribs.cc (attribute_value_equal): Return false if either attribute
            is ATTR_UNIQUE_VALUE_P.
            (merge_attributes): Handle lists with ATTR_UNIQUE_VALUE_P values.
            * doc/invoke.texi: Document -freflection.
            * dwarf2out.cc (is_base_type) <case default>: Check
            TREE_CODE >= LAST_AND_UNUSED_TREE_CODE instead of is_cxx_auto.
            (gen_type_die_with_usage): For TREE_CODE >= LAST_AND_UNUSED_TREE_CODE
            trees use use DW_TAG_unspecified_type.
            * tree-core.h (struct tree_base): Update a comment.
            * tree.h (ATTR_UNIQUE_VALUE_P): Define.
            (BINFO_BASE_ACCESSES): Update the comment.
    
    gcc/c-family/ChangeLog:
    
            * c-attribs.cc (attribute_takes_identifier_p): Return false for C++
            annotations.  Handle "old parm name".
            * c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_impl_reflection.
            * c.opt (freflection): New.
    
    gcc/cp/ChangeLog:
    
            * Make-lang.in: Add cp/reflect.o.  Add a rule for cp/metafns.h.
            * config-lang.in: Add reflect.cc.
            * constexpr.cc (constexpr_global_ctx): Add consteval_block and
            metafns_called members.  Initialize them.
            (cxx_constexpr_quiet_p): New.
            (cxx_constexpr_manifestly_const_eval): New.
            (cxx_constexpr_caller): New.
            (cxx_constexpr_consteval_block): New.
            (enum value_cat): Move into cp-tree.h.
            (cxx_eval_constant_expression): Move the declaration into cp-tree.h.
            No longer static.  Handle REFLECT_EXPR.  Handle conversion of
            a reflection to the meta::info type.
            (cxx_eval_cxa_builtin_fn): Override current_function_decl.
            (cxx_eval_builtin_function_call): Handle __builtin_is_string_literal.
            (is_std_allocator): Also check __new_allocator.
            (is_std_allocator_allocate): No longer static.
            (cxa_allocate_and_throw_exception): New.
            (cxx_eval_call_expression): Handle metafunctions.  Maybe set
            metafns_called.
            (reduced_constant_expression_p): Handle REFLECT_EXPR.
            (cxx_eval_binary_expression): Use compare_reflections for comparing
            reflections.
            (find_immediate_fndecl): Don't walk REFLECT_EXPR_P.
            (cxx_eval_outermost_constant_expr): Set global_ctx.consteval_block.
            Detect consteval-only smuggling.
            (potential_constant_expression_1): Return true for REFLECT_EXPR
            and SPLICE_EXPR.
            * constraint.cc (diagnose_trait_expr): Add CPTK_IS_CONSTEVAL_ONLY case.
            * cp-gimplify.cc (immediate_escalating_function_p): No longer static.
            (promote_function_to_consteval): Likewise.
            (cp_gimplify_expr) <case CALL_EXPR>: Detect any surviving consteval-only
            expressions.
            <case CP_BUILT_IN_IS_STRING_LITERAL>: Handle.
            (wipe_consteval_only_r): New.
            (cp_fold_immediate_r): Detect invalid uses of consteval-only types.
            Clear consteval-only DECL_EXPRs.
            (cp_genericize_r): Wipe consteval-only vars from BIND_EXPR_VARS and
            BLOCK_VARS.
            * cp-objcp-common.cc (cp_common_init_ts): Mark META_TYPE, SPLICE_SCOPE,
            SPLICE_EXPR, and REFLECT_EXPR.
            * cp-trait.def (IS_CONSTEVAL_ONLY): New trait.
            * cp-tree.def (REFLECT_EXPR, META_TYPE, SPLICE_EXPR, SPLICE_SCOPE): New
            trees.
            * cp-tree.h (enum cp_tree_index): Add CPTI_ANNOTATION_IDENTIFIER,
            CPTI_STD_META, and CPTI_META_INFO_TYPE.
            (std_meta_node): Define.
            (meta_info_type_node): Define.
            (annotation_identifier): Define.
            (REFLECTION_TYPE_P): Define.
            (REFLECT_EXPR_P): Define.
            (REFLECT_EXPR_HANDLE): Define.
            (enum reflect_kind): New.
            (REFLECT_EXPR_KIND): Define.
            (SET_REFLECT_EXPR_KIND): Define.
            (SPLICE_EXPR_EXPRESSION_P): Define.
            (SET_SPLICE_EXPR_EXPRESSION_P): Define.
            (SPLICE_EXPR_MEMBER_ACCESS_P): Define.
            (SET_SPLICE_EXPR_MEMBER_ACCESS_P): Define.
            (SPLICE_EXPR_ADDRESS_P): Define.
            (SET_SPLICE_EXPR_ADDRESS_P): Define.
            (SPLICE_SCOPE_EXPR): Define.
            (SPLICE_SCOPE_TYPE_P): Define.
            (WILDCARD_TYPE_P): Include SPLICE_SCOPE.
            (COMPONENT_REF_SPLICE_P): Define.
            (SCALAR_TYPE_P): Include REFLECTION_TYPE_P.
            (ENUM_BEING_DEFINED_P): Define.
            (OLD_PARM_DECL_P): Define.
            (MULTIPLE_NAMES_PARM_P): Define.
            (cp_preserve_using_decl): Declare.
            (DEF_OPERATOR, DEF_ASSN_OPERATOR): Include META.
            (struct ovl_op_info_t): Add meta_name member.
            (enum cp_built_in_function): Add CP_BUILT_IN_IS_STRING_LITERAL.
            (build_stub_type): Declare.
            (current_function_decl_without_access_scope): Declare.
            (dependent_namespace_p): Declare.
            (convert_reflect_constant_arg): Declare.
            (finish_base_specifier): Adjust declaration.
            (parsing_lambda_declarator): Declare.
            (fold_builtin_is_string_literal): Declare.
            (annotation_p): Declare.
            (finish_class_member_access_expr): Adjust declaration.
            (immediate_escalating_function_p): Declare.
            (promote_function_to_consteval): Declare.
            (is_std_allocator_allocate): Declare.
            (cxa_allocate_and_throw_exception): Declare.
            (enum value_cat): Define.
            (cxx_eval_constant_expression): Declare.
            (cxx_constexpr_quiet_p): Declare.
            (cxx_constexpr_manifestly_const_eval): Declare.
            (cxx_constexpr_caller): Declare.
            (cxx_constexpr_consteval_block): Declare.
            (init_reflection): Declare.
            (metafunction_p): Declare.
            (direct_base_parent): Declare.
            (process_metafunction): Declare.
            (get_reflection): Declare.
            (get_null_reflection): Declare.
            (splice): Declare.
            (check_out_of_consteval_use): Declare.
            (consteval_only_p): Declare.
            (compare_reflections): Declare.
            (valid_splice_type_p): Declare.
            (valid_splice_scope_p): Declare.
            (check_splice_expr): Declare.
            (make_splice_scope): Declare.
            (dependent_splice_p): Declare.
            (reflection_mangle_prefix): Declare.
            (check_consteval_only_fn): Declare.
            * cvt.cc (convert_to_void): Call check_out_of_consteval_use.
            * cxx-pretty-print.cc (cxx_pretty_printer::unary_expression): New
            REFLECT_EXPR case.
            (cxx_pretty_printer::expression): Likewise.
            (cxx_pretty_printer::simple_type_specifier): New META_TYPE case.
            (cxx_pretty_printer::type_id): Likewise.
            * decl.cc (duplicate_decls): Merge parameter names for Reflection.
            Maybe set OLD_PARM_DECL_P.
            (initialize_predefined_identifiers): Add "annotation ".
            (cxx_init_decl_processing): Add __builtin_is_string_literal.  Call
            init_reflection.
            (maybe_commonize_var): Do nothing for consteval_only_p.
            (check_initializer): Default-initialize std::meta::info.
            (make_rtl_for_nonlocal_decl): For consteval_only_p vars, set
            DECL_EXTERNAL and return early.
            (cp_finish_decl): Call check_out_of_consteval_use.  Don't go
            creating a varpool node for consteval_only_p.
            (get_tuple_size): Check the instantiation instead of the type.
            (grokfndecl): Call check_consteval_only_fn.
            (xref_basetypes): Stitch annotations onto BINFO_BASE_ACCESSES.
            (finish_enum_value_list): Clear ENUM_BEING_DEFINED_P.
            * decl2.cc (is_late_template_attribute): Handle all annotations as
            late.
            (cp_check_const_attributes): Don't handle annotations here.
            (maybe_make_one_only): Do nothing for consteval_only_p.
            (mark_needed): Likewise.
            (min_vis_expr_r): Handle reflections.
            (prune_vars_needing_no_initialization): Skip consteval_only_p.
            (no_linkage_error): Return early for metafunctions.
            (c_parse_final_cleanups): Don't write out consteval_only_p vars.  Avoid
            complaining about metafunctions.
            * error.cc (dump_type): New cases for CONST_DECL, META_TYPE, and
            SPLICE_SCOPE.
            (dump_type_prefix): New cases for META_TYPE and SPLICE_SCOPE.
            (dump_type_suffix): Likewise.
            (dump_decl): Dump SPLICE_EXPR.
            (dump_expr): Dump REFLECT_EXPR and SPLICE_EXPR.
            * init.cc (build_zero_init_1): Build a null reflection value.
            (perform_member_init): Call check_out_of_consteval_use.
            * lex.cc (DEF_OPERATOR, OPERATOR_TRANSITION): Update defines.
            * mangle.cc (write_type): Mangle META_TYPE.
            (write_expression): Handle REFLECT_EXPR.
            (write_reflection): New.
            (write_template_arg_literal): New REFLECT_EXPR case.
            (write_template_arg): Handle REFLECT_EXPR.
            * method.cc (build_stub_type): No longer static.
            * module.cc (trees_out::type_node): Handle META_TYPE.
            (trees_in::tree_node): Likewise.
            * name-lookup.cc (name_lookup::adl_type): std::meta is an associated
            namespace of std::meta::info.
            (strip_using_decl): Don't strip when cp_preserve_using_decl.
            (handle_namespace_attrs): Handle annotations.
            (do_namespace_alias): Handle SPLICE_EXPR.
            (lookup_qualified_name): When cp_preserve_using_decl, don't do
            OVL_FUNCTION.
            (finish_using_directive): Detect annotations on using directive.
            * operators.def: Update for META_NAME.
            * parser.cc: New cp_preserve_using_decl global.
            (enum required_token): Add RT_CLOSE_SPLICE.
            (get_required_cpp_ttype): Return CPP_CLOSE_SPLICE for RT_CLOSE_SPLICE.
            (cp_parser_next_tokens_start_splice_type_spec_p): New.
            (cp_parser_next_tokens_can_start_splice_scope_spec_p): New.
            (cp_parser_splice_specifier): New.
            (cp_parser_splice_type_specifier): New.
            (cp_parser_splice_expression): New.
            (cp_parser_splice_scope_specifier): New.
            (cp_parser_splice_spec_is_nns_p): New.
            (cp_parser_nth_token_starts_splice_without_nns_p): New.
            (cp_parser_primary_expression): Handle CPP_OPEN_SPLICE.  Give an
            error for ^^ outside reflection.
            (cp_parser_unqualified_id): Allow r.~typename [:R:].
            (cp_parser_nested_name_specifier_opt): Cope with splice-scope-specifier.
            (cp_parser_qualifying_entity): Parse splice-scope-specifier.
            (cp_parser_postfix_expression): Deal with [: :] after a typename.
            (cp_parser_postfix_dot_deref_expression): Parse & handle splices
            in a class member access.  Pass splice_p to
            finish_class_member_access_expr.
            (cp_parser_reflection_name): New.
            (cp_parser_reflect_expression): New.
            (cp_parser_unary_expression): Parse reflect-expression.
            (cp_parser_declaration): Parse splice-scope-specifier.
            (cp_parser_decomposition_declaration): Detect annotations on structured
            bindings.
            (cp_parser_decltype_expr): Parse splice-expression.
            (cp_parser_template_id): New parsed_templ argument.  If it's nonnull,
            don't parse the template name.  Turn an assert into a condition.
            (cp_parser_type_specifier): Handle typename [: :].
            (cp_parser_simple_type_specifier): Parse splice-type-specifier.
            (cp_parser_enum_specifier): Set ENUM_BEING_DEFINED_P.
            (cp_parser_namespace_alias_definition): Parse splice-specifier.
            (cp_parser_using_directive): Likewise.
            (cp_parser_type_id_1): New bool * parameter to distinguish between
            types and type aliases.  Set it.
            (cp_parser_type_id): Adjust the call to cp_parser_type_id_1.
            (cp_parser_template_type_arg): Likewise.
            (cp_parser_trailing_type_id): Likewise.
            (cp_parser_base_specifier): Handle annotations.  Maybe give an error
            for splice-scope-specifier.  Parse splice-type-specifier.  Pass
            annotations to finish_base_specifier.
            (cp_parser_annotation): New.
            (cp_parser_std_attribute_list): Detect mixing annotations and attributes
            in the same list.
            (cp_parser_annotation_list): New.
            (cp_parser_std_attribute_spec): Parse annotations.
            (cp_parser_skip_balanced_tokens): Also handle CPP_OPEN_SPLICE
            and CPP_CLOSE_SPLICE.
            (cp_parser_type_requirement): Parse splice-type-specifier.
            (cp_parser_lookup_name): Also consider dependent namespaces.  Don't
            call check_accessibility_of_qualified_id for USING_DECLs.
            (cp_parser_required_error): Handle RT_CLOSE_SPLICE.
            * pt.cc (current_function_decl_without_access_scope): New.
            (verify_unstripped_args_1): REFLECT_EXPR_P is OK.
            (iterative_hash_template_arg): Handle REFLECT_EXPR.
            (convert_nontype_argument): Maybe give an error for REFLECTION_TYPE_P.
            (for_each_template_parm_r): Handle SPLICE_SCOPE.
            (instantiate_class_template): Handle annotations.
            (tsubst_pack_index): Make static.
            (tsubst_decl): Handle NAMESPACE_DECL.
            (tsubst_splice_scope): New.
            (tsubst_splice_expr): New.
            (tsubst): Don't return early for NAMESPACE_DECL.   New META_TYPE case.
            Handle a splice-specifier that expanded into a NAMESPACE_DECL.  Handle
            SPLICE_SCOPE, SPLICE_EXPR, and TEMPLATE_ID_EXPR.
            (tsubst_scope): Also accept NAMESPACE_DECL.
            (tsubst_qualified_id): Check dependent_namespace_p.
            (tsubst_lambda_expr): Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P.
            (tsubst_expr): Allow dependent_splice_p in an assert.  Check
            COMPONENT_REF_SPLICE_P and pass it to finish_class_member_access_expr.
            <case NAMESPACE_DECL>: Remove.
            New REFLECT_EXPR and SPLICE_EXPR cases.
            (unify): Handle META_TYPE.
            (instantiate_body): Call check_consteval_only_fn.
            (tsubst_enum): Set ENUM_BEING_DEFINED_P.
            (dependent_type_p_r): A splice-scope-specifier is dependent.
            (dependent_namespace_p): New.
            (value_dependent_expression_p): Handle REFLECT_EXPR.  Also handle
            [meta.reflection.access.context]/8.
            (type_dependent_expression_p): REFLECT_EXPR_P is not type-dependent.
            (convert_reflect_constant_arg): New.
            * search.cc (check_final_overrider): Adjust for CWG 3117.
            * semantics.cc (finish_base_specifier): Handle annotations.
            (parsing_lambda_declarator): No longer static.
            (finish_id_expression_1): Check dependent_namespace_p.
            (fold_builtin_is_string_literal): New.
            (trait_expr_value): Handle CPTK_IS_CONSTEVAL_ONLY.
            (finish_trait_expr): Likewise.
            * tree.cc (handle_annotation_attribute): New.
            (builtin_valid_in_constant_expr_p): Return true for
            CP_BUILT_IN_IS_STRING_LITERAL.
            (cp_tree_equal): Handle comparing REFLECT_EXPRs.
            (internal_attributes): Add "annotation ".
            (annotation_p): New.
            * typeck.cc (finish_class_member_access_expr): New splice_p argument.
            Handle dependent splices.  Implement splicing a base class subobject.
            Handle class member access using a splice-expression.
            (cp_build_binary_op): Handle comparing std::meta::infos.
            (check_return_expr): Call check_out_of_consteval_use.
            * metafns.gperf: New file.
            * metafns.h: New file.
            * reflect.cc: New file.
    
    libcc1/ChangeLog:
    
            * libcp1plugin.cc (start_class_def): Update the call to
            finish_base_specifier.
    
    libcpp/ChangeLog:
    
            * charset.cc (_cpp_destroy_iconv): Destroy narrow_cset_desc and
            utf8_cset_desc.
            (cpp_translate_string): New.
            (cpp_valid_identifier): New.
            * include/cpplib.h: Add OPEN_SPLICE, CLOSE_SPLICE, and REFLECT_OP to
            TTYPE_TABLE.
            (cpp_translate_string): Declare.
            (cpp_valid_identifier): Declare.
            * internal.h (struct cpp_reader): Add reverse_narrow_cset_desc and
            reverse_utf8_cset_desc fields.
            * lex.cc (_cpp_lex_direct): Emit CPP_CLOSE_SPLICE, CPP_REFLECT_OP,
            and CPP_OPEN_SPLICE tokens.
    
    libstdc++-v3/ChangeLog:
    
            * include/Makefile.am (std_headers): Add ${std_srcdir}/meta.
            * include/Makefile.in: Regenerate.
            * include/bits/iterator_concepts.h (std::ranges::__access::__begin): Add
            constexpr.
            * include/bits/version.def (reflection): New.
            * include/bits/version.h: Regenerate.
            * include/precompiled/stdc++.h: Include <meta> for C++26.
            * include/std/meta: New file.
            * include/std/type_traits (std::is_reflection): New trait.
            (std::is_fundamental): Include is_reflection for C++26 -freflection.
            (std::is_reflection_v): New variable template.
            (std::is_consteval_only): New trait.
            (std::is_consteval_only_v): New variable template.
            * src/c++23/std.cc.in: Add <meta> exports.
            * testsuite/20_util/variable_templates_for_traits.cc: Add -freflection as
            dg-additional-options for C++26.  Add std::is_reflection_v test in that case.
            * testsuite/20_util/is_consteval_only/requirements/explicit_instantiation.cc: New test.
            * testsuite/20_util/is_consteval_only/requirements/typedefs.cc: New test.
            * testsuite/20_util/is_consteval_only/value.cc: New test.
            * testsuite/20_util/is_reflection/requirements/explicit_instantiation.cc: New test.
            * testsuite/20_util/is_reflection/requirements/typedefs.cc: New test.
            * testsuite/20_util/is_reflection/value.cc: New test.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/DRs/dr2581-1.C: Add -freflection.
            * g++.dg/DRs/dr2581-2.C: Likewise.
            * g++.dg/reflect/access_context1.C: New test.
            * g++.dg/reflect/access_context2.C: New test.
            * g++.dg/reflect/access_context3.C: New test.
            * g++.dg/reflect/adl1.C: New test.
            * g++.dg/reflect/alignment_of1.C: New test.
            * g++.dg/reflect/alignment_of2.C: New test.
            * g++.dg/reflect/annotations1.C: New test.
            * g++.dg/reflect/annotations2.C: New test.
            * g++.dg/reflect/annotations3.C: New test.
            * g++.dg/reflect/annotations4.C: New test.
            * g++.dg/reflect/annotations5.C: New test.
            * g++.dg/reflect/annotations6.C: New test.
            * g++.dg/reflect/annotations7.C: New test.
            * g++.dg/reflect/annotations8.C: New test.
            * g++.dg/reflect/anon1.C: New test.
            * g++.dg/reflect/anon2.C: New test.
            * g++.dg/reflect/anon3.C: New test.
            * g++.dg/reflect/bases_of1.C: New test.
            * g++.dg/reflect/bases_of2.C: New test.
            * g++.dg/reflect/bases_of3.C: New test.
            * g++.dg/reflect/bit_size_of1.C: New test.
            * g++.dg/reflect/bitfield1.C: New test.
            * g++.dg/reflect/can_substitute1.C: New test.
            * g++.dg/reflect/class1.C: New test.
            * g++.dg/reflect/class2.C: New test.
            * g++.dg/reflect/common_reference1.C: New test.
            * g++.dg/reflect/common_type1.C: New test.
            * g++.dg/reflect/compare1.C: New test.
            * g++.dg/reflect/compare10.C: New test.
            * g++.dg/reflect/compare2.C: New test.
            * g++.dg/reflect/compare3.C: New test.
            * g++.dg/reflect/compare4.C: New test.
            * g++.dg/reflect/compare5.C: New test.
            * g++.dg/reflect/compare6.C: New test.
            * g++.dg/reflect/compare7.C: New test.
            * g++.dg/reflect/compare8.C: New test.
            * g++.dg/reflect/compare9.C: New test.
            * g++.dg/reflect/compat1.C: New test.
            * g++.dg/reflect/complete1.C: New test.
            * g++.dg/reflect/constant_of1.C: New test.
            * g++.dg/reflect/constant_of2.C: New test.
            * g++.dg/reflect/constant_of3.C: New test.
            * g++.dg/reflect/constant_of4.C: New test.
            * g++.dg/reflect/constant_of5.C: New test.
            * g++.dg/reflect/constant_of6.C: New test.
            * g++.dg/reflect/constant_of7.C: New test.
            * g++.dg/reflect/constant_of8.C: New test.
            * g++.dg/reflect/constant_of9.C: New test.
            * g++.dg/reflect/crash1.C: New test.
            * g++.dg/reflect/crash10.C: New test.
            * g++.dg/reflect/crash11.C: New test.
            * g++.dg/reflect/crash12.C: New test.
            * g++.dg/reflect/crash13.C: New test.
            * g++.dg/reflect/crash14.C: New test.
            * g++.dg/reflect/crash15.C: New test.
            * g++.dg/reflect/crash16.C: New test.
            * g++.dg/reflect/crash17.C: New test.
            * g++.dg/reflect/crash18.C: New test.
            * g++.dg/reflect/crash2.C: New test.
            * g++.dg/reflect/crash3.C: New test.
            * g++.dg/reflect/crash4.C: New test.
            * g++.dg/reflect/crash5.C: New test.
            * g++.dg/reflect/crash6.C: New test.
            * g++.dg/reflect/crash7.C: New test.
            * g++.dg/reflect/crash8.C: New test.
            * g++.dg/reflect/crash9.C: New test.
            * g++.dg/reflect/data_member_spec1.C: New test.
            * g++.dg/reflect/data_member_spec2.C: New test.
            * g++.dg/reflect/data_member_spec3.C: New test.
            * g++.dg/reflect/data_member_spec4.C: New test.
            * g++.dg/reflect/dealias1.C: New test.
            * g++.dg/reflect/dealias2.C: New test.
            * g++.dg/reflect/dealias3.C: New test.
            * g++.dg/reflect/define_aggregate1.C: New test.
            * g++.dg/reflect/define_aggregate2.C: New test.
            * g++.dg/reflect/define_aggregate3.C: New test.
            * g++.dg/reflect/define_aggregate4.C: New test.
            * g++.dg/reflect/define_aggregate5.C: New test.
            * g++.dg/reflect/define_static_array1.C: New test.
            * g++.dg/reflect/define_static_array2.C: New test.
            * g++.dg/reflect/define_static_array3.C: New test.
            * g++.dg/reflect/define_static_array4.C: New test.
            * g++.dg/reflect/define_static_object1.C: New test.
            * g++.dg/reflect/define_static_object2.C: New test.
            * g++.dg/reflect/define_static_string1.C: New test.
            * g++.dg/reflect/dep1.C: New test.
            * g++.dg/reflect/dep10.C: New test.
            * g++.dg/reflect/dep11.C: New test.
            * g++.dg/reflect/dep2.C: New test.
            * g++.dg/reflect/dep3.C: New test.
            * g++.dg/reflect/dep4.C: New test.
            * g++.dg/reflect/dep5.C: New test.
            * g++.dg/reflect/dep6.C: New test.
            * g++.dg/reflect/dep7.C: New test.
            * g++.dg/reflect/dep8.C: New test.
            * g++.dg/reflect/dep9.C: New test.
            * g++.dg/reflect/diag1.C: New test.
            * g++.dg/reflect/diag2.C: New test.
            * g++.dg/reflect/diag3.C: New test.
            * g++.dg/reflect/diag4.C: New test.
            * g++.dg/reflect/display_string_of1.C: New test.
            * g++.dg/reflect/eh1.C: New test.
            * g++.dg/reflect/eh2.C: New test.
            * g++.dg/reflect/eh3.C: New test.
            * g++.dg/reflect/eh4.C: New test.
            * g++.dg/reflect/eh5.C: New test.
            * g++.dg/reflect/eh6.C: New test.
            * g++.dg/reflect/eh7.C: New test.
            * g++.dg/reflect/eh8.C: New test.
            * g++.dg/reflect/eh9.C: New test.
            * g++.dg/reflect/enumerators_of1.C: New test.
            * g++.dg/reflect/error1.C: New test.
            * g++.dg/reflect/error10.C: New test.
            * g++.dg/reflect/error2.C: New test.
            * g++.dg/reflect/error3.C: New test.
            * g++.dg/reflect/error4.C: New test.
            * g++.dg/reflect/error5.C: New test.
            * g++.dg/reflect/error6.C: New test.
            * g++.dg/reflect/error8.C: New test.
            * g++.dg/reflect/error9.C: New test.
            * g++.dg/reflect/expr1.C: New test.
            * g++.dg/reflect/expr10.C: New test.
            * g++.dg/reflect/expr11.C: New test.
            * g++.dg/reflect/expr12.C: New test.
            * g++.dg/reflect/expr13.C: New test.
            * g++.dg/reflect/expr14.C: New test.
            * g++.dg/reflect/expr2.C: New test.
            * g++.dg/reflect/expr3.C: New test.
            * g++.dg/reflect/expr4.C: New test.
            * g++.dg/reflect/expr5.C: New test.
            * g++.dg/reflect/expr6.C: New test.
            * g++.dg/reflect/expr7.C: New test.
            * g++.dg/reflect/expr8.C: New test.
            * g++.dg/reflect/expr9.C: New test.
            * g++.dg/reflect/extract1.C: New test.
            * g++.dg/reflect/extract2.C: New test.
            * g++.dg/reflect/extract3.C: New test.
            * g++.dg/reflect/extract4.C: New test.
            * g++.dg/reflect/extract5.C: New test.
            * g++.dg/reflect/extract6.C: New test.
            * g++.dg/reflect/extract7.C: New test.
            * g++.dg/reflect/extract8.C: New test.
            * g++.dg/reflect/extract9.C: New test.
            * g++.dg/reflect/feat1.C: New test.
            * g++.dg/reflect/feat2.C: New test.
            * g++.dg/reflect/has_c_language_linkage1.C: New test.
            * g++.dg/reflect/has_default_argument1.C: New test.
            * g++.dg/reflect/has_default_argument2.C: New test.
            * g++.dg/reflect/has_default_member_initializer1.C: New test.
            * g++.dg/reflect/has_ellipsis_parameter1.C: New test.
            * g++.dg/reflect/has_external_linkage1.C: New test.
            * g++.dg/reflect/has_external_linkage2.C: New test.
            * g++.dg/reflect/has_identifier1.C: New test.
            * g++.dg/reflect/has_identifier2.C: New test.
            * g++.dg/reflect/has_internal_linkage1.C: New test.
            * g++.dg/reflect/has_internal_linkage2.C: New test.
            * g++.dg/reflect/has_linkage1.C: New test.
            * g++.dg/reflect/has_module_linkage1.C: New test.
            * g++.dg/reflect/has_module_linkage2.C: New test.
            * g++.dg/reflect/has_parent1.C: New test.
            * g++.dg/reflect/has_template_arguments1.C: New test.
            * g++.dg/reflect/has_template_arguments2.C: New test.
            * g++.dg/reflect/has_template_arguments3.C: New test.
            * g++.dg/reflect/has_template_arguments4.C: New test.
            * g++.dg/reflect/identifier_of1.C: New test.
            * g++.dg/reflect/identifier_of2.C: New test.
            * g++.dg/reflect/init1.C: New test.
            * g++.dg/reflect/init10.C: New test.
            * g++.dg/reflect/init11.C: New test.
            * g++.dg/reflect/init12.C: New test.
            * g++.dg/reflect/init13.C: New test.
            * g++.dg/reflect/init14.C: New test.
            * g++.dg/reflect/init15.C: New test.
            * g++.dg/reflect/init16.C: New test.
            * g++.dg/reflect/init17.C: New test.
            * g++.dg/reflect/init2.C: New test.
            * g++.dg/reflect/init3.C: New test.
            * g++.dg/reflect/init4.C: New test.
            * g++.dg/reflect/init5.C: New test.
            * g++.dg/reflect/init6.C: New test.
            * g++.dg/reflect/init7.C: New test.
            * g++.dg/reflect/init8.C: New test.
            * g++.dg/reflect/init9.C: New test.
            * g++.dg/reflect/is_accessible1.C: New test.
            * g++.dg/reflect/is_accessible2.C: New test.
            * g++.dg/reflect/is_alias_template1.C: New test.
            * g++.dg/reflect/is_assignment1.C: New test.
            * g++.dg/reflect/is_bit_field1.C: New test.
            * g++.dg/reflect/is_class_member1.C: New test.
            * g++.dg/reflect/is_class_template1.C: New test.
            * g++.dg/reflect/is_complete_type1.C: New test.
            * g++.dg/reflect/is_complete_type2.C: New test.
            * g++.dg/reflect/is_concept1.C: New test.
            * g++.dg/reflect/is_const1.C: New test.
            * g++.dg/reflect/is_consteval_only1.C: New test.
            * g++.dg/reflect/is_constructible_type1.C: New test.
            * g++.dg/reflect/is_constructible_type2.C: New test.
            * g++.dg/reflect/is_constructor_template1.C: New test.
            * g++.dg/reflect/is_constuctor1.C: New test.
            * g++.dg/reflect/is_conversion_function1.C: New test.
            * g++.dg/reflect/is_conversion_function_template1.C: New test.
            * g++.dg/reflect/is_copy_assignment1.C: New test.
            * g++.dg/reflect/is_copy_constructor1.C: New test.
            * g++.dg/reflect/is_data_member_spec1.C: New test.
            * g++.dg/reflect/is_default_constructor1.C: New test.
            * g++.dg/reflect/is_defaulted1.C: New test.
            * g++.dg/reflect/is_defaulted2.C: New test.
            * g++.dg/reflect/is_deleted1.C: New test.
            * g++.dg/reflect/is_deleted2.C: New test.
            * g++.dg/reflect/is_destructor1.C: New test.
            * g++.dg/reflect/is_enumerable_type1.C: New test.
            * g++.dg/reflect/is_enumerator1.C: New test.
            * g++.dg/reflect/is_explicit1.C: New test.
            * g++.dg/reflect/is_explicit2.C: New test.
            * g++.dg/reflect/is_explicit_object_parameter1.C: New test.
            * g++.dg/reflect/is_final1.C: New test.
            * g++.dg/reflect/is_function1.C: New test.
            * g++.dg/reflect/is_function2.C: New test.
            * g++.dg/reflect/is_function3.C: New test.
            * g++.dg/reflect/is_function_parameter1.C: New test.
            * g++.dg/reflect/is_function_parameter2.C: New test.
            * g++.dg/reflect/is_function_template1.C: New test.
            * g++.dg/reflect/is_function_template2.C: New test.
            * g++.dg/reflect/is_function_type1.C: New test.
            * g++.dg/reflect/is_literal_operator1.C: New test.
            * g++.dg/reflect/is_literal_operator_template1.C: New test.
            * g++.dg/reflect/is_lrvalue_reference_qualified1.C: New test.
            * g++.dg/reflect/is_move_assignment1.C: New test.
            * g++.dg/reflect/is_move_constructor1.C: New test.
            * g++.dg/reflect/is_mutable_member1.C: New test.
            * g++.dg/reflect/is_namespace1.C: New test.
            * g++.dg/reflect/is_namespace_alias1.C: New test.
            * g++.dg/reflect/is_namespace_member1.C: New test.
            * g++.dg/reflect/is_noexcept1.C: New test.
            * g++.dg/reflect/is_noexcept2.C: New test.
            * g++.dg/reflect/is_noexcept3.C: New test.
            * g++.dg/reflect/is_noexcept4.C: New test.
            * g++.dg/reflect/is_nonstatic_data_member1.C: New test.
            * g++.dg/reflect/is_object1.C: New test.
            * g++.dg/reflect/is_object2.C: New test.
            * g++.dg/reflect/is_operator_function1.C: New test.
            * g++.dg/reflect/is_operator_function_template1.C: New test.
            * g++.dg/reflect/is_override1.C: New test.
            * g++.dg/reflect/is_pure_virtual1.C: New test.
            * g++.dg/reflect/is_special_member_function1.C: New test.
            * g++.dg/reflect/is_static_member1.C: New test.
            * g++.dg/reflect/is_string_literal1.C: New test.
            * g++.dg/reflect/is_structured_binding1.C: New test.
            * g++.dg/reflect/is_structured_binding2.C: New test.
            * g++.dg/reflect/is_template1.C: New test.
            * g++.dg/reflect/is_template2.C: New test.
            * g++.dg/reflect/is_type1.C: New test.
            * g++.dg/reflect/is_type_alias1.C: New test.
            * g++.dg/reflect/is_type_alias2.C: New test.
            * g++.dg/reflect/is_type_alias3.C: New test.
            * g++.dg/reflect/is_user_declared1.C: New test.
            * g++.dg/reflect/is_user_declared2.C: New test.
            * g++.dg/reflect/is_user_provided1.C: New test.
            * g++.dg/reflect/is_user_provided2.C: New test.
            * g++.dg/reflect/is_variable1.C: New test.
            * g++.dg/reflect/is_variable_template1.C: New test.
            * g++.dg/reflect/is_virtual1.C: New test.
            * g++.dg/reflect/is_volatile1.C: New test.
            * g++.dg/reflect/lex1.C: New test.
            * g++.dg/reflect/lex2.C: New test.
            * g++.dg/reflect/mangle1.C: New test.
            * g++.dg/reflect/member-visibility1.C: New test.
            * g++.dg/reflect/member-visibility2.C: New test.
            * g++.dg/reflect/member1.C: New test.
            * g++.dg/reflect/member10.C: New test.
            * g++.dg/reflect/member11.C: New test.
            * g++.dg/reflect/member12.C: New test.
            * g++.dg/reflect/member13.C: New test.
            * g++.dg/reflect/member14.C: New test.
            * g++.dg/reflect/member15.C: New test.
            * g++.dg/reflect/member16.C: New test.
            * g++.dg/reflect/member17.C: New test.
            * g++.dg/reflect/member18.C: New test.
            * g++.dg/reflect/member19.C: New test.
            * g++.dg/reflect/member2.C: New test.
            * g++.dg/reflect/member20.C: New test.
            * g++.dg/reflect/member3.C: New test.
            * g++.dg/reflect/member4.C: New test.
            * g++.dg/reflect/member5.C: New test.
            * g++.dg/reflect/member6.C: New test.
            * g++.dg/reflect/member7.C: New test.
            * g++.dg/reflect/member8.C: New test.
            * g++.dg/reflect/member9.C: New test.
            * g++.dg/reflect/members_of1.C: New test.
            * g++.dg/reflect/members_of2.C: New test.
            * g++.dg/reflect/members_of3.C: New test.
            * g++.dg/reflect/members_of4.C: New test.
            * g++.dg/reflect/members_of5.C: New test.
            * g++.dg/reflect/members_of6.C: New test.
            * g++.dg/reflect/members_of7.C: New test.
            * g++.dg/reflect/metafn-ptr1.C: New test.
            * g++.dg/reflect/ns1.C: New test.
            * g++.dg/reflect/ns2.C: New test.
            * g++.dg/reflect/ns3.C: New test.
            * g++.dg/reflect/ns4.C: New test.
            * g++.dg/reflect/ns5.C: New test.
            * g++.dg/reflect/ns6.C: New test.
            * g++.dg/reflect/null1.C: New test.
            * g++.dg/reflect/null2.C: New test.
            * g++.dg/reflect/null3.C: New test.
            * g++.dg/reflect/null4.C: New test.
            * g++.dg/reflect/null5.C: New test.
            * g++.dg/reflect/object_of1.C: New test.
            * g++.dg/reflect/object_of2.C: New test.
            * g++.dg/reflect/odr1.C: New test.
            * g++.dg/reflect/offset_of1.C: New test.
            * g++.dg/reflect/operator_of1.C: New test.
            * g++.dg/reflect/override1.C: New test.
            * g++.dg/reflect/p2996-1.C: New test.
            * g++.dg/reflect/p2996-10.C: New test.
            * g++.dg/reflect/p2996-11.C: New test.
            * g++.dg/reflect/p2996-12.C: New test.
            * g++.dg/reflect/p2996-13.C: New test.
            * g++.dg/reflect/p2996-14.C: New test.
            * g++.dg/reflect/p2996-15.C: New test.
            * g++.dg/reflect/p2996-16.C: New test.
            * g++.dg/reflect/p2996-17.C: New test.
            * g++.dg/reflect/p2996-18.C: New test.
            * g++.dg/reflect/p2996-19.C: New test.
            * g++.dg/reflect/p2996-2.C: New test.
            * g++.dg/reflect/p2996-20.C: New test.
            * g++.dg/reflect/p2996-21.C: New test.
            * g++.dg/reflect/p2996-3.C: New test.
            * g++.dg/reflect/p2996-4.C: New test.
            * g++.dg/reflect/p2996-5.C: New test.
            * g++.dg/reflect/p2996-6.C: New test.
            * g++.dg/reflect/p2996-7.C: New test.
            * g++.dg/reflect/p2996-8.C: New test.
            * g++.dg/reflect/p2996-9.C: New test.
            * g++.dg/reflect/p3394-1.C: New test.
            * g++.dg/reflect/p3491-1.C: New test.
            * g++.dg/reflect/p3491-2.C: New test.
            * g++.dg/reflect/p3491-3.C: New test.
            * g++.dg/reflect/pack-index1.C: New test.
            * g++.dg/reflect/parameters_of1.C: New test.
            * g++.dg/reflect/parameters_of2.C: New test.
            * g++.dg/reflect/parameters_of3.C: New test.
            * g++.dg/reflect/parameters_of4.C: New test.
            * g++.dg/reflect/parameters_of5.C: New test.
            * g++.dg/reflect/parameters_of6.C: New test.
            * g++.dg/reflect/parent_of1.C: New test.
            * g++.dg/reflect/parm1.C: New test.
            * g++.dg/reflect/parm2.C: New test.
            * g++.dg/reflect/parm3.C: New test.
            * g++.dg/reflect/parm4.C: New test.
            * g++.dg/reflect/pr122634-1.C: New test.
            * g++.dg/reflect/pr122634-2.C: New test.
            * g++.dg/reflect/qrn1.C: New test.
            * g++.dg/reflect/qrn2.C: New test.
            * g++.dg/reflect/range_args.C: New test.
            * g++.dg/reflect/reflect_constant1.C: New test.
            * g++.dg/reflect/reflect_constant2.C: New test.
            * g++.dg/reflect/reflect_constant3.C: New test.
            * g++.dg/reflect/reflect_constant4.C: New test.
            * g++.dg/reflect/reflect_constant5.C: New test.
            * g++.dg/reflect/reflect_constant6.C: New test.
            * g++.dg/reflect/reflect_constant7.C: New test.
            * g++.dg/reflect/reflect_constant8.C: New test.
            * g++.dg/reflect/reflect_constant9.C: New test.
            * g++.dg/reflect/reflect_constant_array1.C: New test.
            * g++.dg/reflect/reflect_constant_array2.C: New test.
            * g++.dg/reflect/reflect_constant_array3.C: New test.
            * g++.dg/reflect/reflect_constant_array4.C: New test.
            * g++.dg/reflect/reflect_constant_string1.C: New test.
            * g++.dg/reflect/reflect_constant_string2.C: New test.
            * g++.dg/reflect/reflect_function1.C: New test.
            * g++.dg/reflect/reflect_function2.C: New test.
            * g++.dg/reflect/reflect_object1.C: New test.
            * g++.dg/reflect/reflect_object2.C: New test.
            * g++.dg/reflect/reflect_object3.C: New test.
            * g++.dg/reflect/reflect_object4.C: New test.
            * g++.dg/reflect/return_type_of1.C: New test.
            * g++.dg/reflect/return_type_of2.C: New test.
            * g++.dg/reflect/serialize1.C: New test.
            * g++.dg/reflect/serialize2.C: New test.
            * g++.dg/reflect/size_of1.C: New test.
            * g++.dg/reflect/source_location_of1.C: New test.
            * g++.dg/reflect/source_location_of2.C: New test.
            * g++.dg/reflect/splice1.C: New test.
            * g++.dg/reflect/splice2.C: New test.
            * g++.dg/reflect/splice3.C: New test.
            * g++.dg/reflect/splice4.C: New test.
            * g++.dg/reflect/splice5.C: New test.
            * g++.dg/reflect/splice6.C: New test.
            * g++.dg/reflect/splice7.C: New test.
            * g++.dg/reflect/splicing-base1.C: New test.
            * g++.dg/reflect/splicing-base2.C: New test.
            * g++.dg/reflect/splicing-base3.C: New test.
            * g++.dg/reflect/splicing-base4.C: New test.
            * g++.dg/reflect/storage_duration1.C: New test.
            * g++.dg/reflect/storage_duration2.C: New test.
            * g++.dg/reflect/storage_duration3.C: New test.
            * g++.dg/reflect/subobjects_of1.C: New test.
            * g++.dg/reflect/substitute1.C: New test.
            * g++.dg/reflect/substitute2.C: New test.
            * g++.dg/reflect/symbol_of1.C: New test.
            * g++.dg/reflect/symbol_of2.C: New test.
            * g++.dg/reflect/template_arguments_of1.C: New test.
            * g++.dg/reflect/template_arguments_of2.C: New test.
            * g++.dg/reflect/template_arguments_of3.C: New test.
            * g++.dg/reflect/template_of1.C: New test.
            * g++.dg/reflect/template_of2.C: New test.
            * g++.dg/reflect/template_of3.C: New test.
            * g++.dg/reflect/tuple1.C: New test.
            * g++.dg/reflect/tuple2.C: New test.
            * g++.dg/reflect/type1.C: New test.
            * g++.dg/reflect/type10.C: New test.
            * g++.dg/reflect/type2.C: New test.
            * g++.dg/reflect/type3.C: New test.
            * g++.dg/reflect/type4.C: New test.
            * g++.dg/reflect/type5.C: New test.
            * g++.dg/reflect/type6.C: New test.
            * g++.dg/reflect/type7.C: New test.
            * g++.dg/reflect/type8.C: New test.
            * g++.dg/reflect/type9.C: New test.
            * g++.dg/reflect/type_of1.C: New test.
            * g++.dg/reflect/type_of2.C: New test.
            * g++.dg/reflect/type_rels1.C: New test.
            * g++.dg/reflect/type_trait1.C: New test.
            * g++.dg/reflect/type_trait10.C: New test.
            * g++.dg/reflect/type_trait11.C: New test.
            * g++.dg/reflect/type_trait12.C: New test.
            * g++.dg/reflect/type_trait13.C: New test.
            * g++.dg/reflect/type_trait2.C: New test.
            * g++.dg/reflect/type_trait3.C: New test.
            * g++.dg/reflect/type_trait4.C: New test.
            * g++.dg/reflect/type_trait5.C: New test.
            * g++.dg/reflect/type_trait6.C: New test.
            * g++.dg/reflect/type_trait8.C: New test.
            * g++.dg/reflect/type_trait9.C: New test.
            * g++.dg/reflect/u8display_string_of1.C: New test.
            * g++.dg/reflect/u8identifier_of1.C: New test.
            * g++.dg/reflect/u8symbol_of1.C: New test.
            * g++.dg/reflect/underlying_type1.C: New test.
            * g++.dg/reflect/using1.C: New test.
            * g++.dg/reflect/value_or_object1.C: New test.
            * g++.dg/reflect/variable_of1.C: New test.
            * g++.dg/reflect/variable_of2.C: New test.
            * g++.dg/reflect/variable_of3.C: New test.
            * g++.dg/reflect/variant1.C: New test.
            * g++.dg/reflect/variant2.C: New test.
            * g++.dg/reflect/vector1.C: New test.
            * g++.dg/reflect/visibility1.C: New test.
    
    Co-authored-by: Jakub Jelinek <jakub@redhat.com>
    Signed-off-by: Valentyn Yukhymenko <vyuhimenko@bloomberg.net>
    Signed-off-by: Alex Yesmanchyk <ayesmanchyk@bloomberg.net>
    Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
    Reviewed-by: Jason Merrill <jason@redhat.com>
Comment 46 Marek Polacek 2026-01-15 15:42:04 UTC
Implemented for GCC 16.
Comment 47 Boris Staletic 2026-01-15 16:30:28 UTC
Besides comment #c42[1], I have found two (maybe three) additional bugs.

Should I make a new bug report, or just post them here?
Or maybe one bug report per test case?

I don't want to create spam, which is why I am asking.

[1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120775#c41
Comment 48 Sam James 2026-01-15 16:31:54 UTC
(In reply to Boris Staletic from comment #47)

Please go ahead w/ one bug per test case unless someone tells you otherwise, unless you have reason to believe they're genuinely the same problem. Thank you!
Comment 49 Marek Polacek 2026-01-15 16:32:21 UTC
(In reply to Boris Staletic from comment #47)
> Besides comment #c42[1], I have found two (maybe three) additional bugs.
> 
> Should I make a new bug report, or just post them here?
> Or maybe one bug report per test case?

This, please (one bug report per test case).  Thanks.