Hi!

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).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-04-10  Jakub Jelinek  <[email protected]>

        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.

--- gcc/cp/reflect.cc.jj        2026-04-08 15:40:47.318192269 +0200
+++ gcc/cp/reflect.cc   2026-04-09 16:02:19.379053882 +0200
@@ -6760,6 +6760,24 @@ namespace_members_of (location_t loc, tr
          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, so perhaps it doesn't need to be
+            handled.  */
+         tree type = CP_DECL_CONTEXT (b);
+         if (!data->seen)
+           data->seen = new hash_set<tree>;
+         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);
 
--- gcc/testsuite/g++.dg/reflect/members_of13.C.jj      2026-04-09 
15:45:44.788055664 +0200
+++ gcc/testsuite/g++.dg/reflect/members_of13.C 2026-04-09 16:12:01.943097471 
+0200
@@ -0,0 +1,31 @@
+// PR c++/124831
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+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);

        Jakub

Reply via email to