This patch implements [dcl.attr.grammar]/5: "If an attribute-specifier-seq
appertains to a friend declaration ([class.friend]), that declaration shall
be a definition."

This restriction only applies to C++11-style attributes.  There are
various forms of friend declarations, we have friend templates, C++11
extended friend declarations, and so on.  In some cases we already
ignore the attribute and warn that it was ignored.  But certain cases
weren't diagnosed, and with this patch we'll give a hard error.  I tried
hard not to emit both a warning and error and I think it worked out.

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

gcc/cp/ChangeLog:

        PR c++/99032
        * decl.c (grokdeclarator): Diagnose when an attribute appertains to
        a friend declaration that is not a definition.
        * parser.c (cp_parser_elaborated_type_specifier): Likewise.
        (cp_parser_member_declaration): Likewise.

gcc/testsuite/ChangeLog:

        PR c++/99032
        * g++.dg/cpp0x/friend7.C: New test.
---
 gcc/cp/decl.c                        |  4 +++
 gcc/cp/parser.c                      | 15 +++++++++-
 gcc/testsuite/g++.dg/cpp0x/friend7.C | 41 ++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/friend7.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bc3928d7f85..687a59d49e3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13741,6 +13741,10 @@ grokdeclarator (const cp_declarator *declarator,
 
        if (friendp)
          {
+           if (attrlist && !funcdef_flag
+               && cxx11_attribute_p (*attrlist))
+             error_at (id_loc, "attribute appertains to a friend declaration "
+                       "that is not a definition");
            /* Friends are treated specially.  */
            if (ctype == current_class_type)
              ;  /* We already issued a permerror.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 0fe29c658d2..612ca4598b9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19764,11 +19764,15 @@ cp_parser_elaborated_type_specifier (cp_parser* 
parser,
               && ! processing_explicit_instantiation)
        warning (OPT_Wattributes,
                 "attributes ignored on template instantiation");
+      else if (is_friend && cxx11_attribute_p (attributes))
+       error ("attribute appertains to a friend declaration that is not "
+              "a definition");
       else if (is_declaration && cp_parser_declares_only_class_p (parser))
        cplus_decl_attributes (&type, attributes, (int) 
ATTR_FLAG_TYPE_IN_PLACE);
       else
        warning (OPT_Wattributes,
-                "attributes ignored on elaborated-type-specifier that is not a 
forward declaration");
+                "attributes ignored on elaborated-type-specifier that is "
+                "not a forward declaration");
     }
 
   if (tag_type == enum_type)
@@ -26054,6 +26058,15 @@ cp_parser_member_declaration (cp_parser* parser)
                 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
+                       && (cxx11_attribute_p (decl_specifiers.std_attributes)
+                           || cxx11_attribute_p (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
new file mode 100644
index 00000000000..4aa7b14cf7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/friend7.C
@@ -0,0 +1,41 @@
+// PR c++/99032
+// { dg-do compile { target c++11 } }
+
+class X { };
+template<typename T1, typename T2>
+void foo (T1, T2);
+
+struct S {
+  [[deprecated]] friend void f(); // { dg-error "attribute appertains" }
+  [[deprecated]] friend void f2() { }
+  __attribute__((deprecated)) friend void f3();
+  friend void f3 [[deprecated]] (); // { dg-error "attribute appertains" }
+  friend void f4 [[deprecated]] () { }
+  [[deprecated]] friend void; // { dg-error "attribute appertains" }
+  friend [[deprecated]] void; // { dg-error "attribute appertains" }
+  __attribute__((deprecated)) friend int;
+  friend __attribute__((deprecated)) int;
+  friend int __attribute__((deprecated));
+  [[deprecated]] friend X; // { dg-error "attribute appertains" }
+  [[deprecated]] friend class N; // { dg-warning "attribute ignored" }
+  friend class [[deprecated]] N2; // { dg-error "attribute appertains" }
+  friend class __attribute__((deprecated)) N3;
+  [[deprecated]] friend void foo<>(int, int); // { dg-error "attribute 
appertains" }
+  // FIXME: Add dg error when PR100339 is resolved.
+  //[[deprecated]] friend void ::foo(int, int);
+};
+
+template<typename T>
+class node { };
+
+template<typename T>
+struct A {
+  [[deprecated]] friend T; // { dg-error "attribute appertains" }
+  [[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" }
+};

base-commit: 71d38ec80008afdbb9a059253407d80598b765c0
-- 
2.31.1

Reply via email to