From 6535e206f12552c7840169adeb9187fe9cf7f3a6 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 10 Apr 2026 18:49:00 +0200 Subject: [PATCH] c++: Include anon enum types in namespace members_of [PR124831] As the testcase shows, we have similar problem with namespace scope anonymous enums like we have with namespace scope anonymous unions. Because they are anonymous, in neither case we emit anything into the namespace bindings but we should still list those. Now, for anonymous union this is done by adding it (once only) when seeing corresponding DECL_ANON_UNION_VAR_P (and it doesn't work when there is anon union without any members but that is a pedwarn anyway). The following patch handles it similarly for anon enums, namespace scope enum {}; is still ignored (but that is a pedwarn as well, so not a big deal) and when there is at least one enumerator in it, we add it when seeing the CONST_DECL (but again, just once for the whole members_of call). 2026-04-10 Jakub Jelinek PR c++/124831 * reflect.cc (namespace_members_of): Append reflection of anon unions when we see it first time as CP_DECL_CONTEXT of some CONST_DECL in the namespace. * g++.dg/reflect/members_of13.C: New test. Reviewed-by: Jason Merrill --- gcc/cp/reflect.cc | 18 ++++++++++++ gcc/testsuite/g++.dg/reflect/members_of13.C | 31 +++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 gcc/testsuite/g++.dg/reflect/members_of13.C diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 8925bf49465..06bfae27748 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -6755,6 +6755,24 @@ namespace_members_of (location_t loc, tree ns) return; } + if (TREE_CODE (b) == CONST_DECL + && enum_with_enumerator_for_linkage_p (CP_DECL_CONTEXT (b)) + && members_of_representable_p (data->ns, CP_DECL_CONTEXT (b))) + { + /* TODO: This doesn't handle namespace N { enum {}; } + but we pedwarn on that because it violates [dcl.pre]/6, so + perhaps it doesn't need to be handled. */ + tree type = CP_DECL_CONTEXT (b); + if (!data->seen) + data->seen = new hash_set; + if (!data->seen->add (type)) + { + CONSTRUCTOR_APPEND_ELT (data->elts, NULL_TREE, + get_reflection_raw (data->loc, type)); + return; + } + } + if (TREE_CODE (b) == TYPE_DECL) m = TREE_TYPE (b); diff --git a/gcc/testsuite/g++.dg/reflect/members_of13.C b/gcc/testsuite/g++.dg/reflect/members_of13.C new file mode 100644 index 00000000000..c9c0cc9b70e --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/members_of13.C @@ -0,0 +1,31 @@ +// PR c++/124831 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include + +namespace N +{ + enum { A, B, C }; + enum { D }; + enum { E, F, G, H, I }; +} + +namespace O +{ + typedef enum { A, B, C } J; + typedef enum { D } K; + typedef enum { E, F, G, H, I } L; +} + +static_assert (members_of (^^N, std::meta::access_context::current ()).size () == 3); +static_assert (enumerators_of (members_of (^^N, std::meta::access_context::current ())[0])[0] == ^^N::A + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[1])[0] == ^^N::A + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[2])[0] == ^^N::A); +static_assert (enumerators_of (members_of (^^N, std::meta::access_context::current ())[0])[0] == ^^N::D + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[1])[0] == ^^N::D + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[2])[0] == ^^N::D); +static_assert (enumerators_of (members_of (^^N, std::meta::access_context::current ())[0])[0] == ^^N::E + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[1])[0] == ^^N::E + || enumerators_of (members_of (^^N, std::meta::access_context::current ())[2])[0] == ^^N::E); +static_assert (members_of (^^O, std::meta::access_context::current ()).size () == 6); -- 2.47.3