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