aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2021-04-29 21:38:14 -0400
committerMarek Polacek <polacek@redhat.com>2021-05-13 21:13:32 -0400
commit149061188c7c6ddf27663c8c00b7574fc8d0fd23 (patch)
tree73ad0e8a10cdf67cb96a97cd2909cdaacf2dbe44 /gcc
parentf9af11c7f156bede9aa28410073acbab7b0fa0fe (diff)
downloadgcc-149061188c7c6ddf27663c8c00b7574fc8d0fd23.zip
gcc-149061188c7c6ddf27663c8c00b7574fc8d0fd23.tar.gz
gcc-149061188c7c6ddf27663c8c00b7574fc8d0fd23.tar.bz2
c++: Check attributes on friend declarations [PR99032]
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 applies to C++11-style attributes as well as GNU attributes with the exception that we allow GNU attributes that require a type, such as vector_size to continue accepting code as in attrib63.C. 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. Jason provided the cp_parser_decl_specifier_seq hunk to detect using standard attributes in the middle of decl-specifiers, which is invalid. Co-authored-by: Jason Merrill <jason@redhat.com> gcc/cp/ChangeLog: PR c++/99032 * cp-tree.h (any_non_type_attribute_p): Declare. * decl.c (grokdeclarator): Diagnose when an attribute appertains to a friend declaration that is not a definition. * decl2.c (any_non_type_attribute_p): New. * parser.c (cp_parser_decl_specifier_seq): Diagnose standard attributes in the middle of decl-specifiers. (cp_parser_elaborated_type_specifier): Diagnose when an attribute appertains to a friend declaration that is not a definition. (cp_parser_member_declaration): Likewise. gcc/testsuite/ChangeLog: PR c++/99032 * g++.dg/cpp0x/friend7.C: New test. * g++.dg/cpp0x/gen-attrs-4.C: Add dg-error. * g++.dg/cpp0x/gen-attrs-39-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-74.C: New test. * g++.dg/ext/attrib63.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c5
-rw-r--r--gcc/cp/decl2.c14
-rw-r--r--gcc/cp/parser.c23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/friend7.C40
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-74.C10
-rw-r--r--gcc/testsuite/g++.dg/ext/attrib63.C16
9 files changed, 112 insertions, 3 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 122dadf..580db91 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6763,6 +6763,7 @@ 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 bc3928d..17511f0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13741,6 +13741,11 @@ 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");
/* 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 89f874a..8e4dd6b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1331,6 +1331,20 @@ 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 41df5dd..c0b5795 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15146,6 +15146,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
if (!found_decl_spec)
break;
+ if (decl_specs->std_attributes)
+ {
+ error_at (decl_specs->locations[ds_std_attribute],
+ "standard attributes in middle of decl-specifiers");
+ inform (decl_specs->locations[ds_std_attribute],
+ "standard attributes must precede the decl-specifiers to "
+ "apply to the declaration, or follow them to apply to "
+ "the type");
+ }
+
decl_specs->any_specifiers_p = true;
/* After we see one decl-specifier, further decl-specifiers are
always optional. */
@@ -19764,11 +19774,15 @@ 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_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 +26068,13 @@ 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 && 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 0000000..734b367
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/friend7.C
@@ -0,0 +1,40 @@
+// 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(); // { dg-error "attribute appertains" }
+ friend void f3 [[deprecated]] (); // { dg-error "attribute appertains" }
+ 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 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" }
+ // { dg-bogus "should have" "PR100339" { xfail *-*-* } .-1 }
+};
+
+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" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C
index 453fc01..4010ba7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C
@@ -2,7 +2,8 @@
int fragile_block(void) {
typedef
- [[gnu::aligned (16)]] // { dg-warning "ignored" }
+ [[gnu::aligned (16)]] // { dg-error "standard attributes in middle of decl-specifiers" }
+// { dg-warning "attribute ignored" "" { target *-*-* } .-1 }
struct {
int i;
} XmmUint16;
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C
index b401c69..c120aed 100644
--- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C
@@ -13,7 +13,8 @@ int one_third [[noreturn]] [[gnu::unused]] (void);
int [[gnu::unused]] one_half(); // { dg-warning "ignored" }
static
-[[noreturn]] // { dg-warning "ignored" }
+[[noreturn]] // { dg-error "standard attributes in middle of decl-specifiers" }
+// { dg-warning "attribute ignored" "" { target *-*-* } .-1 }
void two [[gnu::unused]] (void) {}
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-74.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-74.C
new file mode 100644
index 0000000..7e17bc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-74.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+// A C++11 attribute cannot appear in the middle of the decl-specifier-seq,
+// only before it (in which case it appertains to the declaration) or at
+// the end (in which case it appertains to the type).
+
+struct S {
+ friend [[deprecated]] void; // { dg-error "standard attributes in middle of decl-specifiers" }
+ friend [[deprecated]] int fn(); // { dg-error "standard attributes in middle of decl-specifiers" }
+ // { dg-warning "attribute ignored" "" { target *-*-* } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/ext/attrib63.C b/gcc/testsuite/g++.dg/ext/attrib63.C
new file mode 100644
index 0000000..e515a2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attrib63.C
@@ -0,0 +1,16 @@
+// { dg-do compile }
+
+#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" }
+};
+
+vector float vf;
+vector float
+f ()
+{
+ return vf;
+}