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">;
def err_cxx11_attribute_forbids_ellipsis : Error<
"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<
"default scope specifier for attributes is incompatible with C++ standards "
"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
if (Tok.is(tok::l_paren))
AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,

View File

@ -1,6 +1,6 @@
// 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()]] int m3(); // expected-error {{attribute 'carries_dependency' cannot have an argument list}}

View File

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

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify %s
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 {};
[[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}}
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()]] 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
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}}

View File

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

View File

@ -3,7 +3,7 @@
struct [[maybe_unused]] S1 { // ok
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;
};
struct [[maybe_unused("Wrong")]] S3 { // expected-error {{'maybe_unused' cannot have an argument list}}

View File

@ -3,7 +3,7 @@
struct [[nodiscard]] S1 { // ok
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;
};
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]] 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}}
// unsupported-error@-1 {{cannot appear multiple times}} unsupported-warning@-1 2{{unknown}}
[[no_unique_address, no_unique_address]] int duplicated; // ok
// unsupported-warning@-1 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}}