https://gcc.gnu.org/g:2065297fd2c5f90859efc113c08edd168a79a56d

commit r16-8942-g2065297fd2c5f90859efc113c08edd168a79a56d
Author: Jakub Jelinek <[email protected]>
Date:   Thu May 7 17:31:09 2026 +0200

    c++: Improve REFLECT_EXPR printing [PR125007]
    
    The following patch fixes REFLECT_EXPR printing.  Currently it prints 
everything
    as ^^ followed by dumping the decl/type/expr handle of the 
REFLECT_EXPR_HANDLE
    except the weird printing of data member specifications.
    E.g. annotations are printed as ^^ and dump_expr on the REFLECT_EXPR_HANDLE,
    which is a TREE_LIST so it prints the TREE_VALUE of TREE_VALUE of that in
    the end and prints e.g. reflection of [[=1]] as ^^1.
    The following patch prints reflections of annotations as ^^[[=1]] which is
    also not valid C++ syntax, but because the IL doesn't store the decl/type
    etc. in whose DECL_ATTRIBUTES/TYPE_ATTRIBUTES it appears, I'm afraid we
    can't do much better (like print annotations_of(^^something)[N]).
    For 
REFLECT_BASE/REFLECT_PARM/REFLECT_DATA_MEMBER_SPEC/REFLECT_VALUE/REFLECT_OBJECT,
    it attempts to use the C++ valid syntax, so prints
    bases_of(^^type,std::meta::access_context::unchecked())[N] {aka base_type}
    parameters_of(^^decl)[N] {aka param_name}
    data_member_spec(^^type,{.name="foo"})
    std::meta::reflect_constant(X)
    std::meta::reflect_object(X)
    etc.
    
    2026-05-07  Jakub Jelinek  <[email protected]>
    
            PR c++/125007
            * cp-tree.h (maybe_update_function_parm): Declare.
            * reflect.cc (maybe_update_function_parm): No longer static.
            * error.cc (dump_expr) <case REFLECT_EXPR>: Improve printing
            of various reflections.
    
            * g++.dg/reflect/pr125007.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>
    (cherry picked from commit e8aa21caed8a3c8b4b27d224a04296f008bcf3da)

Diff:
---
 gcc/cp/cp-tree.h                        |   1 +
 gcc/cp/error.cc                         | 159 +++++++++++++++++++++++++++++---
 gcc/cp/reflect.cc                       |   2 +-
 gcc/testsuite/g++.dg/reflect/pr125007.C |  46 +++++++++
 4 files changed, 195 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index cd37a931e4ab..8e2bdd756f58 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9508,6 +9508,7 @@ extern void coro_set_ramp_function                (tree, 
tree);
 
 /* In reflect.cc */
 extern void init_reflection ();
