On 3/4/26 3:45 AM, Jakub Jelinek wrote:
On Wed, Feb 25, 2026 at 08:50:40PM +0100, Jakub Jelinek wrote:
Will change next week.

Here is an updated patch.

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

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

        PR c++/123810
        * cp-tree.h (TYPE_DECL_FOR_LINKAGE_PURPOSES_P): Define.
        (TYPE_DECL_WAS_UNNAMED): Likewise.
        (TYPE_WAS_UNNAMED): Also check TYPE_DECL_WAS_UNNAMED.
        * decl.cc (start_decl): Use TYPE_DECL_FOR_LINKAGE_PURPOSES_P.
        (maybe_diagnose_non_c_class_typedef_for_l): If t == type, use
        DECL_SOURCE_LOCATION (orig) instead of
        DECL_SOURCE_LOCATION (TYPE_NAME (t)).
        (name_unnamed_type): Set TYPE_DECL_FOR_LINKAGE_PURPOSES_P
        on decl.  For -freflection don't change TYPE_NAME from
        orig to decl, but instead change DECL_NAME (orig) to
        DECL_NAME (decl) and set TYPE_DECL_FOR_LINKAGE_PURPOSES_P on
        orig too.
        * decl2.cc (grokfield): Use TYPE_DECL_FOR_LINKAGE_PURPOSES_P.
        * name-lookup.cc (fields_linear_search): Ignore
        TYPE_DECL_WAS_UNNAMED decls.
        (count_class_fields): Likewise.
        (member_vec_append_class_fields): Likewise.
        (pop_local_binding): Likewise.
        * reflect.cc (namespace_members_of): For TYPE_DECL with
        TYPE_DECL_FOR_LINKAGE_PURPOSES_P set also append
        reflection of strip_typedefs (m).
        * class.cc (find_flexarrays): Handle TYPE_DECLs with
        TYPE_DECL_FOR_LINKAGE_PURPOSES_P like the ones with IDENTIFIER_ANON_P
        name.

        * g++.dg/reflect/members_of10.C: New test.
        * g++.dg/cpp2a/typedef1.C: Expect one message on a different line.

--- gcc/cp/cp-tree.h.jj 2026-03-02 07:43:12.342788130 +0100
+++ gcc/cp/cp-tree.h    2026-03-03 17:22:57.917038151 +0100
@@ -591,6 +591,7 @@ extern GTY(()) tree cp_global_trees[CPTI
     7: DECL_THUNK_P (in a member FUNCTION_DECL)
        DECL_NORMAL_CAPTURE_P (in FIELD_DECL)
        DECL_DECLARED_CONSTINIT_P (in VAR_DECL)
+      TYPE_DECL_FOR_LINKAGE_PURPOSES_P (in TYPE_DECL)
     8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL)
Usage of language-independent fields in a language-dependent manner:
@@ -4000,6 +4001,20 @@ struct GTY(()) lang_decl {
     && TREE_CODE (TYPE_NAME (NODE)) == TYPE_DECL       \
     && TYPE_DECL_ALIAS_P (TYPE_NAME (NODE)))
