]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Improve REFLECT_EXPR printing [PR125007]
authorJakub Jelinek <jakub@redhat.com>
Thu, 7 May 2026 15:31:09 +0000 (17:31 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 7 May 2026 15:31:09 +0000 (17:31 +0200)
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  <jakub@redhat.com>

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 <jason@redhat.com>
gcc/cp/cp-tree.h
gcc/cp/error.cc
gcc/cp/reflect.cc
gcc/testsuite/g++.dg/reflect/pr125007.C [new file with mode: 0644]

index b2c040c2fa4c2e28db79c4b58967a157f306fd63..06dc5af495501dca2d2c1f68e66c194a7cfae1a7 100644 (file)
@@ -9517,6 +9517,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,
index 5f4cb477230762228fd2b75ff46571cf49e5804e..a22c8ee113e8ca4e4e30681f96bdaeb30791b931 100644 (file)
@@ -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;
       }
 
index 0f8daf55d0a6d0c4b196e7293cbfa7e5da628c11..ad4c77fab3eb13f01ebd22dbca9d666598a10fe6 100644 (file)
@@ -283,7 +283,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 (file)
index 0000000..4ac0dfe
--- /dev/null
@@ -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 }