+extern tree maybe_update_function_parm (tree);
 extern bool metafunction_p (tree) ATTRIBUTE_PURE;
 extern tree direct_base_derived (tree) ATTRIBUTE_PURE;
 extern tree process_metafunction (const constexpr_ctx *, tree, tree,
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index e7121dc10175..a80b6e668922 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3331,21 +3331,156 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
 
     case REFLECT_EXPR:
       {
-       pp_string (pp, "^^");
        tree h = REFLECT_EXPR_HANDLE (t);
-       if (DECL_P (h))
-         dump_decl (pp, h, flags);
-       else if (TYPE_P (h))
-         dump_type (pp, h, flags);
-       else if (TREE_CODE (h) == TREE_VEC)
+       bool any;
+       switch (REFLECT_EXPR_KIND (t))
          {
-           pp_format_decoder (pp) = cp_printer;
-           pp->set_format_postprocessor
-             (std::make_unique<cxx_format_postprocessor> ());
-           dump_data_member_spec (pp, h);
+         case REFLECT_ANNOTATION:
+           pp_string (pp, "^^[[=");
+           pp->set_padding (pp_none);
+           dump_expr (pp, TREE_VALUE (TREE_VALUE (h)), flags);
+           pp_string (pp, "]]");
+           break;
+         case REFLECT_DATA_MEMBER_SPEC:
+           pp_cxx_ws_string (pp, "data_member_spec");
+           pp_string (pp, "(^^");
+           pp->set_padding (pp_none);
+           dump_type (pp, TREE_VEC_ELT (h, 0), flags);
+           pp_string (pp, ",{");
+           any = false;
+           if (TREE_VEC_ELT (h, 1))
+             {
+               pp_string (pp, ".name=");
+               pp_doublequote (pp);
+               pp->set_padding (pp_none);
+               dump_decl (pp, TREE_VEC_ELT (h, 1), flags);
+               pp_doublequote (pp);
+               any = true;
+             }
+           if (TREE_VEC_ELT (h, 2))
+             {
+               if (any)
+                 pp_comma (pp);
+               pp_string (pp, ".alignment=");
+               pp->set_padding (pp_none);
+               dump_expr (pp, TREE_VEC_ELT (h, 2), flags);
+               any = true;
+             }
+           if (TREE_VEC_ELT (h, 3))
+             {
+               if (any)
+                 pp_comma (pp);
+               pp_string (pp, ".bit_width=");
+               pp->set_padding (pp_none);
+               dump_expr (pp, TREE_VEC_ELT (h, 3), flags);
+               any = true;
+             }
+           if (TREE_VEC_ELT (h, 4) && !integer_zerop (TREE_VEC_ELT (h, 4)))
+             {
+               if (any)
+                 pp_comma (pp);
+               pp_string (pp, ".no_unique_address=");
+               pp->set_padding (pp_none);
+               dump_expr (pp, TREE_VEC_ELT (h, 4), flags);
+               any = true;
+             }
+           if (TREE_VEC_LENGTH (h) > 5)
+             {
+               if (any)
+                 pp_comma (pp);
+               pp_string (pp, ".annotations={");
+               pp->set_padding (pp_none);
+               for (int i = 5; i < TREE_VEC_LENGTH (h); ++i)
+                 {
+                   dump_expr (pp, TREE_VEC_ELT (h, i), flags);
+                   if (i != TREE_VEC_LENGTH (h) - 1)
+                     pp_comma (pp);
+                   pp->set_padding (pp_none);
+                 }
+               pp_right_brace (pp);
+             }
+           pp_string (pp, "})");
+           break;
+         case REFLECT_BASE:
+           {
+             pp_cxx_ws_string (pp, "bases_of");
+             pp_string (pp, "(^^");
+             pp->set_padding (pp_none);
+             tree d = direct_base_derived (h);
+             dump_type (pp, d, flags);
+             pp_string (pp, ",std::meta::access_context::unchecked())[");
+             pp->set_padding (pp_none);
+             tree binfo = TYPE_BINFO (d), base_binfo;
+             for (unsigned i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo);
+                  i++)
+               if (base_binfo == h)
+                 {
+                   pp_wide_integer (pp, i);
+                   break;
+                 }
+             pp_string (pp, "] {aka ");
+             pp->set_padding (pp_none);
+             dump_type (pp, BINFO_TYPE (h), flags);
+             pp_right_brace (pp);
+             break;
+           }
+         case REFLECT_PARM:
+           {
+             pp_cxx_ws_string (pp, "parameters_of");
+             pp_string (pp, "(^^");
+             pp->set_padding (pp_none);
+             h = maybe_update_function_parm (h);
+             dump_decl (pp, DECL_CONTEXT (h), flags);
+             pp_string (pp, ")[");
+             pp->set_padding (pp_none);
+             unsigned int i = 0;
+             for (tree arg = FUNCTION_FIRST_USER_PARM (DECL_CONTEXT (h));
+                  arg; arg = DECL_CHAIN (arg), ++i)
+               if (arg == h)
+                 {
+                   pp_wide_integer (pp, i);
+                   break;
+                 }
+             pp_right_bracket (pp);
+             if (MULTIPLE_NAMES_PARM_P (h))
+               break;
+             if (DECL_NAME (h))
+               h = DECL_NAME (h);
+             else if (tree opn = lookup_attribute ("old parm name",
+                                                   DECL_ATTRIBUTES (h)))
+               h = TREE_VALUE (TREE_VALUE (opn));
+             else
+               break;
+             pp_string (pp, " {aka ");
+             dump_decl (pp, h, flags);
+             pp_right_brace (pp);
+             break;
+           }
+         case REFLECT_OBJECT:
+           pp_cxx_ws_string (pp, "std::meta::reflect_object");
+           pp_left_paren (pp);
+           pp->set_padding (pp_none);
+           dump_expr (pp, h, flags);
+           pp_right_paren (pp);
+           break;
+         case REFLECT_VALUE:
+           pp_cxx_ws_string (pp, "std::meta::reflect_constant");
+           pp_left_paren (pp);
+           pp->set_padding (pp_none);
+           dump_expr (pp, h, flags);
+           pp_right_paren (pp);
+           break;
+         default:
+           pp_string (pp, "^^");
+           pp->set_padding (pp_none);
+           if (DECL_P (h))
+             dump_decl (pp, h, flags);
+           else if (TYPE_P (h))
+             dump_type (pp, h, flags);
+           else
+             dump_expr (pp, h, flags);
+           break;
          }
-       else
-         dump_expr (pp, h, flags);
        break;
       }
 
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 08d38a345c77..e1c49c944ade 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -295,7 +295,7 @@ maybe_strip_typedefs (tree t)
    DECL_ARGUMENTS (DECL_CONTEXT (parm)) chain.  Return corresponding
    PARM_DECL which is in the chain.  */
 
