]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Fix friend attributes [PR51344]
authorJason Merrill <jason@redhat.com>
Fri, 5 Feb 2021 15:36:49 +0000 (10:36 -0500)
committerJason Merrill <jason@redhat.com>
Thu, 29 Apr 2021 18:38:50 +0000 (14:38 -0400)
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.  And then apply_late_template_attributes can avoid
copying the non-dependent attributes.

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.
* pt.c (apply_late_template_attributes): Optimize.

gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/pt.c

index d693b4386682d486809bd239506004499bb12d54..dad3849d44fe9bb9a887b2c7348d281167b4e121 100644 (file)
@@ -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);
index d3639e3346006139c24a8e7fa67b98265b0ccaf0..368d9f5adf79acddb8a03e7c8dd815c3a8c38373 100644 (file)
@@ -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);
index e51c1b09652ca6a9b8fc8c5ee7be74bc03135aee..d1e73373660561c3b3d8a3f181ceff06a2abba2f 100644 (file)
@@ -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
index a82960fb39c031760b244799526f9174bf00ba81..89f874a32cc95f1fe9496481fd603df684951853 100644 (file)
@@ -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))
index ee73adb1677a468af356e351bed5d834788769e0..4f6288414d988ff3957329caea68a81af2637c69 100644 (file)
@@ -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);
index fc5065be4dbf7f99169ad17fc9736dacbccc146f..116bdd2e42a895f40f93f31803da0ca893717b04 100644 (file)
@@ -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)
-    {
-      tree late_attrs = NULL_TREE;
-      tree *q = &late_attrs;
+  /* Apply any non-dependent attributes.  */
+  *p = nondep;
 
-      for (; *p; )
+  /* And then any dependent ones.  */
+  tree late_attrs = NULL_TREE;
+  tree *q = &late_attrs;
+  for (t = attributes; t != nondep; t = TREE_CHAIN (t))
+    {
+      *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;
 }