Implement WG21 P2156R1/WG14 N2557 on duplicate attributes

These proposals make the same changes to both C++ and C and remove a
restriction on standard attributes appearing multiple times in the same
attribute list.

We could warn on the duplicate attributes, but do not. This is for
consistency as we do not warn on attributes duplicated within the
attribute specifier sequence. If we want to warn on duplicated
standard attributes, we should do so both for both situations:
[[foo, foo]] and [[foo]][[foo]].
This commit is contained in:
Aaron Ballman 2021-04-13 12:24:16 -04:00
parent 6666e0d7a2
commit 62328f2f29
11 changed files with 10 additions and 19 deletions

View File

@ -684,8 +684,6 @@ def err_attribute_requires_arguments : Error<
"parentheses must be omitted if %0 attribute's argument list is empty">; "parentheses must be omitted if %0 attribute's argument list is empty">;
def err_cxx11_attribute_forbids_ellipsis : Error< def err_cxx11_attribute_forbids_ellipsis : Error<
"attribute %0 cannot be used as an attribute pack">; "attribute %0 cannot be used as an attribute pack">;
def err_cxx11_attribute_repeated : Error<
"attribute %0 cannot appear multiple times in an attribute specifier">;
def warn_cxx14_compat_using_attribute_ns : Warning< def warn_cxx14_compat_using_attribute_ns : Warning<
"default scope specifier for attributes is incompatible with C++ standards " "default scope specifier for attributes is incompatible with C++ standards "
"before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore;

View File

@ -4260,13 +4260,6 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
} }
} }
bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName);
if (StandardAttr &&
!SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second)
Diag(AttrLoc, diag::err_cxx11_attribute_repeated)
<< AttrName << SourceRange(SeenAttrs[AttrName]);
// Parse attribute arguments // Parse attribute arguments
if (Tok.is(tok::l_paren)) if (Tok.is(tok::l_paren))
AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc, AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify -std=c++11 %s // RUN: %clang_cc1 -verify -std=c++11 %s
[[carries_dependency, carries_dependency]] int m1(); // expected-error {{attribute 'carries_dependency' cannot appear multiple times in an attribute specifier}} [[carries_dependency, carries_dependency]] int m1(); // ok
[[carries_dependency]] [[carries_dependency]] int m2(); // ok [[carries_dependency]] [[carries_dependency]] int m2(); // ok
[[carries_dependency()]] int m3(); // expected-error {{attribute 'carries_dependency' cannot have an argument list}} [[carries_dependency()]] int m3(); // expected-error {{attribute 'carries_dependency' cannot have an argument list}}

View File

