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 }
