c++: Relax attribute on friend declaration checking [PR100596]
authorMarek Polacek <polacek@redhat.com>
Tue, 18 May 2021 20:11:16 +0000 (16:11 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 19 May 2021 17:10:15 +0000 (13:10 -0400)
It turned out that there are codebases that profusely use GNU attributes
on friend declarations, so we have to dial back our checking and allow
them.  And for C++11 attributes let's just warn instead of giving
errors.

PR c++/100596

gcc/cp/ChangeLog:

* cp-tree.h (any_non_type_attribute_p): Remove.
* decl.c (grokdeclarator): Turn an error into a warning and only
warn for standard attributes.
* decl2.c (any_non_type_attribute_p): Remove.
* parser.c (cp_parser_elaborated_type_specifier): Turn an error
into a warning and only warn for standard attributes.
(cp_parser_member_declaration): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/friend7.C: Turn a few dg-warnings into dg-errors.
Remove dg-errors for GNU attributes.
* g++.dg/ext/attrib63.C: Remove dg-error.
* g++.dg/cpp0x/friend8.C: New test.

gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp0x/friend7.C
gcc/testsuite/g++.dg/cpp0x/friend8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attrib63.C

index 3c900dc..860ed79 100644 (file)
@@ -6761,7 +6761,6 @@ extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *,
                          tree, tree, tree);
 extern tree splice_template_attributes         (tree *, tree);
 extern bool any_dependent_type_attributes_p    (tree);
-extern bool any_non_type_attribute_p           (tree);
 extern tree cp_reconstruct_complex_type                (tree, tree);
 extern bool attributes_naming_typedef_ok       (tree);
 extern void cplus_decl_attributes              (tree *, tree, int);
index 4f2fc2e..28052df 100644 (file)
@@ -13731,11 +13731,15 @@ grokdeclarator (const cp_declarator *declarator,
 
        if (friendp)
          {
-           if (attrlist && !funcdef_flag
-               /* Hack to allow attributes like vector_size on a friend.  */
-               && any_non_type_attribute_p (*attrlist))
-             error_at (id_loc, "attribute appertains to a friend "
-                       "declaration that is not a definition");
+           /* Packages tend to use GNU attributes on friends, so we only
+              warn for standard attributes.  */
+           if (attrlist && !funcdef_flag && cxx11_attribute_p (*attrlist))
+             {
+               *attrlist = NULL_TREE;
+               if (warning_at (id_loc, OPT_Wattributes, "attribute ignored"))
+                 inform (id_loc, "an attribute that appertains to a friend "
+                         "declaration that is not a definition is ignored");
+             }
            /* Friends are treated specially.  */
            if (ctype == current_class_type)
              ;  /* We already issued a permerror.  */
index 8e4dd6b..89f874a 100644 (file)
@@ -1331,20 +1331,6 @@ any_dependent_type_attributes_p (tree attrs)
   return false;
 }
 
-/* True if ATTRS contains any attribute that does not require a type.  */
-
-bool
-any_non_type_attribute_p (tree attrs)
-{
-  for (tree a = attrs; a; a = TREE_CHAIN (a))
-    {
-      const attribute_spec *as = lookup_attribute_spec (get_attribute_name (a));
-      if (as && !as->type_required)
-       return true;
-    }
-  return false;
-}
-
 /* Return true iff ATTRS are acceptable attributes to be applied in-place
    to a typedef which gives a previously unnamed class or enum a name for
    linkage purposes.  */
index f3503b1..bc0505d 100644 (file)
@@ -19774,9 +19774,12 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
               && ! processing_explicit_instantiation)
        warning (OPT_Wattributes,
                 "attributes ignored on template instantiation");
-      else if (is_friend && attributes)
-       error ("attribute appertains to a friend declaration that is not "
-              "a definition");
+      else if (is_friend && cxx11_attribute_p (attributes))
+       {
+         if (warning (OPT_Wattributes, "attribute ignored"))
+           inform (input_location, "an attribute that appertains to a friend "
+                   "declaration that is not a definition is ignored");
+       }
       else if (is_declaration && cp_parser_declares_only_class_p (parser))
        cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
       else
@@ -26064,17 +26067,23 @@ cp_parser_member_declaration (cp_parser* parser)
                   if (type && TREE_CODE (type) == TYPE_DECL)
                     type = TREE_TYPE (type);
                 }
+              /* Warn if an attribute cannot appear here, as per
+                 [dcl.attr.grammar]/5.  But not when declares_class_or_enum:
+                 we ignore attributes in elaborated-type-specifiers.  */
+              if (!declares_class_or_enum
+                  && cxx11_attribute_p (decl_specifiers.attributes))
+                {
+                  decl_specifiers.attributes = NULL_TREE;
+                  if (warning_at (decl_spec_token_start->location,
+                                  OPT_Wattributes, "attribute ignored"))
+                    inform (decl_spec_token_start->location, "an attribute "
+                            "that appertains to a friend declaration that "
+                            "is not a definition is ignored");
+                }
               if (!type || !TYPE_P (type))
                 error_at (decl_spec_token_start->location,
                           "friend declaration does not name a class or "
                           "function");
