51344 was a problem with calling save_template_attributes twice for the same
friend function: once from do_friend and once from grokmethod.  The 2012
patch for the bug avoided creating an infinite loop when this happens, but
it's better to avoid the duplication in the first place.  This also restores
the dependent attributes to the beginning of the attribute list, as
originally intended.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog:

        PR c++/51344
        * decl2.c (grokfield): Call cplus_decl_attributes for friend.
        (save_template_attributes): Use chainon.
        * friend.c (do_friend): Remove attrlist parm.
        * cp-tree.h (do_friend): Adjust.
        * class.c (add_implicitly_declared_members): Adjust.
        * decl.c (grokdeclarator): Adjust.
---
 gcc/cp/cp-tree.h |  2 +-
 gcc/cp/class.c   |  2 +-
 gcc/cp/decl.c    |  3 +--
 gcc/cp/decl2.c   | 10 +++++++---
 gcc/cp/friend.c  |  9 +--------
 gcc/cp/pt.c      | 51 ++++++++++++++++++++++--------------------------
 6 files changed, 34 insertions(+), 43 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d3639e33460..368d9f5adf7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6848,7 +6848,7 @@ extern void mark_exp_read                 (tree);
 extern int is_friend                           (tree, tree);
 extern void make_friend_class                  (tree, tree, bool);
 extern void add_friend                         (tree, tree, bool);
-extern tree do_friend                          (tree, tree, tree, tree,
+extern tree do_friend                          (tree, tree, tree,
                                                 enum overload_flags, bool);
 
 extern void set_global_friend                  (tree);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index d693b438668..dad3849d44f 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3314,7 +3314,7 @@ add_implicitly_declared_members (tree t, tree* 
access_decls,
        bool is_friend = DECL_CONTEXT (space) != t;
        if (is_friend)
          do_friend (NULL_TREE, DECL_NAME (eq), eq,
-                    NULL_TREE, NO_SPECIAL, true);
+                    NO_SPECIAL, true);
        else
          {
            add_method (t, eq, false);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e51c1b09652..d1e73373660 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13758,8 +13758,7 @@ grokdeclarator (const cp_declarator *declarator,
                  }
 
                decl = do_friend (ctype, unqualified_id, decl,
-                                 *attrlist, flags,
-                                 funcdef_flag);
+                                 flags, funcdef_flag);
                return decl;
              }
            else
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a82960fb39c..89f874a32cc 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -974,7 +974,11 @@ grokfield (const cp_declarator *declarator,
   if ((TREE_CODE (value) == FUNCTION_DECL
        || TREE_CODE (value) == TEMPLATE_DECL)
       && DECL_CONTEXT (value) != current_class_type)
-    return value;
+    {
+      if (attrlist)
+       cplus_decl_attributes (&value, attrlist, 0);
+      return value;
+    }
 
   /* Need to set this before push_template_decl.  */
   if (VAR_P (value))
@@ -1278,9 +1282,9 @@ save_template_attributes (tree *attr_p, tree *decl_p, int 
flags)
 
   tree old_attrs = *q;
 
-  /* Merge the late attributes at the beginning with the attribute
+  /* Place the late attributes at the beginning of the attribute
      list.  */
-  late_attrs = merge_attributes (late_attrs, *q);
+  late_attrs = chainon (late_attrs, *q);
   if (*q != late_attrs
       && !DECL_P (*decl_p)
       && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index ee73adb1677..4f6288414d9 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -475,7 +475,7 @@ make_friend_class (tree type, tree friend_type, bool 
complain)
 
 tree
 do_friend (tree ctype, tree declarator, tree decl,
-          tree attrlist, enum overload_flags flags,
+          enum overload_flags flags,
           bool funcdef_flag)
 {
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
@@ -488,13 +488,6 @@ do_friend (tree ctype, tree declarator, tree decl,
     error ("friend declaration %qD may not have virt-specifiers",
           decl);
 
-  /* Unfortunately, we have to handle attributes here.  Normally we would
-     handle them in start_decl_1, but since this is a friend decl start_decl_1
-     never gets to see it.  */
-
-  /* Set attributes here so if duplicate decl, will have proper attributes.  */
-  cplus_decl_attributes (&decl, attrlist, 0);
-
   if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
     {
       declarator = TREE_OPERAND (declarator, 0);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3cd803f2f81..e65f7469484 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11659,7 +11659,6 @@ static bool
 apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
                                tree args, tsubst_flags_t complain, tree 
in_decl)
 {
-  tree last_dep = NULL_TREE;
   tree t;
   tree *p;
 
@@ -11685,39 +11684,35 @@ apply_late_template_attributes (tree *decl_p, tree 
attributes, int attr_flags,
        p = &TREE_CHAIN (*p);
     }
 
+  /* save_template_attributes puts the dependent attributes at the beginning of
+     the list; find the non-dependent ones.  */
   for (t = attributes; t; t = TREE_CHAIN (t))
-    if (ATTR_IS_DEPENDENT (t))
-      {
-       last_dep = t;
-       attributes = copy_list (attributes);
-       break;
-      }
+    if (!ATTR_IS_DEPENDENT (t))
+      break;
+  tree nondep = t;
 
-  *p = attributes;
-  if (last_dep)
+  /* Apply any non-dependent attributes.  */
+  *p = nondep;
+
+  /* And then any dependent ones.  */
+  tree late_attrs = NULL_TREE;
+  tree *q = &late_attrs;
+  for (t = attributes; t != nondep; t = TREE_CHAIN (t))
     {
-      tree late_attrs = NULL_TREE;
-      tree *q = &late_attrs;
-
-      for (; *p; )
+      *q = tsubst_attribute (t, decl_p, args, complain, in_decl);
+      if (*q == error_mark_node)
+       return false;
+      if (*q == t)
        {
-         t = *p;
-         if (ATTR_IS_DEPENDENT (t))
-           {
-             *q = tsubst_attribute (t, decl_p, args, complain, in_decl);
-             if (*q == error_mark_node)
-               return false;
-             *p = TREE_CHAIN (t);
-             TREE_CHAIN (t) = NULL_TREE;
-             while (*q)
-               q = &TREE_CHAIN (*q);
-           }
-         else
-           p = &TREE_CHAIN (t);
+         *q = copy_node (t);
+         TREE_CHAIN (*q) = NULL_TREE;
        }
-
-      cplus_decl_attributes (decl_p, late_attrs, attr_flags);
+      while (*q)
+       q = &TREE_CHAIN (*q);
     }
+
+  cplus_decl_attributes (decl_p, late_attrs, attr_flags);
+
   return true;
 }
 

base-commit: 449d7b40f6f6be8d7f9aa7232c73b0371f0963bf
prerequisite-patch-id: 39f358d55a4ba496b673d13e00215152266caa54
prerequisite-patch-id: f0d6c56fe2c9e16572f0760fb223f6d4df3e859e
prerequisite-patch-id: 8188da37013371fd5864b80fb0cc5ad4596a1ff6
-- 
2.27.0

Reply via email to