https://gcc.gnu.org/g:23a80bd08ffaaf2260a499d828d63d001e1d634c
commit r16-7648-g23a80bd08ffaaf2260a499d828d63d001e1d634c Author: Marek Polacek <[email protected]> Date: Thu Feb 19 14:47:26 2026 -0500 c++/reflection: members_of and friend class [PR123641] The assert in this test currently doesn't pass because .size () is 3, due to {A, B, B} found in N, but it should only be {A, B}, because we should skip the hidden "void N::B()". PR c++/123641 gcc/cp/ChangeLog: * name-lookup.cc: Move STAT_* and MAYBE_STAT_* macros from here to... * name-lookup.h: ...here. * reflect.cc (namespace_members_of): Use them. Skip STAT_TYPE_HIDDEN_P. gcc/testsuite/ChangeLog: * g++.dg/reflect/members_of8.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/name-lookup.cc | 24 ------------------------ gcc/cp/name-lookup.h | 24 ++++++++++++++++++++++++ gcc/cp/reflect.cc | 10 +++++----- gcc/testsuite/g++.dg/reflect/members_of8.C | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 9a732e14979a..b7fc43391cf2 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -57,30 +57,6 @@ enum binding_slots BINDING_SLOTS_FIXED = BINDING_SLOT_GLOBAL + 1 }; -/* Create an overload suitable for recording an artificial TYPE_DECL - and another decl. We use this machanism to implement the struct - stat hack. */ - -#define STAT_HACK_P(N) ((N) && TREE_CODE (N) == OVERLOAD && OVL_LOOKUP_P (N)) -#define STAT_TYPE_VISIBLE_P(N) TREE_USED (OVERLOAD_CHECK (N)) -#define STAT_TYPE(N) TREE_TYPE (N) -#define STAT_DECL(N) OVL_FUNCTION (N) -#define STAT_VISIBLE(N) OVL_CHAIN (N) -#define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N) -#define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE) - -/* When a STAT_HACK_P is true, OVL_USING_P and OVL_EXPORT_P are valid - and apply to the hacked type. */ - -/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P. - But we also need to indicate hiddenness on implicit type decls - (injected friend classes), and (coming soon) decls injected from - block-scope externs. It is too awkward to press the existing - overload marking for that. If we have a hidden non-function, we - always create a STAT_HACK, and use these two markers as needed. */ -#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N) -#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N) - /* Create a STAT_HACK node with DECL as the value binding and TYPE as the type binding. */ diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 4c167cd135c4..12d75b3437b0 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -41,6 +41,30 @@ struct cp_binding_level; value and type slots are both filled and both hidden. */ #define HIDDEN_TYPE_BINDING_P(NODE) ((NODE)->type_is_hidden) +/* Create an overload suitable for recording an artificial TYPE_DECL + and another decl. We use this machanism to implement the struct + stat hack. */ + +#define STAT_HACK_P(N) ((N) && TREE_CODE (N) == OVERLOAD && OVL_LOOKUP_P (N)) +#define STAT_TYPE_VISIBLE_P(N) TREE_USED (OVERLOAD_CHECK (N)) +#define STAT_TYPE(N) TREE_TYPE (N) +#define STAT_DECL(N) OVL_FUNCTION (N) +#define STAT_VISIBLE(N) OVL_CHAIN (N) +#define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N) +#define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE) + +/* When a STAT_HACK_P is true, OVL_USING_P and OVL_EXPORT_P are valid + and apply to the hacked type. */ + +/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P. + But we also need to indicate hiddenness on implicit type decls + (injected friend classes), and (coming soon) decls injected from + block-scope externs. It is too awkward to press the existing + overload marking for that. If we have a hidden non-function, we + always create a STAT_HACK, and use these two markers as needed. */ +#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N) +#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N) + /* Datatype that represents binding established by a declaration between a name and a C++ entity. */ struct GTY(()) cxx_binding { diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 46355251bcdd..a80f7ca0a141 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -6473,18 +6473,18 @@ namespace_members_of (location_t loc, tree ns) hash_set<tree> *seen = nullptr; for (tree o : *DECL_NAMESPACE_BINDINGS (ns)) { - if (TREE_CODE (o) == OVERLOAD && OVL_LOOKUP_P (o)) + if (STAT_HACK_P (o)) { - if (TREE_TYPE (o)) + if (STAT_TYPE (o) && !STAT_TYPE_HIDDEN_P (o)) { - tree m = TREE_TYPE (TREE_TYPE (o)); + tree m = TREE_TYPE (STAT_TYPE (o)); if (members_of_representable_p (ns, m)) CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, get_reflection_raw (loc, m)); } - if (OVL_DEDUP_P (o) || !OVL_FUNCTION (o)) + if (STAT_DECL_HIDDEN_P (o) || !STAT_DECL (o)) continue; - o = OVL_FUNCTION (o); + o = STAT_DECL (o); } for (ovl_iterator iter (o); iter; ++iter) { diff --git a/gcc/testsuite/g++.dg/reflect/members_of8.C b/gcc/testsuite/g++.dg/reflect/members_of8.C new file mode 100644 index 000000000000..ec6b6fdf1920 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/members_of8.C @@ -0,0 +1,17 @@ +// PR c++/123641 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test that we skip STAT_TYPE_HIDDEN_P. + +#include <meta> +using namespace std::meta; + +namespace N { + void B (); + struct A { + int m; + friend class B; + }; +} +constexpr access_context uctx = access_context::unchecked (); +static_assert (members_of (^^N, uctx).size () == 2);