-              /* Give an error if an attribute cannot appear here, as per
-                 [dcl.attr.grammar]/5.  But not when declares_class_or_enum:
-                 we ignore attributes in elaborated-type-specifiers.  */
-              else if (!declares_class_or_enum && decl_specifiers.attributes)
-                error_at (decl_spec_token_start->location,
-                          "attribute appertains to a friend declaration "
-                          "that is not a definition");
               else
                 make_friend_class (current_class_type, type,
                                    /*complain=*/true);
index 734b367..e1d5f44 100644 (file)
@@ -6,21 +6,21 @@ template<typename T1, typename T2>
 void foo (T1, T2);
 
 struct S {
-  [[deprecated]] friend void f(); // { dg-error "attribute appertains" }
+  [[deprecated]] friend void f(); // { dg-warning "attribute ignored" }
   [[deprecated]] friend void f2() { }
-  __attribute__((deprecated)) friend void f3(); // { dg-error "attribute appertains" }
-  friend void f3 [[deprecated]] (); // { dg-error "attribute appertains" }
+  __attribute__((deprecated)) friend void f3();
+  friend void f3 [[deprecated]] (); // { dg-warning "attribute ignored" }
   friend void f4 [[deprecated]] () { }
-  [[deprecated]] friend void; // { dg-error "attribute appertains" }
-  __attribute__((deprecated)) friend int; // { dg-error "attribute appertains" }
-  friend __attribute__((deprecated)) int; // { dg-error "attribute appertains" }
-  friend int __attribute__((deprecated)); // { dg-error "attribute appertains" }
-  [[deprecated]] friend X; // { dg-error "attribute appertains" }
+  [[deprecated]] friend void; // { dg-warning "attribute ignored" }
+  __attribute__((deprecated)) friend int;
+  friend __attribute__((deprecated)) int;
+  friend int __attribute__((deprecated));
+  [[deprecated]] friend X; // { dg-warning "attribute ignored" }
   [[deprecated]] friend class N; // { dg-warning "attribute ignored" }
-  friend class [[deprecated]] N2; // { dg-error "attribute appertains" }
-  friend class __attribute__((deprecated)) N3; // { dg-error "attribute appertains" }
-  [[deprecated]] friend void foo<>(int, int); // { dg-error "attribute appertains" }
-  [[deprecated]] friend void ::foo(int, int); // { dg-error "attribute appertains" }
+  friend class [[deprecated]] N2; // { dg-warning "attribute ignored" }
+  friend class __attribute__((deprecated)) N3;
+  [[deprecated]] friend void foo<>(int, int); // { dg-warning "attribute ignored" }
+  [[deprecated]] friend void ::foo(int, int); // { dg-warning "attribute ignored" }
   // { dg-bogus "should have" "PR100339" { xfail *-*-* } .-1 }
 };
 
@@ -29,12 +29,12 @@ class node { };
 
 template<typename T>
 struct A {
-  [[deprecated]] friend T; // { dg-error "attribute appertains" }
+  [[deprecated]] friend T; // { dg-warning "attribute ignored" }
   [[deprecated]] friend class node<T>; // { dg-warning "attribute ignored" }
   template<typename>
   [[deprecated]] friend class A; // { dg-warning "attribute ignored" }
   template<typename>
   [[deprecated]] friend void bar () { }
   template<typename>
-  [[deprecated]] friend void baz (); // { dg-error "attribute appertains" }
+  [[deprecated]] friend void baz (); // { dg-warning "attribute ignored" }
 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/friend8.C b/gcc/testsuite/g++.dg/cpp0x/friend8.C
new file mode 100644 (file)
index 0000000..8d2a2d3
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/100596
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  __attribute((deprecated)) friend void f(A); // part of A API, definition in .C
+  [[deprecated]] friend void f2(A); // { dg-warning "ignored" }
+};
+
+int main()
+{
+  A a;
+  f(a); // { dg-warning "is deprecated" }
+  f2(a);
+}
index 93bde1e..583779a 100644 (file)
@@ -4,9 +4,9 @@
 #define vector __attribute__((vector_size(16)))
 class A {
   friend vector float f();
-  __attribute__((deprecated)) friend void f2(); // { dg-error "attribute appertains" }
-  friend __attribute__((deprecated, vector_size(16))) float f3(); // { dg-error "attribute appertains" }
-  friend __attribute__((vector_size(16), deprecated)) float f4(); // { dg-error "attribute appertains" }
+  __attribute__((deprecated)) friend void f2();
+  friend __attribute__((deprecated, vector_size(16))) float f3();
+  friend __attribute__((vector_size(16), deprecated)) float f4();
 };
 
 vector float vf;
@@ -15,3 +15,20 @@ f ()
 {
   return vf;
 }
+
+void
+f2 ()
+{
+}
+
+vector float
+f3 ()
+{
+  return vf;
+}
+
+vector float
+f4 ()
+{
+  return vf;
+}