+/* Nonzero for typedef name for linkage purposes. For -freflection
+   set also on the originally unnamed TYPE_DECL.  */
+#define TYPE_DECL_FOR_LINKAGE_PURPOSES_P(NODE) \
+  DECL_LANG_FLAG_7 (TYPE_DECL_CHECK (NODE))
+
+/* Nonzero for TYPE_DECL originally with IDENTIFIER_ANON_P DECL_NAME
+   later on named by a typedef name for linkage purposes in the
+   -freflection case (otherwise the TYPE_DECL keeps IDENTIFIER_ANON_P
+   DECL_NAME).  */
+#define TYPE_DECL_WAS_UNNAMED(NODE) \
+  (TREE_CODE (NODE) == TYPE_DECL \
+   && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (NODE) \
+   && DECL_IMPLICIT_TYPEDEF_P (NODE))
+
  /* If non-NULL for a VAR_DECL, FUNCTION_DECL, TYPE_DECL, TEMPLATE_DECL,
     or CONCEPT_DECL, the entity is either a template specialization (if
     DECL_USE_TEMPLATE is nonzero) or the abstract instance of the
@@ -5372,10 +5387,13 @@ get_vec_init_expr (tree t)
/* True if TYPE is an unnamed structured type with a typedef for
     linkage purposes.  In that case TYPE_NAME and TYPE_STUB_DECL of the
-   MAIN-VARIANT are different.  */
+   MAIN-VARIANT are different or TYPE_DECL_WAS_UNNAMED
+   is true for the TYPE_NAME.  */
  #define TYPE_WAS_UNNAMED(NODE)                                \
    (TYPE_NAME (TYPE_MAIN_VARIANT (NODE))                       \
-   != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
+   != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE))                \
+   || TYPE_DECL_WAS_UNNAMED            \
+       (TYPE_NAME (TYPE_MAIN_VARIANT (NODE))))
/* C++: all of these are overloaded! These apply only to TYPE_DECLs. */ --- gcc/cp/decl.cc.jj 2026-02-17 15:56:52.071376438 +0100
+++ gcc/cp/decl.cc      2026-03-03 17:22:57.919239897 +0100
@@ -6618,8 +6618,7 @@ start_decl (const cp_declarator *declara
    /* If this is a typedef that names the class for linkage purposes
       (7.1.3p8), apply any attributes directly to the type.  */
    if (TREE_CODE (decl) == TYPE_DECL
-      && OVERLOAD_TYPE_P (TREE_TYPE (decl))
-      && decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
+      && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (decl))
      flags = ATTR_FLAG_TYPE_IN_PLACE;
    else
      flags = 0;
@@ -13731,7 +13730,8 @@ maybe_diagnose_non_c_class_typedef_for_l
      {
        auto_diagnostic_group d;
        if (diagnose_non_c_class_typedef_for_linkage (type, orig))
-       inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
+       inform (type == t ? DECL_SOURCE_LOCATION (orig)
+               : DECL_SOURCE_LOCATION (TYPE_NAME (t)),
                "type is not C-compatible because it has a base class");
        return true;
      }
@@ -13797,12 +13797,22 @@ name_unnamed_type (tree type, tree decl)
    gcc_assert (TYPE_UNNAMED_P (type)
              || enum_with_enumerator_for_linkage_p (type));
- /* Replace the anonymous decl with the real decl. Be careful not to
-     rename other typedefs (such as the self-reference) of type.  */
    tree orig = TYPE_NAME (type);
-  for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-    if (TYPE_NAME (t) == orig)
-      TYPE_NAME (t) = decl;
+  if (flag_reflection)
+    {
+      /* For -freflection for typedef struct { ... } S; ^^S needs to be
+        a reflection of a type alias.  So, TREE_TYPE (DECL) can't be
+        TYPE.  Instead of what we do below, override DECL_NAME (orig).  */
+      DECL_NAME (orig) = DECL_NAME (decl);
+      TYPE_DECL_FOR_LINKAGE_PURPOSES_P (orig) = 1;
+    }
+  else
+    /* Replace the anonymous decl with the real decl.  Be careful not to
+       rename other typedefs (such as the self-reference) of type.  */
+    for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+      if (TYPE_NAME (t) == orig)
+       TYPE_NAME (t) = decl;
+  TYPE_DECL_FOR_LINKAGE_PURPOSES_P (decl) = 1;
/* If this is a typedef within a template class, the nested
       type is a (non-primary) template.  The name for the
--- gcc/cp/decl2.cc.jj  2026-02-12 17:51:31.805334303 +0100
+++ gcc/cp/decl2.cc     2026-03-03 17:22:57.920518198 +0100
@@ -1303,8 +1303,7 @@ grokfield (const cp_declarator *declarat
/* If this is a typedef that names the class for linkage purposes
             (7.1.3p8), apply any attributes directly to the type.  */
-         if (OVERLOAD_TYPE_P (TREE_TYPE (value))
-             && value == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))))
+         if (TYPE_DECL_FOR_LINKAGE_PURPOSES_P (value))
            attrflags = ATTR_FLAG_TYPE_IN_PLACE;
