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]].

GitOrigin-RevId: 62328f2f29b432dadbd327ff91ba3914c478e3fc
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index b0f9b31..8b3da90 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -684,8 +684,6 @@
   "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;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index e1d29f5..bc59b41 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -4260,13 +4260,6 @@
       }
     }
 
-    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,
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp
index 6cf27af..424b159 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp
@@ -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}}
 
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
index 22815bb..675ab3e 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
@@ -61,7 +61,7 @@
     return;
 
   case 0:
-    [[fallthrough, fallthrough]]; // expected-error {{multiple times}}
+    [[fallthrough, fallthrough]]; // ok
   case 1:
     [[fallthrough(0)]]; // expected-error {{argument list}}
   case 2:
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp
index 982f18f..142d4d6 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp
@@ -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();
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
index d92356c..49c1106 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
@@ -14,7 +14,7 @@
                                                           // 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}}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
index 6c9b8a7..2cee3cb 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
@@ -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}}
diff --git a/test/Sema/c2x-fallthrough.c b/test/Sema/c2x-fallthrough.c
index e5508e0..baa62aa 100644
--- a/test/Sema/c2x-fallthrough.c
+++ b/test/Sema/c2x-fallthrough.c
@@ -65,7 +65,7 @@
     return;
 
   case 0:
-    [[fallthrough, fallthrough]]; // expected-error {{multiple times}}
+    [[fallthrough, fallthrough]]; // ok
   case 1:
     [[fallthrough(0)]]; // expected-error {{argument list}}
   case 2:
diff --git a/test/Sema/c2x-maybe_unused-errors.c b/test/Sema/c2x-maybe_unused-errors.c
index 5d3eb4d..72cefd1 100644
--- a/test/Sema/c2x-maybe_unused-errors.c
+++ b/test/Sema/c2x-maybe_unused-errors.c
@@ -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}}
diff --git a/test/Sema/c2x-nodiscard.c b/test/Sema/c2x-nodiscard.c
index f62ba27..8124217 100644
--- a/test/Sema/c2x-nodiscard.c
+++ b/test/Sema/c2x-nodiscard.c
@@ -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.
diff --git a/test/SemaCXX/cxx2a-no-unique-address.cpp b/test/SemaCXX/cxx2a-no-unique-address.cpp
index 107466e..44d6d3a 100644
--- a/test/SemaCXX/cxx2a-no-unique-address.cpp
+++ b/test/SemaCXX/cxx2a-no-unique-address.cpp
@@ -10,8 +10,8 @@
   [[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}}