-static tree
+tree
 maybe_update_function_parm (tree parm)
 {
   if (!OLD_PARM_DECL_P (parm))
diff --git a/gcc/testsuite/g++.dg/reflect/pr125007.C 
b/gcc/testsuite/g++.dg/reflect/pr125007.C
new file mode 100644
index 000000000000..4ac0dfe03cc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/pr125007.C
@@ -0,0 +1,46 @@
+// PR c++/125007
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+[[=1]] void foo (int x, int y);
+[[=2]] void foo (int x, int z);
+
+struct A { int a; };
+struct B { int b; };
+struct C : public A, B {};
+struct D : public A, B {};
+
+constexpr auto ctx = std::meta::access_context::unchecked ();
+static_assert (annotations_of (^^foo)[0] == annotations_of (^^foo)[1]);        
// { dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(\\\^\\\^\\\[\\\[=1\\\]\\\] == \\\^\\\^\\\[\\\[=2\\\]\\\]\\\)'" "" { target 
*-*-* } .-1 }
+static_assert (parameters_of (^^foo)[0] == parameters_of (^^foo)[1]);  // { 
dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(parameters_of\\\(\\\^\\\^foo\\\(int, int\\\)\\\)\\\[0\\\] \\\{aka x\\\} == 
parameters_of\\\(\\\^\\\^foo\\\(int, int\\\)\\\)\\\[1\\\]\\\)'" "" { target 
*-*-* } .-1 }
+static_assert (bases_of (^^C, ctx)[0] == bases_of (^^C, ctx)[1]);      // { 
dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(bases_of\\\(\\\^\\\^C,std::meta::access_context::unchecked\\\(\\\)\\\)\\\[0\\\]
 \\\{aka A\\\} == 
bases_of\\\(\\\^\\\^C,std::meta::access_context::unchecked\\\(\\\)\\\)\\\[1\\\] 
\\\{aka B\\\}\\\)'" "" { target *-*-* } .-1 }
+static_assert (bases_of (^^C, ctx)[1] == bases_of (^^D, ctx)[1]);      // { 
dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(bases_of\\\(\\\^\\\^C,std::meta::access_context::unchecked\\\(\\\)\\\)\\\[1\\\]
 \\\{aka B\\\} == 
bases_of\\\(\\\^\\\^D,std::meta::access_context::unchecked\\\(\\\)\\\)\\\[1\\\] 
\\\{aka B\\\}\\\)'" "" { target *-*-* } .-1 }
+constexpr auto an1 = annotations_of (^^foo)[0];
+constexpr auto an2 = annotations_of (^^foo)[1];
+constexpr auto an3 = std::meta::reflect_constant (3);
+static_assert (data_member_spec (^^int, { .name = "foo", .alignment = 64, 
.no_unique_address = true, .annotations = { an1, an2, an3 } }) == ^^::);     // 
{ dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(data_member_spec\\\(\\\^\\\^int,\\\{.name=\\\"foo\\\",.alignment=64,.no_unique_address=true,.annotations=\\\{std::meta::reflect_constant\\\(1\\\),std::meta::reflect_constant\\\(2\\\),std::meta::reflect_constant\\\(3\\\)\\\}\\\}\\\)
 == \\\^\\\^::\\\)'" "" { target *-*-* } .-1 }
+static_assert (data_member_spec (^^int, { .bit_width = 5 }) == ^^::);  // { 
dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(data_member_spec\\\(\\\^\\\^int,\\\{.bit_width=5\\\}\\\) == 
\\\^\\\^::\\\)'" "" { target *-*-* } .-1 }
+static_assert (std::meta::reflect_constant (42) == std::meta::reflect_constant 
(A { 42 })); // { dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(std::meta::reflect_constant\\\(42\\\) == 
std::meta::reflect_object\\\(A\\\{42\\\}\\\)\\\)'" "" { target *-*-* } .-1 }
+int v[42];
+static_assert (std::meta::reflect_object (v[4]) == std::meta::reflect_object 
(v[5])); // { dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(std::meta::reflect_object\\\(v\\\[4\\\]\\\) == 
std::meta::reflect_object\\\(v\\\[5\\\]\\\)\\\)'" "" { target *-*-* } .-1 }
+
+void
+qux (int, int)
+{
+}
+
+void qux (int x, int y);
+void qux (int x, int y);
+
+static_assert (parameters_of (^^qux)[0] == parameters_of (^^qux)[1]);  // { 
dg-error "static assertion failed" }
+// { dg-message "note: the comparison reduces to 
'\\\(parameters_of\\\(\\\^\\\^qux\\\(int, int\\\)\\\)\\\[0\\\] \\\{aka x\\\} == 
parameters_of\\\(\\\^\\\^qux\\\(int, int\\\)\\\)\\\[1\\\] \\\{aka y\\\}\\\)'" 
"" { target *-*-* } .-1 }

Reply via email to