On 3/15/26 7:57 AM, Thomas Berger wrote:
Previously, finish_member_declaration prepended non-type members and
appended TYPE_DECLs to TYPE_FIELDS separately, so that the TYPE_DECLs
always appeared after all non-type members regardless of their decleration
order.

Store all members in declaration order instead and update the places,
that relied on the old layout.

gcc/analyzer/ChangeLog:

        * region-model.cc (struct_or_union_with_inheritance_p): Skip
          leading TYPE_DECL nodes before checking for base class field.

gcc/cp/ChangeLog:

        * class.cc (unreverse_member_declarations): Use nreverse for both
          CLASSTYPE_DECL_LIST and TYPE_FIELDS.
        * decl.cc (reshape_init_class): Guard anonymous aggregate field
          search with FIELD_DECL check.
        * name-lookup.cc (fields_linear_search): Return first non-type
          match immediately; fall back to TYPE_DECL if no non-type is found.
        * parser.cc (remove_dummy_lambda_op): Search chain for dummy
          operator instead of assuming it is the TYPE_FIELDS head.
        * semantics.cc (finish_member_declaration): Always prepend to
          FIELD_DECL; remove separate handling for TYPE_DECL.

Signed-off-by: Thomas Berger <[email protected]>
---
  gcc/analyzer/region-model.cc |  5 +++++
  gcc/cp/class.cc              | 26 +-------------------------
  gcc/cp/decl.cc               |  3 ++-
  gcc/cp/name-lookup.cc        | 17 +++++++++++++++--
  gcc/cp/parser.cc             | 20 +++++++++++---------
  gcc/cp/semantics.cc          | 20 ++------------------
  6 files changed, 36 insertions(+), 55 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 4a6f5b4800c..1935b3a45fa 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -4116,6 +4116,11 @@ static bool
  struct_or_union_with_inheritance_p (tree struc)
  {
    tree iter = TYPE_FIELDS (struc);
+
+  // look for the first non type member

In general comments need to start with a capital letter and end with period. This comment in particular seems unnecessary, since it doesn't say anything more than the next line.

+  while (iter && TREE_CODE (iter) == TYPE_DECL)

Let's make this != FIELD_DECL, since that's what the function is looking for. Does that sound right to you, David?

+    iter = DECL_CHAIN (iter);
+
    if (iter == NULL_TREE)
          return false;
    if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (iter)))
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 8beeb797a08..399fbdc136b 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8180,32 +8180,8 @@ finish_struct_1 (tree t)
  void
  unreverse_member_declarations (tree t)
  {
-  tree next;
-  tree prev;
-  tree x;
-
-  /* The following lists are all in reverse order.  Put them in
-     declaration order now.  */

Let's keep this comment.

    CLASSTYPE_DECL_LIST (t) = nreverse (CLASSTYPE_DECL_LIST (t));
-
-  /* For the TYPE_FIELDS, only the non TYPE_DECLs are in reverse
-     order, so we can't just use nreverse.  Due to stat_hack
-     chicanery in finish_member_declaration.  */
-  prev = NULL_TREE;
-  for (x = TYPE_FIELDS (t);
-       x && TREE_CODE (x) != TYPE_DECL;
-       x = next)
-    {
-      next = DECL_CHAIN (x);
-      DECL_CHAIN (x) = prev;
-      prev = x;
-    }
-
-  if (prev)
-    {
-      DECL_CHAIN (TYPE_FIELDS (t)) = x;
-      TYPE_FIELDS (t) = prev;
-    }
+  TYPE_FIELDS(t) = nreverse (TYPE_FIELDS(t));

Space before (.

  }
/* Classes, structs or unions T marked with hotness attributes propagate
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 49056d94857..0700df77f85 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7901,7 +7901,8 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
              /* Now find the TYPE member with that anon aggr type.  */
              tree aafield = TYPE_FIELDS (type);
              for (; aafield; aafield = TREE_CHAIN (aafield))
-               if (TREE_TYPE (aafield) == ictx)
+               if (TREE_TYPE (aafield) == ictx
+                 && TREE_CODE(aafield) == FIELD_DECL)

Space before (.

                  break;
              gcc_assert (aafield);
              field = aafield;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 13aafab4e68..8addd3b29ca 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -1848,6 +1848,7 @@ member_vec_linear_search (vec<tree, va_gc> *member_vec, 
tree name)
  static tree
  fields_linear_search (tree klass, tree name, bool want_type)
  {
+  tree found = NULL_TREE;
    for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN 
(fields))
      {
        tree decl = fields;
@@ -1878,11 +1879,23 @@ fields_linear_search (tree klass, tree name, bool 
want_type)
        /* Functions are found separately.  */
        continue;
- if (!want_type || DECL_DECLARES_TYPE_P (decl))
+      if (DECL_DECLARES_TYPE_P (decl))
+       {
+         if (want_type)

We could also return immediately if !DECL_IMPLICIT_TYPEDEF_P.

+           return decl;
+
+         /* This decl may be hidden through a non-TYPE_DECL member later on.
+            We store the type and return it in the case no other matching
+            member was found. */
+         found = decl;
+         continue;
+       }
+
+      if (!want_type)
        return decl;
      }
- return NULL_TREE;
+  return found;
  }
/* Like fields_linear_search, but specific for "_" name. There can be multiple
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ffb22aa776f..e18a740a918 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -13673,15 +13673,17 @@ void
  remove_dummy_lambda_op (tree dummy_fco, tree lambda_expr)
  {
    tree type = TREE_TYPE (lambda_expr);
-  if (TYPE_FIELDS (type) == dummy_fco)
-    {
-      /* Stitch out the dummy operator().  */
-      TYPE_FIELDS (type) = DECL_CHAIN (TYPE_FIELDS (type));
-      /* And clear the member vector as well.  */
-      auto *member_vec = CLASSTYPE_MEMBER_VEC (type);
-      gcc_assert (member_vec->length () == 1);
-      member_vec->truncate (0);
-    }
+  for (tree *prev_p = &TYPE_FIELDS (type); *prev_p;
+       prev_p = &DECL_CHAIN (*prev_p))
+    if (*prev_p == dummy_fco)
+      {
+       *prev_p = DECL_CHAIN (*prev_p);
+       auto *member_vec = CLASSTYPE_MEMBER_VEC (type);
+       gcc_assert (member_vec->length () == 1);
+       member_vec->truncate (0);
+       break;
+      }
+
    /* Class templates will have the dummy operator() stashed here too.  */
    tree &list = CLASSTYPE_DECL_LIST (type);
    if (list && TREE_VALUE (list) == dummy_fco)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index ac08b598f3d..a0dcc14c3fe 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4323,24 +4323,8 @@ finish_member_declaration (tree decl)
if (add)
      {
-      /* All TYPE_DECLs go at the end of TYPE_FIELDS.  Ordinary fields
-        go at the beginning.  The reason is that
-        legacy_nonfn_member_lookup searches the list in order, and we
-        want a field name to override a type name so that the "struct
-        stat hack" will work.  In particular:
-
-          struct S { enum E { }; static const int E = 5; int ary[S::E]; } s;
-
-        is valid.  */
-
-      if (TREE_CODE (decl) == TYPE_DECL)
-       TYPE_FIELDS (current_class_type)
-         = chainon (TYPE_FIELDS (current_class_type), decl);
-      else
-       {
-         DECL_CHAIN (decl) = TYPE_FIELDS (current_class_type);
-         TYPE_FIELDS (current_class_type) = decl;
-       }
+      DECL_CHAIN (decl) = TYPE_FIELDS (current_class_type);
+      TYPE_FIELDS (current_class_type) = decl;
maybe_add_class_template_decl_list (current_class_type, decl,
                                          /*friend_p=*/0);

Reply via email to