cplus_decl_attributes (&value, attrlist, attrflags);
--- gcc/cp/name-lookup.cc.jj    2026-03-02 07:43:12.343788113 +0100
+++ gcc/cp/name-lookup.cc       2026-03-03 17:57:41.387644318 +0100
@@ -1869,6 +1869,11 @@ fields_linear_search (tree klass, tree n
            continue;
        }
+ if (TYPE_DECL_WAS_UNNAMED (decl))
+       /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+          purposes.  */
+       continue;
+
        if (DECL_DECLARES_FUNCTION_P (decl))
        /* Functions are found separately.  */
        continue;
@@ -2345,7 +2350,13 @@ count_class_fields (tree klass)
             && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
        n_fields += count_class_fields (TREE_TYPE (fields));
      else if (DECL_NAME (fields))
-      n_fields += 1;
+      {
+       if (TYPE_DECL_WAS_UNNAMED (fields))
+         /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+            purposes.  */
+         continue;
+       n_fields += 1;
+      }
return n_fields;
  }
@@ -2369,6 +2380,10 @@ member_vec_append_class_fields (vec<tree
        if (TREE_CODE (field) == USING_DECL
            && IDENTIFIER_CONV_OP_P (DECL_NAME (field)))
          field = ovl_make (conv_op_marker, field);
+       else if (TYPE_DECL_WAS_UNNAMED (field))
+         /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+            purposes.  */
+         continue;
        member_vec->quick_push (field);
        }
  }
@@ -2700,7 +2715,9 @@ pop_local_binding (tree id, tree decl)
      binding->value = NULL_TREE;
    else if (binding->type == decl)
      binding->type = NULL_TREE;
-  else
+  /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+     purposes.  */
+  else if (!TYPE_DECL_WAS_UNNAMED (decl))
      {
        /* Name-independent variable was found after at least one declaration
         with the same name.  */
--- gcc/cp/reflect.cc.jj        2026-03-03 16:42:26.904622279 +0100
+++ gcc/cp/reflect.cc   2026-03-03 17:22:57.921903017 +0100
@@ -6545,6 +6545,14 @@ namespace_members_of (location_t loc, tr
             so don't bother calling it here.  */
          CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
                                  get_reflection_raw (loc, m));
+         /* For typedef struct { ... } S; include both the S type
+            alias (added above) and dealias of that for the originally
+            unnamed type (added below).  */
+         if (TREE_CODE (b) == TYPE_DECL
+             && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (b))

Perhaps this...

+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc,
+                                                       strip_typedefs (m)));
        }
      }
    delete seen;
--- gcc/cp/class.cc.jj  2026-02-12 17:51:31.801334370 +0100
+++ gcc/cp/class.cc     2026-03-03 17:22:57.922677708 +0100
@@ -7608,7 +7608,8 @@ find_flexarrays (tree t, flexmems_t *fme
        if (TREE_CODE (fld) == TYPE_DECL
          && DECL_IMPLICIT_TYPEDEF_P (fld)
          && CLASS_TYPE_P (TREE_TYPE (fld))
-         && IDENTIFIER_ANON_P (DECL_NAME (fld)))
+         && (IDENTIFIER_ANON_P (DECL_NAME (fld))
+             || TYPE_DECL_FOR_LINKAGE_PURPOSES_P (fld)))

...and this should also use WAS_UNNAMED for clarity?

OK either way.

Jason

Reply via email to