On 5/18/21 5:00 PM, Marek Polacek wrote:
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.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.

        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                     |  1 -
  gcc/cp/decl.c                        | 14 +++++++++-----
  gcc/cp/decl2.c                       | 14 --------------
  gcc/cp/parser.c                      | 29 ++++++++++++++++++----------
  gcc/testsuite/g++.dg/cpp0x/friend7.C | 28 +++++++++++++--------------
  gcc/testsuite/g++.dg/cpp0x/friend8.C | 15 ++++++++++++++
  gcc/testsuite/g++.dg/ext/attrib63.C  | 23 +++++++++++++++++++---
  7 files changed, 77 insertions(+), 47 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/friend8.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 580db914d40..122dadf976f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6763,7 +6763,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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 17511f09e79..92fb4a2daea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13741,11 +13741,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.  */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8e4dd6b544a..89f874a32cc 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c0b57955954..ac1cefc5c41 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/friend7.C 
b/gcc/testsuite/g++.dg/cpp0x/friend7.C
index 734b367cd2b..e1d5f449f5c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/friend7.C
+++ b/gcc/testsuite/g++.dg/cpp0x/friend7.C
@@ -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
index 00000000000..8d2a2d35d54
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/friend8.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/ext/attrib63.C 
b/gcc/testsuite/g++.dg/ext/attrib63.C
index 93bde1e7d72..583779a9159 100644
--- a/gcc/testsuite/g++.dg/ext/attrib63.C
+++ b/gcc/testsuite/g++.dg/ext/attrib63.C
@@ -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;
+}

base-commit: 8c114759b8c9c9e2ec90b82d92a24b5a71647017


Reply via email to