@ -61,7 +61,7 @@ void g() {
return; return;
case 0: case 0:
[[fallthrough, fallthrough]]; // expected-error {{multiple times}} [[fallthrough, fallthrough]]; // ok
case 1: case 1:
[[fallthrough(0)]]; // expected-error {{argument list}} [[fallthrough(0)]]; // expected-error {{argument list}}
case 2: case 2:

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify %s // RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify %s
struct [[nodiscard]] S1 {}; // ok struct [[nodiscard]] S1 {}; // ok
struct [[nodiscard, nodiscard]] S2 {}; // expected-error {{attribute 'nodiscard' cannot appear multiple times in an attribute specifier}} struct [[nodiscard, nodiscard]] S2 {}; // ok
struct [[nodiscard("Wrong")]] S3 {}; struct [[nodiscard("Wrong")]] S3 {};
[[nodiscard]] int f(); [[nodiscard]] int f();

View File

@ -14,7 +14,7 @@ template <typename T> void a4 [[noreturn]] () { return; } // expected-warning {{
// expected-warning@-1 {{function 'a4<long>' declared 'noreturn' should not return}} // expected-warning@-1 {{function 'a4<long>' declared 'noreturn' should not return}}
void a4_test() { a4<long>(); } // expected-note {{in instantiation of function template specialization 'a4<long>' requested here}} void a4_test() { a4<long>(); } // expected-note {{in instantiation of function template specialization 'a4<long>' requested here}}
[[noreturn, noreturn]] void b() { throw 0; } // expected-error {{attribute 'noreturn' cannot appear multiple times in an attribute specifier}} [[noreturn, noreturn]] void b() { throw 0; } // ok
[[noreturn]] [[noreturn]] void b2() { throw 0; } // ok [[noreturn]] [[noreturn]] void b2() { throw 0; } // ok
[[noreturn()]] void c(); // expected-error {{attribute 'noreturn' cannot have an argument list}} [[noreturn()]] void c(); // expected-error {{attribute 'noreturn' cannot have an argument list}}

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++1z -verify %s // RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++1z -verify %s
struct [[maybe_unused]] S1 {}; // ok struct [[maybe_unused]] S1 {}; // ok
struct [[maybe_unused, maybe_unused]] S2 {}; // expected-error {{attribute 'maybe_unused' cannot appear multiple times in an attribute specifier}} struct [[maybe_unused, maybe_unused]] S2 {}; // ok
struct [[maybe_unused("Wrong")]] S3 {}; // expected-error {{'maybe_unused' cannot have an argument list}} struct [[maybe_unused("Wrong")]] S3 {}; // expected-error {{'maybe_unused' cannot have an argument list}}

View File

@ -65,7 +65,7 @@ void g(void) {
return; return;
case 0: case 0:
[[fallthrough, fallthrough]]; // expected-error {{multiple times}} [[fallthrough, fallthrough]]; // ok
case 1: case 1:
[[fallthrough(0)]]; // expected-error {{argument list}} [[fallthrough(0)]]; // expected-error {{argument list}}
case 2: case 2:

View File

@ -3,7 +3,7 @@
struct [[maybe_unused]] S1 { // ok struct [[maybe_unused]] S1 { // ok
int a [[maybe_unused]]; int a [[maybe_unused]];
}; };
struct [[maybe_unused, maybe_unused]] S2 { // expected-error {{attribute 'maybe_unused' cannot appear multiple times in an attribute specifier}} struct [[maybe_unused, maybe_unused]] S2 { // ok
int a; int a;
}; };
struct [[maybe_unused("Wrong")]] S3 { // expected-error {{'maybe_unused' cannot have an argument list}} struct [[maybe_unused("Wrong")]] S3 { // expected-error {{'maybe_unused' cannot have an argument list}}

View File

@ -3,7 +3,7 @@
struct [[nodiscard]] S1 { // ok struct [[nodiscard]] S1 { // ok
int i; int i;
}; };
struct [[nodiscard, nodiscard]] S2 { // expected-error {{attribute 'nodiscard' cannot appear multiple times in an attribute specifier}} struct [[nodiscard, nodiscard]] S2 { // ok
int i; int i;
}; };
struct [[nodiscard("Wrong")]] S3 { // FIXME: may need an extension warning. struct [[nodiscard("Wrong")]] S3 { // FIXME: may need an extension warning.

View File

@ -10,8 +10,8 @@ struct [[no_unique_address]] S { // expected-error {{only applies to non-bit-fie
[[no_unique_address]] static void sf(); // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}} [[no_unique_address]] static void sf(); // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
[[no_unique_address]] int b : 3; // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}} [[no_unique_address]] int b : 3; // expected-error {{only applies to non-bit-field non-static data members}} unsupported-warning {{unknown}}
[[no_unique_address, no_unique_address]] int duplicated; // expected-error {{cannot appear multiple times}} [[no_unique_address, no_unique_address]] int duplicated; // ok
// unsupported-error@-1 {{cannot appear multiple times}} unsupported-warning@-1 2{{unknown}} // unsupported-warning@-1 2{{unknown}}
[[no_unique_address]] [[no_unique_address]] int duplicated2; // unsupported-warning 2{{unknown}} [[no_unique_address]] [[no_unique_address]] int duplicated2; // unsupported-warning 2{{unknown}}
[[no_unique_address()]] int arglist; // expected-error {{cannot have an argument list}} unsupported-warning {{unknown}} [[no_unique_address()]] int arglist; // expected-error {{cannot have an argument list}} unsupported-warning {{unknown}}