On Fri, Feb 20, 2026 at 08:56:03AM +0100, Jakub Jelinek wrote:
> On Thu, Feb 19, 2026 at 03:09:49PM -0500, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > 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 (STAT_TYPE_HIDDEN_P, STAT_DECL_HIDDEN_P): Moved from
> >     here to...
> >     * name-lookup.h: ...here.
> >     * reflect.cc (namespace_members_of): Skip STAT_TYPE_HIDDEN_P.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/reflect/members_of8.C: New test.
> 
> > --- a/gcc/cp/name-lookup.cc
> > +++ b/gcc/cp/name-lookup.cc
> > @@ -59,7 +59,9 @@ enum binding_slots
> >  
> >  /* Create an overload suitable for recording an artificial TYPE_DECL
> >     and another decl.  We use this machanism to implement the struct
> > -   stat hack.  */
> > +   stat hack.
> > +   When a STAT_HACK_P is true, OVL_USING_P and OVL_EXPORT_P are valid
> > +   and apply to the hacked type.  */
> >  
> >  #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))
> > @@ -69,18 +71,6 @@ enum binding_slots
> >  #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)
> 
> I thought you should move over all the macros, starting with STAT_HACK_P
> and ending with STAT_DECL_HIDDEN_P, including the comments.

Can do.

> > --- a/gcc/cp/reflect.cc
> > +++ b/gcc/cp/reflect.cc
> > @@ -6482,7 +6482,7 @@ namespace_members_of (location_t loc, tree ns)
> >             CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
> >                                     get_reflection_raw (loc, m));
> >         }
> > -     if (OVL_DEDUP_P (o) || !OVL_FUNCTION (o))
> > +     if (OVL_DEDUP_P (o) || !OVL_FUNCTION (o) || STAT_TYPE_HIDDEN_P (o))
> >         continue;
> >       o = OVL_FUNCTION (o);
> 
> I think STAT_TYPE_HIDDEN_P means the STAT_TYPE should be hidden, not
> STAT_DECL.
> Furthermore, if/when all the macros are moved, it would be better to
> use those macros in the function rather than what they expand to.
> So untested
> -      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);
>          }
> ?

Looks much better.  Here's a patch:

dg.exp passed so far, ok for trunk?

-- >8 --
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.
---
 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(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/members_of8.C

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 9a732e14979..b7fc43391cf 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 4c167cd135c..12d75b3437b 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 46355251bcd..a80f7ca0a14 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 00000000000..ec6b6fdf192
--- /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);

base-commit: e47f44074a5fe9b51cbe75269363a42e90d6a580
-- 
2.53.0

Reply via email to