diff mbox series

c++: Relax attribute on friend declaration checking [PR100596]

Message ID 20210518210054.916026-1-polacek@redhat.com
State New
Headers show
Series c++: Relax attribute on friend declaration checking [PR100596] | expand

Commit Message

Marek Polacek May 18, 2021, 9 p.m. UTC
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?

	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


base-commit: 8c114759b8c9c9e2ec90b82d92a24b5a71647017

Comments

Jason Merrill May 19, 2021, 5:02 p.m. UTC | #1
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
>
diff mbox series

Patch

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;
+}