Author: Richard Sandiford
Date: 2023-05-31T10:43:10+01:00
New Revision: 33ee5c4663465022ffe288817968e90064d88a09

URL: 
https://github.com/llvm/llvm-project/commit/33ee5c4663465022ffe288817968e90064d88a09
DIFF: 
https://github.com/llvm/llvm-project/commit/33ee5c4663465022ffe288817968e90064d88a09.diff

LOG: [clang] Add Parse and Sema support for RegularKeyword attributes

This patch adds the Parse and Sema support for RegularKeyword attributes,
following on from a previous patch that added Attr.td support.

The patch is quite large.  However, nothing outside the tests is
specific to the first RegularKeyword attribute (__arm_streaming).
The patch should therefore be a one-off, up-front cost.  Other
attributes just need an entry in Attr.td and the usual Sema support.

The approach taken in the patch is that the keywords can be used with
any language version.  If standard attributes were added in language
version Y, the keyword rules for version X<Y are the same as they were
for version Y (to the extent possible).  Any extensions beyond Y are
handled in the same way for both keywords and attributes.  This ensures
that existing C++11 successors like C++17 are not treated differently
from versions that have yet to be defined.

Some notes on the implementation:

* The patch emits errors rather than warnings for diagnostics that
relate to keywords.

* Where possible, the patch drops “attribute” from diagnostics
relating to keywords.

* One exception to the previous point is that warnings about C++
extensions do still mention attributes.  The use there seemed OK
since the diagnostics are noting a change in the production rules.

* If a diagnostic string needs to be different for keywords and
attributes, the patch standardizes on passing the attribute/
name/token followed by 0 for attributes and 1 for keywords.

* Although the patch updates warn_attribute_wrong_decl_type_str,
warn_attribute_wrong_decl_type, and warn_attribute_wrong_decl_type,
only the error forms of these strings are used for keywords.

* I couldn't trigger the warnings in checkUnusedDeclAttributes,
even for existing attributes.  An assert on the warnings caused
no failures in the testsuite.  I think in practice all standard
attributes would be diagnosed before this.

* The patch drops a call to standardAttributesAllowed in
ParseFunctionDeclarator.  This is because MaybeParseCXX11Attributes
checks the same thing itself, where appropriate.

* The new tests are based on c2x-attributes.c and
cxx0x-attributes.cpp.  The C++ test also incorporates a version of
cxx11-base-spec-attributes.cpp.  The FIXMEs are carried across from
the originals.

Differential Revision: https://reviews.llvm.org/D148702

Added: 
    clang/test/Parser/c2x-attribute-keywords.c
    clang/test/Parser/c2x-attribute-keywords.m
    clang/test/Parser/cxx0x-keyword-attributes.cpp

Modified: 
    clang/examples/Attribute/Attribute.cpp
    clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp
    clang/include/clang/Basic/DiagnosticCommonKinds.td
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/DeclSpec.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Parse/ParsePragma.cpp
    clang/lib/Parse/ParseStmt.cpp
    clang/lib/Parse/ParseTentative.cpp
    clang/lib/Parse/Parser.cpp
    clang/lib/Sema/ParsedAttr.cpp
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaStmtAttr.cpp
    clang/lib/Sema/SemaType.cpp
    clang/utils/TableGen/ClangAttrEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/examples/Attribute/Attribute.cpp 
b/clang/examples/Attribute/Attribute.cpp
index 24b95dde4e559..008da2e18e44f 100644
--- a/clang/examples/Attribute/Attribute.cpp
+++ b/clang/examples/Attribute/Attribute.cpp
@@ -43,7 +43,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
     // This attribute appertains to functions only.
     if (!isa<FunctionDecl>(D)) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-          << Attr << "functions";
+          << Attr << Attr.isRegularKeywordAttribute() << "functions";
       return false;
     }
     return true;

diff  --git a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp 
b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp
index 21460e4f6bd06..12d4c311586e6 100644
--- a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp
+++ b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp
@@ -169,7 +169,7 @@ struct CallSuperAttrInfo : public ParsedAttrInfo {
     const auto *TheMethod = dyn_cast_or_null<CXXMethodDecl>(D);
     if (!TheMethod || !TheMethod->isVirtual()) {
       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-          << Attr << "virtual functions";
+          << Attr << Attr.isRegularKeywordAttribute() << "virtual functions";
       return false;
     }
     MarkedMethods.insert(TheMethod);

diff  --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td 
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 42d8a0abfbceb..eb1649cc238a5 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -121,7 +121,7 @@ def note_pragma_entered_here : Note<"#pragma entered here">;
 def note_decl_hiding_tag_type : Note<
   "%1 %0 is hidden by a non-type declaration of %0 here">;
 def err_attribute_not_type_attr : Error<
-  "%0 attribute cannot be applied to types">;
+  "%0%select{ attribute|}1 cannot be applied to types">;
 def err_enum_template : Error<"enumeration cannot be a template">;
 
 def warn_cxx20_compat_consteval : Warning<
@@ -175,6 +175,8 @@ def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
 def warn_attribute_ignored : Warning<"%0 attribute ignored">,
   InGroup<IgnoredAttributes>;
+def err_keyword_not_supported_on_target : Error<
+  "%0 is not supported on this target">;
 def err_use_of_tag_name_without_tag : Error<
   "must use '%1' tag to refer to type %0%select{| in this scope}2">;
 

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 5d5048a7d2c04..d015628db7f23 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -733,10 +733,12 @@ def ext_using_attribute_ns : ExtWarn<
 def err_using_attribute_ns_conflict : Error<
   "attribute with scope specifier cannot follow default scope specifier">;
 def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
+def err_keyword_not_allowed : Error<"%0 cannot appear here">;
 def ext_cxx11_attr_placement : ExtWarn<
-  "ISO C++ does not allow an attribute list to appear here">,
+  "ISO C++ does not allow %select{an attribute list|%0}1 to appear here">,
   InGroup<DiagGroup<"cxx-attribute-extension">>;
 def err_attributes_misplaced : Error<"misplaced attributes; expected 
attributes here">;
+def err_keyword_misplaced : Error<"misplaced %0; expected %0 here">;
 def err_l_square_l_square_not_attribute : Error<
   "C++11 only allows consecutive left square brackets when "
   "introducing an attribute">;
@@ -1014,14 +1016,15 @@ def err_lambda_capture_multiple_ellipses : Error<
 def err_capture_default_first : Error<
   "capture default must be first">;
 def ext_decl_attrs_on_lambda : ExtWarn<
-  "an attribute specifier sequence in this position is a C++23 extension">,
-  InGroup<CXX23>;
+  "%select{an attribute specifier sequence|%0}1 in this position "
+  "is a C++23 extension">, InGroup<CXX23>;
 def ext_lambda_missing_parens : ExtWarn<
   "lambda without a parameter clause is a C++23 extension">,
   InGroup<CXX23>;
 def warn_cxx20_compat_decl_attrs_on_lambda : Warning<
-  "an attribute specifier sequence in this position is incompatible with C++ "
-  "standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
+  "%select{an attribute specifier sequence|%1}0 in this position "
+  "is incompatible with C++ standards before C++23">,
+  InGroup<CXXPre23Compat>, DefaultIgnore;
 
 // C++17 lambda expressions
 def err_expected_star_this_capture : Error<
@@ -1582,8 +1585,12 @@ def err_module_expected_ident : Error<
   "expected a module name after '%select{module|import}0'">;
 def err_attribute_not_module_attr : Error<
   "%0 attribute cannot be applied to a module">;
+def err_keyword_not_module_attr : Error<
+  "%0 cannot be applied to a module">;
 def err_attribute_not_import_attr : Error<
   "%0 attribute cannot be applied to a module import">;
+def err_keyword_not_import_attr : Error<
+  "%0 cannot be applied to a module import">;
 def err_module_expected_semi : Error<
   "expected ';' after module name">;
 def err_global_module_introducer_not_at_start : Error<

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3edffbe190273..4847509ae1ec3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3022,7 +3022,7 @@ def err_musttail_no_variadic : Error<
 def err_nsobject_attribute : Error<
   "'NSObject' attribute is for pointer types only">;
 def err_attributes_are_not_compatible : Error<
-  "%0 and %1 attributes are not compatible">;
+  "%0 and %1%select{ attributes|}2 are not compatible">;
 def err_attribute_invalid_argument : Error<
   "%select{a reference type|an array type|a non-vector or "
   "non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
@@ -3430,9 +3430,9 @@ def warn_attribute_has_no_effect_on_compile_time_if : 
Warning<
 def note_attribute_has_no_effect_on_compile_time_if_here : Note<
   "annotating the 'if %select{constexpr|consteval}0' statement here">;
 def err_decl_attribute_invalid_on_stmt : Error<
-  "%0 attribute cannot be applied to a statement">;
+  "%0%select{ attribute|}1 cannot be applied to a statement">;
 def err_attribute_invalid_on_decl : Error<
-  "%0 attribute cannot be applied to a declaration">;
+  "%0%select{ attribute|}1 cannot be applied to a declaration">;
 def warn_type_attribute_deprecated_on_decl : Warning<
   "applying attribute %0 to a declaration is deprecated; apply it to the type 
instead">,
   InGroup<DeprecatedAttributes>;
@@ -3440,6 +3440,10 @@ def warn_declspec_attribute_ignored : Warning<
   "attribute %0 is ignored, place it after "
   "\"%select{class|struct|interface|union|enum|enum class|enum struct}1\" to 
apply attribute to "
   "type declaration">, InGroup<IgnoredAttributes>;
+def err_declspec_keyword_has_no_effect : Error<
+  "%0 cannot appear here, place it after "
+  "\"%select{class|struct|interface|union|enum}1\" to apply it to the "
+  "type declaration">;
 def warn_attribute_precede_definition : Warning<
   "attribute declaration must precede definition">,
   InGroup<IgnoredAttributes>;
@@ -3538,11 +3542,11 @@ def err_attribute_weakref_without_alias : Error<
 def err_alias_not_supported_on_darwin : Error <
   "aliases are not supported on darwin">;
 def warn_attribute_wrong_decl_type_str : Warning<
-  "%0 attribute only applies to %1">, InGroup<IgnoredAttributes>;
+  "%0%select{ attribute|}1 only applies to %2">, InGroup<IgnoredAttributes>;
 def err_attribute_wrong_decl_type_str : Error<
   warn_attribute_wrong_decl_type_str.Summary>;
 def warn_attribute_wrong_decl_type : Warning<
-  "%0 attribute only applies to %select{"
+  "%0%select{ attribute|}1 only applies to %select{"
   "functions"
   "|unions"
   "|variables and functions"
@@ -3555,13 +3559,15 @@ def warn_attribute_wrong_decl_type : Warning<
   "|types and namespaces"
   "|variables, functions and classes"
   "|kernel functions"
-  "|non-K&R-style functions}1">,
+  "|non-K&R-style functions}2">,
   InGroup<IgnoredAttributes>;
 def err_attribute_wrong_decl_type : 
Error<warn_attribute_wrong_decl_type.Summary>;
 def warn_type_attribute_wrong_type : Warning<
   "'%0' only applies to %select{function|pointer|"
   "Objective-C object or block pointer}1 types; type here is %2">,
   InGroup<IgnoredAttributes>;
+def err_type_attribute_wrong_type : Error<
+  warn_type_attribute_wrong_type.Summary>;
 def warn_incomplete_encoded_type : Warning<
   "encoding of %0 type is incomplete because %1 component has unknown 
encoding">,
   InGroup<DiagGroup<"encode-type">>;
@@ -3612,7 +3618,7 @@ def err_invalid_pcs : Error<"invalid PCS type">;
 def warn_attribute_not_on_decl : Warning<
   "%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
 def err_base_specifier_attribute : Error<
-  "%0 attribute cannot be applied to a base specifier">;
+  "%0%select{ attribute|}1 cannot be applied to a base specifier">;
 def warn_declspec_allocator_nonpointer : Warning<
   "ignoring __declspec(allocator) because the function return type %0 is not "
   "a pointer or reference type">, InGroup<IgnoredAttributes>;

diff  --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 43ea50a71f744..992d92c990e11 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2691,6 +2691,18 @@ class Parser : public CodeCompletionHandler {
     return LO.DoubleSquareBracketAttributes;
   }
 
+  /// Return true if the next token should be treated as a [[]] attribute,
+  /// or as a keyword that behaves like one.  The former is only true if
+  /// [[]] attributes are enabled, whereas the latter is true whenever
+  /// such a keyword appears.  The arguments are as for
+  /// isCXX11AttributeSpecifier.
+  bool isAllowedCXX11AttributeSpecifier(bool Disambiguate = false,
+                                        bool OuterMightBeMessageSend = false) {
+    return (Tok.isRegularKeywordAttribute() ||
+            (standardAttributesAllowed() &&
+             isCXX11AttributeSpecifier(Disambiguate, 
OuterMightBeMessageSend)));
+  }
+
   // Check for the start of an attribute-specifier-seq in a context where an
   // attribute is not allowed.
   bool CheckProhibitedCXX11Attribute() {
@@ -2703,11 +2715,13 @@ class Parser : public CodeCompletionHandler {
   bool DiagnoseProhibitedCXX11Attribute();
   void CheckMisplacedCXX11Attribute(ParsedAttributes &Attrs,
                                     SourceLocation CorrectLocation) {
-    if (!standardAttributesAllowed())
-      return;
-    if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
-        Tok.isNot(tok::kw_alignas))
-      return;
+    if (!Tok.isRegularKeywordAttribute()) {
+      if (!standardAttributesAllowed())
+        return;
+      if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
+          Tok.isNot(tok::kw_alignas))
+        return;
+    }
     DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation);
   }
   void DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs,
@@ -2721,7 +2735,7 @@ class Parser : public CodeCompletionHandler {
                           SourceLocation FixItLoc = SourceLocation()) {
     if (Attrs.Range.isInvalid())
       return;
-    DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc);
+    DiagnoseProhibitedAttributes(Attrs, FixItLoc);
     Attrs.clear();
   }
 
@@ -2729,10 +2743,10 @@ class Parser : public CodeCompletionHandler {
                           SourceLocation FixItLoc = SourceLocation()) {
     if (Attrs.Range.isInvalid())
       return;
-    DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc);
+    DiagnoseProhibitedAttributes(Attrs, FixItLoc);
     Attrs.clearListOnly();
   }
-  void DiagnoseProhibitedAttributes(const SourceRange &Range,
+  void DiagnoseProhibitedAttributes(const ParsedAttributesView &Attrs,
                                     SourceLocation FixItLoc);
 
   // Forbid C++11 and C2x attributes that appear on certain syntactic locations
@@ -2741,7 +2755,8 @@ class Parser : public CodeCompletionHandler {
   // For the most cases we don't want to warn on unknown type attributes, but
   // left them to later diagnoses. However, for a few cases like module
   // declarations and module import declarations, we should do it.
-  void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
+  void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID,
+                               unsigned KeywordDiagId,
                                bool DiagnoseEmptyAttrs = false,
                                bool WarnOnUnknownAttrs = false);
 
@@ -2795,7 +2810,7 @@ class Parser : public CodeCompletionHandler {
   bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs,
                             LateParsedAttrList *LateAttrs = nullptr) {
     if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) ||
-        (standardAttributesAllowed() && isCXX11AttributeSpecifier())) {
+        isAllowedCXX11AttributeSpecifier()) {
       ParseAttributes(WhichAttrKinds, Attrs, LateAttrs);
       return true;
     }
@@ -2847,7 +2862,7 @@ class Parser : public CodeCompletionHandler {
     }
   }
   void MaybeParseCXX11Attributes(Declarator &D) {
-    if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
+    if (isAllowedCXX11AttributeSpecifier()) {
       ParsedAttributes Attrs(AttrFactory);
       ParseCXX11Attributes(Attrs);
       D.takeAttributes(Attrs);
@@ -2856,8 +2871,7 @@ class Parser : public CodeCompletionHandler {
 
   bool MaybeParseCXX11Attributes(ParsedAttributes &Attrs,
                                  bool OuterMightBeMessageSend = false) {
-    if (standardAttributesAllowed() &&
-        isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
+    if (isAllowedCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
       ParseCXX11Attributes(Attrs);
       return true;
     }

diff  --git a/clang/include/clang/Sema/DeclSpec.h 
b/clang/include/clang/Sema/DeclSpec.h
index b0bf87dc18d79..c63378c732908 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1972,9 +1972,10 @@ class Declarator {
         InventedTemplateParameterList(nullptr) {
     assert(llvm::all_of(DeclarationAttrs,
                         [](const ParsedAttr &AL) {
-                          return AL.isStandardAttributeSyntax();
+                          return (AL.isStandardAttributeSyntax() ||
+                                  AL.isRegularKeywordAttribute());
                         }) &&
-           "DeclarationAttrs may only contain [[]] attributes");
+           "DeclarationAttrs may only contain [[]] and keyword attributes");
   }
 
   ~Declarator() {
@@ -2619,14 +2620,6 @@ class Declarator {
     return false;
   }
 
-  /// Return a source range list of C++11 attributes associated
-  /// with the declarator.
-  void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &Ranges) {
-    for (const ParsedAttr &AL : Attrs)
-      if (AL.isCXX11Attribute())
-        Ranges.push_back(AL.getRange());
-  }
-
   void setAsmLabel(Expr *E) { AsmLabel = E; }
   Expr *getAsmLabel() const { return AsmLabel; }
 

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0e62f0dff980f..da1d17d14c4c8 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1693,30 +1693,43 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
 void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs,
                                              SourceLocation CorrectLocation) {
   assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
-         Tok.is(tok::kw_alignas));
+         Tok.is(tok::kw_alignas) || Tok.isRegularKeywordAttribute());
 
   // Consume the attributes.
+  auto Keyword =
+      Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr;
   SourceLocation Loc = Tok.getLocation();
   ParseCXX11Attributes(Attrs);
   CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true);
   // FIXME: use err_attributes_misplaced
-  Diag(Loc, diag::err_attributes_not_allowed)
-    << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
-    << FixItHint::CreateRemoval(AttrRange);
+  (Keyword ? Diag(Loc, diag::err_keyword_not_allowed) << Keyword
+           : Diag(Loc, diag::err_attributes_not_allowed))
+      << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
+      << FixItHint::CreateRemoval(AttrRange);
 }
 
 void Parser::DiagnoseProhibitedAttributes(
-    const SourceRange &Range, const SourceLocation CorrectLocation) {
+    const ParsedAttributesView &Attrs, const SourceLocation CorrectLocation) {
+  auto *FirstAttr = Attrs.empty() ? nullptr : &Attrs.front();
   if (CorrectLocation.isValid()) {
-    CharSourceRange AttrRange(Range, true);
-    Diag(CorrectLocation, diag::err_attributes_misplaced)
+    CharSourceRange AttrRange(Attrs.Range, true);
+    (FirstAttr && FirstAttr->isRegularKeywordAttribute()
+         ? Diag(CorrectLocation, diag::err_keyword_misplaced) << FirstAttr
+         : Diag(CorrectLocation, diag::err_attributes_misplaced))
         << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
         << FixItHint::CreateRemoval(AttrRange);
-  } else
-    Diag(Range.getBegin(), diag::err_attributes_not_allowed) << Range;
+  } else {
+    const SourceRange &Range = Attrs.Range;
+    (FirstAttr && FirstAttr->isRegularKeywordAttribute()
+         ? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr
+         : Diag(Range.getBegin(), diag::err_attributes_not_allowed))
+        << Range;
+  }
 }
 
-void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
+void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs,
+                                     unsigned AttrDiagID,
+                                     unsigned KeywordDiagID,
                                      bool DiagnoseEmptyAttrs,
                                      bool WarnOnUnknownAttrs) {
 
@@ -1736,13 +1749,18 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes 
&Attrs, unsigned DiagID,
         // The attribute range starts with [[, but is empty. So this must
         // be [[]], which we are supposed to diagnose because
         // DiagnoseEmptyAttrs is true.
-        Diag(Attrs.Range.getBegin(), DiagID) << Attrs.Range;
+        Diag(Attrs.Range.getBegin(), AttrDiagID) << Attrs.Range;
         return;
       }
     }
   }
 
   for (const ParsedAttr &AL : Attrs) {
+    if (AL.isRegularKeywordAttribute()) {
+      Diag(AL.getLoc(), KeywordDiagID) << AL;
+      AL.setInvalid();
+      continue;
+    }
     if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
       continue;
     if (AL.getKind() == ParsedAttr::UnknownAttribute) {
@@ -1750,7 +1768,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes 
&Attrs, unsigned DiagID,
         Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
             << AL << AL.getRange();
     } else {
-      Diag(AL.getLoc(), DiagID) << AL;
+      Diag(AL.getLoc(), AttrDiagID) << AL;
       AL.setInvalid();
     }
   }
@@ -1758,8 +1776,10 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes 
&Attrs, unsigned DiagID,
 
 void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) {
   for (const ParsedAttr &PA : Attrs) {
-    if (PA.isCXX11Attribute() || PA.isC2xAttribute())
-      Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange();
+    if (PA.isCXX11Attribute() || PA.isC2xAttribute() ||
+        PA.isRegularKeywordAttribute())
+      Diag(PA.getLoc(), diag::ext_cxx11_attr_placement)
+          << PA << PA.isRegularKeywordAttribute() << PA.getRange();
   }
 }
 
@@ -1991,11 +2011,11 @@ bool Parser::MightBeDeclarator(DeclaratorContext 
Context) {
       return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken());
 
     default:
-      return false;
+      return Tok.isRegularKeywordAttribute();
     }
 
   default:
-    return false;
+    return Tok.isRegularKeywordAttribute();
   }
 }
 
@@ -3298,13 +3318,17 @@ void Parser::ParseDeclarationSpecifiers(
 
     switch (Tok.getKind()) {
     default:
+      if (Tok.isRegularKeywordAttribute())
+        goto Attribute;
+
     DoneWithDeclSpec:
       if (!AttrsLastTime)
         ProhibitAttributes(attrs);
       else {
         // Reject C++11 / C2x attributes that aren't type attributes.
         for (const ParsedAttr &PA : attrs) {
-          if (!PA.isCXX11Attribute() && !PA.isC2xAttribute())
+          if (!PA.isCXX11Attribute() && !PA.isC2xAttribute() &&
+              !PA.isRegularKeywordAttribute())
             continue;
           if (PA.getKind() == ParsedAttr::UnknownAttribute)
             // We will warn about the unknown attribute elsewhere (in
@@ -3323,7 +3347,8 @@ void Parser::ParseDeclarationSpecifiers(
           if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound 
&&
               PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck)
             continue;
-          Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
+          Diag(PA.getLoc(), diag::err_attribute_not_type_attr)
+              << PA << PA.isRegularKeywordAttribute();
           PA.setInvalid();
         }
 
@@ -3337,9 +3362,10 @@ void Parser::ParseDeclarationSpecifiers(
 
     case tok::l_square:
     case tok::kw_alignas:
-      if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier())
+      if (!isAllowedCXX11AttributeSpecifier())
         goto DoneWithDeclSpec;
 
+    Attribute:
       ProhibitAttributes(attrs);
       // FIXME: It would be good to recover by accepting the attributes,
       //        but attempting to do that now would cause serious
@@ -5015,6 +5041,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
   if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt &&
       !getLangOpts().ObjC) {
     ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+                            diag::err_keyword_not_allowed,
                             /*DiagnoseEmptyAttrs=*/true);
     if (BaseType.isUsable())
       Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
@@ -5160,7 +5187,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl 
*EnumDecl) {
     // If attributes exist after the enumerator, parse them.
     ParsedAttributes attrs(AttrFactory);
     MaybeParseGNUAttributes(attrs);
-    if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
+    if (isAllowedCXX11AttributeSpecifier()) {
       if (getLangOpts().CPlusPlus)
         Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
                                     ? diag::warn_cxx14_compat_ns_enum_attribute
@@ -5885,8 +5912,8 @@ void Parser::ParseTypeQualifierListOpt(
     DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
     bool IdentifierRequired,
     std::optional<llvm::function_ref<void()>> CodeCompletionHandler) {
-  if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
-      isCXX11AttributeSpecifier()) {
+  if ((AttrReqs & AR_CXX11AttributesParsed) &&
+      isAllowedCXX11AttributeSpecifier()) {
     ParsedAttributes Attrs(AttrFactory);
     ParseCXX11Attributes(Attrs);
     DS.takeAttributesFrom(Attrs);
@@ -6660,6 +6687,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
       PrototypeScope.Exit();
     } else if (Tok.is(tok::l_square)) {
       ParseBracketDeclarator(D);
+    } else if (Tok.isRegularKeywordAttribute()) {
+      // For consistency with attribute parsing.
+      Diag(Tok, diag::err_keyword_not_allowed) << Tok.getIdentifierInfo();
+      ConsumeToken();
     } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) {
       // This declarator is declaring a function, but the requires clause is
       // in the wrong place:
@@ -7064,7 +7095,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
         TrailingReturnTypeLoc = Range.getBegin();
         EndLoc = Range.getEnd();
       }
-    } else if (standardAttributesAllowed()) {
+    } else {
       MaybeParseCXX11Attributes(FnAttrs);
     }
   }

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp 
b/clang/lib/Parse/ParseDeclCXX.cpp
index 717c014520892..32c928e5031b2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -635,6 +635,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
       Tok.is(tok::identifier) &&
       (NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
        NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) ||
+       NextToken().isRegularKeywordAttribute() ||
        NextToken().is(tok::kw___attribute)) &&
       D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
       !D.SS.getScopeRep()->getAsNamespace() &&
@@ -767,11 +768,15 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
   // If we had any misplaced attributes from earlier, this is where they
   // should have been written.
   if (MisplacedAttrs.Range.isValid()) {
-    Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
+    auto *FirstAttr =
+        MisplacedAttrs.empty() ? nullptr : &MisplacedAttrs.front();
+    auto &Range = MisplacedAttrs.Range;
+    (FirstAttr && FirstAttr->isRegularKeywordAttribute()
+         ? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr
+         : Diag(Range.getBegin(), diag::err_attributes_not_allowed))
         << FixItHint::CreateInsertionFromRange(
-               Tok.getLocation(),
-               CharSourceRange::getTokenRange(MisplacedAttrs.Range))
-        << FixItHint::CreateRemoval(MisplacedAttrs.Range);
+               Tok.getLocation(), CharSourceRange::getTokenRange(Range))
+        << FixItHint::CreateRemoval(Range);
     Attrs.takeAllFrom(MisplacedAttrs);
   }
 
@@ -1384,6 +1389,8 @@ bool Parser::isValidAfterTypeSpecifier(bool 
CouldBeBitfield) {
   // This switch enumerates the valid "follow" set for type-specifiers.
   switch (Tok.getKind()) {
   default:
+    if (Tok.isRegularKeywordAttribute())
+      return true;
     break;
   case tok::semi:              // struct foo {...} ;
   case tok::star:              // struct foo {...} *         P;
@@ -1841,6 +1848,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
   } else if (isClassCompatibleKeyword() &&
              (NextToken().is(tok::l_square) ||
               NextToken().is(tok::kw_alignas) ||
+              NextToken().isRegularKeywordAttribute() ||
               isCXX11VirtSpecifier(NextToken()) != VirtSpecifiers::VS_None)) {
     // We can't tell if this is a definition or reference
     // until we skipped the 'final' and C++11 attribute specifiers.
@@ -1862,6 +1870,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
         ConsumeParen();
         if (!SkipUntil(tok::r_paren, StopAtSemi))
           break;
+      } else if (Tok.isRegularKeywordAttribute()) {
+        ConsumeToken();
       } else {
         break;
       }
@@ -1898,7 +1908,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
     // them to the right place.
     SourceRange AttrRange = Attributes.Range;
     if (AttrRange.isValid()) {
-      Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
+      auto *FirstAttr = Attributes.empty() ? nullptr : &Attributes.front();
+      auto Loc = AttrRange.getBegin();
+      (FirstAttr && FirstAttr->isRegularKeywordAttribute()
+           ? Diag(Loc, diag::err_keyword_not_allowed) << FirstAttr
+           : Diag(Loc, diag::err_attributes_not_allowed))
           << AttrRange
           << FixItHint::CreateInsertionFromRange(
                  AttrFixitLoc, CharSourceRange(AttrRange, true))
@@ -1946,6 +1960,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
                TUK == Sema::TUK_Declaration) {
       // This is an explicit instantiation of a class template.
       ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+                              diag::err_keyword_not_allowed,
                               /*DiagnoseEmptyAttrs=*/true);
 
       TagOrTempResult = Actions.ActOnExplicitInstantiation(
@@ -1962,6 +1977,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
                (TUK == Sema::TUK_Friend &&
                 TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
       ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+                              diag::err_keyword_not_allowed,
                               /*DiagnoseEmptyAttrs=*/true);
       TypeResult = Actions.ActOnTagTemplateIdType(
           TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc,
@@ -2031,6 +2047,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
   } else if (TUK == Sema::TUK_Friend &&
              TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
     ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+                            diag::err_keyword_not_allowed,
                             /*DiagnoseEmptyAttrs=*/true);
 
     TagOrTempResult = Actions.ActOnTemplatedFriendTag(
@@ -2041,6 +2058,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind 
TagTokKind,
   } else {
     if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
       ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
+                              diag::err_keyword_not_allowed,
                               /* DiagnoseEmptyAttrs=*/true);
 
     if (TUK == Sema::TUK_Definition &&
@@ -3017,12 +3035,14 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier 
AS,
       //
       // Diagnose attributes that appear in a friend member function 
declarator:
       //   friend int foo [[]] ();
-      SmallVector<SourceRange, 4> Ranges;
-      DeclaratorInfo.getCXX11AttributeRanges(Ranges);
-      for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
-                                                  E = Ranges.end();
-           I != E; ++I)
-        Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
+      for (const ParsedAttr &AL : DeclaratorInfo.getAttributes())
+        if (AL.isCXX11Attribute() || AL.isRegularKeywordAttribute()) {
+          auto Loc = AL.getRange().getBegin();
+          (AL.isRegularKeywordAttribute()
+               ? Diag(Loc, diag::err_keyword_not_allowed) << AL
+               : Diag(Loc, diag::err_attributes_not_allowed))
+              << AL.getRange();
+        }
 
       ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
                                                  TemplateParams);
@@ -4470,6 +4490,14 @@ void 
Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
     return;
   }
 
+  if (Tok.isRegularKeywordAttribute()) {
+    SourceLocation Loc = Tok.getLocation();
+    IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+    Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Tok.getKind());
+    ConsumeToken();
+    return;
+  }
+
   assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) &&
          "Not a double square bracket attribute list");
 
@@ -4589,26 +4617,30 @@ void 
Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
 /// attribute-specifier-seq:
 ///       attribute-specifier-seq[opt] attribute-specifier
 void Parser::ParseCXX11Attributes(ParsedAttributes &Attrs) {
-  assert(standardAttributesAllowed());
+  assert(standardAttributesAllowed() || Tok.isRegularKeywordAttribute());
 
   SourceLocation StartLoc = Tok.getLocation();
   SourceLocation EndLoc = StartLoc;
 
   do {
     ParseCXX11AttributeSpecifier(Attrs, &EndLoc);
-  } while (isCXX11AttributeSpecifier());
+  } while (isAllowedCXX11AttributeSpecifier());
 
   Attrs.Range = SourceRange(StartLoc, EndLoc);
 }
 
 void Parser::DiagnoseAndSkipCXX11Attributes() {
+  auto Keyword =
+      Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr;
   // Start and end location of an attribute or an attribute list.
   SourceLocation StartLoc = Tok.getLocation();
   SourceLocation EndLoc = SkipCXX11Attributes();
 
   if (EndLoc.isValid()) {
     SourceRange Range(StartLoc, EndLoc);
-    Diag(StartLoc, diag::err_attributes_not_allowed) << Range;
+    (Keyword ? Diag(StartLoc, diag::err_keyword_not_allowed) << Keyword
+             : Diag(StartLoc, diag::err_attributes_not_allowed))
+        << Range;
   }
 }
 
@@ -4624,6 +4656,9 @@ SourceLocation Parser::SkipCXX11Attributes() {
       T.consumeOpen();
       T.skipToEnd();
       EndLoc = T.getCloseLocation();
+    } else if (Tok.isRegularKeywordAttribute()) {
+      EndLoc = Tok.getLocation();
+      ConsumeToken();
     } else {
       assert(Tok.is(tok::kw_alignas) && "not an attribute specifier");
       ConsumeToken();

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp 
b/clang/lib/Parse/ParseExprCXX.cpp
index 123cf432b0969..037dc923c47eb 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1364,7 +1364,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   if (isCXX11AttributeSpecifier()) {
     Diag(Tok, getLangOpts().CPlusPlus23
                   ? diag::warn_cxx20_compat_decl_attrs_on_lambda
-                  : diag::ext_decl_attrs_on_lambda);
+                  : diag::ext_decl_attrs_on_lambda)
+        << Tok.getIdentifierInfo() << Tok.isRegularKeywordAttribute();
     MaybeParseCXX11Attributes(D);
   }
 
@@ -1499,6 +1500,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                   tok::kw___private, tok::kw___global, tok::kw___local,
                   tok::kw___constant, tok::kw___generic, tok::kw_groupshared,
                   tok::kw_requires, tok::kw_noexcept) ||
+      Tok.isRegularKeywordAttribute() ||
       (Tok.is(tok::l_square) && NextToken().is(tok::l_square));
 
   if (HasSpecifiers && !HasParentheses && !getLangOpts().CPlusPlus23) {

diff  --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 8c3da9a7438e8..79707bc297f43 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1819,7 +1819,8 @@ void Parser::HandlePragmaAttribute() {
     ConsumeToken();
   };
 
-  if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+  if ((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
+      Tok.isRegularKeywordAttribute()) {
     // Parse the CXX11 style attribute.
     ParseCXX11AttributeSpecifier(Attrs);
   } else if (Tok.is(tok::kw___attribute)) {

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index bde9df0877382..aea810e8cf45c 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -335,7 +335,12 @@ StmtResult 
Parser::ParseStatementOrDeclarationAfterAttributes(
 
   case tok::kw_asm: {
     for (const ParsedAttr &AL : CXX11Attrs)
-      Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
+      // Could be relaxed if asm-related regular keyword attributes are
+      // added later.
+      (AL.isRegularKeywordAttribute()
+           ? Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed)
+           : Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored))
+          << AL;
     // Prevent these from being interpreted as statement attributes later on.
     CXX11Attrs.clear();
     ProhibitAttributes(GNUAttrs);

diff  --git a/clang/lib/Parse/ParseTentative.cpp 
b/clang/lib/Parse/ParseTentative.cpp
index ef1f3ca548f6a..e36ce8aa2bfe4 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -723,6 +723,9 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
   if (Tok.is(tok::kw_alignas))
     return CAK_AttributeSpecifier;
 
+  if (Tok.isRegularKeywordAttribute())
+    return CAK_AttributeSpecifier;
+
   if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
     return CAK_NotAttributeSpecifier;
 
@@ -862,7 +865,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
 
 bool Parser::TrySkipAttributes() {
   while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec,
-                     tok::kw_alignas)) {
+                     tok::kw_alignas) ||
+         Tok.isRegularKeywordAttribute()) {
     if (Tok.is(tok::l_square)) {
       ConsumeBracket();
       if (Tok.isNot(tok::l_square))
@@ -873,6 +877,8 @@ bool Parser::TrySkipAttributes() {
       // Note that explicitly checking for `[[` and `]]` allows to fail as
       // expected in the case of the Objective-C message send syntax.
       ConsumeBracket();
+    } else if (Tok.isRegularKeywordAttribute()) {
+      ConsumeToken();
     } else {
       ConsumeToken();
       if (Tok.isNot(tok::l_paren))

diff  --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 6e44d5f4892be..b1ccbeb99e589 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2461,6 +2461,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState 
&ImportState) {
   ParsedAttributes Attrs(AttrFactory);
   MaybeParseCXX11Attributes(Attrs);
   ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr,
+                          diag::err_keyword_not_module_attr,
                           /*DiagnoseEmptyAttrs=*/false,
                           /*WarnOnUnknownAttrs=*/true);
 
@@ -2530,6 +2531,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
   MaybeParseCXX11Attributes(Attrs);
   // We don't support any module import attributes yet.
   ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr,
+                          diag::err_keyword_not_import_attr,
                           /*DiagnoseEmptyAttrs=*/false,
                           /*WarnOnUnknownAttrs=*/true);
 

diff  --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 2af688fb58c8a..d7acb589172b5 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -203,6 +203,11 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const {
 }
 
 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
+  if (isRegularKeywordAttribute())
+    // The appurtenance rules are applied strictly for all regular keyword
+    // atributes.
+    return false;
+
   assert(isStandardAttributeSyntax());
 
   // We have historically allowed some type attributes with standard attribute

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 7cc0d472fca02..b0a8aeddf6034 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1184,7 +1184,7 @@ void Sema::ActOnEndOfTranslationUnit() {
         !(isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl)))
       for (const auto &WI : WeakIDs.second)
         Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type)
-            << "'weak'" << ExpectedVariableOrFunction;
+            << "'weak'" << /*isRegularKeyword=*/0 << 
ExpectedVariableOrFunction;
     else
       for (const auto &WI : WeakIDs.second)
         Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared)

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index aac57196012aa..d7c595b4201f1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5315,10 +5315,14 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, 
AccessSpecifier AS,
         TypeSpecType == DeclSpec::TST_union ||
         TypeSpecType == DeclSpec::TST_enum) {
       for (const ParsedAttr &AL : DS.getAttributes())
-        Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
+        Diag(AL.getLoc(), AL.isRegularKeywordAttribute()
+                              ? diag::err_declspec_keyword_has_no_effect
+                              : diag::warn_declspec_attribute_ignored)
             << AL << GetDiagnosticTypeSpecifierID(DS);
       for (const ParsedAttr &AL : DeclAttrs)
-        Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
+        Diag(AL.getLoc(), AL.isRegularKeywordAttribute()
+                              ? diag::err_declspec_keyword_has_no_effect
+                              : diag::warn_declspec_attribute_ignored)
             << AL << GetDiagnosticTypeSpecifierID(DS);
     }
   }

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f46915a6d6429..1e48d078a61bb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -273,7 +273,9 @@ static bool checkPositiveIntArgument(Sema &S, const 
AttrInfo &AI, const Expr *Ex
 template <typename AttrTy>
 static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (const auto *A = D->getAttr<AttrTy>()) {
-    S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A;
+    S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+        << AL << A
+        << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
     S.Diag(A->getLocation(), diag::note_conflicting_attribute);
     return true;
   }
@@ -283,8 +285,9 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, 
const ParsedAttr &AL) {
 template <typename AttrTy>
 static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) {
   if (const auto *A = D->getAttr<AttrTy>()) {
-    S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL
-                                                                      << A;
+    S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible)
+        << &AL << A
+        << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
     S.Diag(A->getLocation(), diag::note_conflicting_attribute);
     return true;
   }
@@ -1878,8 +1881,11 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
       // Cannot have two ownership attributes of 
diff erent kinds for the same
       // index.
       if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) {
-        S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << 
I;
-        return;
+          S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+              << AL << I
+              << (AL.isRegularKeywordAttribute() ||
+                  I->isRegularKeywordAttribute());
+          return;
       } else if (K == OwnershipAttr::Returns &&
                  I->getOwnKind() == OwnershipAttr::Returns) {
         // A returns attribute conflicts with any other returns attribute using
@@ -2164,7 +2170,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
     // nonstatic) when in Microsoft compatibility mode.
     if (S.getLangOpts().MSVCCompat && isa<CXXMethodDecl>(D)) {
       S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
-          << AL << "non-member functions";
+          << AL << AL.isRegularKeywordAttribute() << "non-member functions";
       return;
     }
   }
@@ -2177,7 +2183,8 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const 
ParsedAttr &Attrs) {
 
   if (!isa<ObjCMethodDecl>(D)) {
     S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << Attrs << ExpectedFunctionOrMethod;
+        << Attrs << Attrs.isRegularKeywordAttribute()
+        << ExpectedFunctionOrMethod;
     return;
   }
 
@@ -2218,7 +2225,9 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) {
 bool Sema::CheckAttrTarget(const ParsedAttr &AL) {
   // Check whether the attribute is valid on the current target.
   if (!AL.existsInTarget(Context.getTargetInfo())) {
-    Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
+    Diag(AL.getLoc(), AL.isRegularKeywordAttribute()
+                          ? diag::err_keyword_not_supported_on_target
+                          : diag::warn_unknown_attribute_ignored)
         << AL << AL.getRange();
     AL.setInvalid();
     return true;
@@ -2238,7 +2247,8 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
       S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax()
                               ? diag::err_attribute_wrong_decl_type
                               : diag::warn_attribute_wrong_decl_type)
-          << AL << ExpectedFunctionMethodOrBlock;
+          << AL << AL.isRegularKeywordAttribute()
+          << ExpectedFunctionMethodOrBlock;
       return;
     }
   }
@@ -2888,12 +2898,10 @@ static void handleVisibilityAttr(Sema &S, Decl *D, 
const ParsedAttr &AL,
   }
 
   // 'type_visibility' can only go on a type or namespace.
-  if (isTypeVisibility &&
-      !(isa<TagDecl>(D) ||
-        isa<ObjCInterfaceDecl>(D) ||
-        isa<NamespaceDecl>(D))) {
+  if (isTypeVisibility && !(isa<TagDecl>(D) || isa<ObjCInterfaceDecl>(D) ||
+                            isa<NamespaceDecl>(D))) {
     S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
-        << AL << ExpectedTypeOrNamespace;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedTypeOrNamespace;
     return;
   }
 
@@ -3112,12 +3120,14 @@ static void handleSentinelAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
       }
     } else {
       S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-          << AL << ExpectedFunctionMethodOrBlock;
+          << AL << AL.isRegularKeywordAttribute()
+          << ExpectedFunctionMethodOrBlock;
       return;
     }
   } else {
     S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << AL << ExpectedFunctionMethodOrBlock;
+        << AL << AL.isRegularKeywordAttribute()
+        << ExpectedFunctionMethodOrBlock;
     return;
   }
   D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos));
@@ -3142,7 +3152,8 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, 
const ParsedAttr &AL) {
     // as a function pointer.
     if (isa<VarDecl>(D))
       S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-          << AL << "functions, classes, or enumerations";
+          << AL << AL.isRegularKeywordAttribute()
+          << "functions, classes, or enumerations";
 
     // If this is spelled as the standard C++17 attribute, but not in C++17,
     // warn about using it as an extension. If there are attribute arguments,
@@ -3188,7 +3199,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
       // Nothing to warn about here.
     } else
       S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-          << AL << ExpectedVariableOrFunction;
+          << AL << AL.isRegularKeywordAttribute() << 
ExpectedVariableOrFunction;
 
     return;
   }
@@ -3884,7 +3895,9 @@ ErrorAttr *Sema::mergeErrorAttr(Decl *D, const 
AttributeCommonInfo &CI,
                  (EA->isWarning() && NewAttr == "warning");
     if (!Match) {
       Diag(EA->getLocation(), diag::err_attributes_are_not_compatible)
-          << CI << EA;
+          << CI << EA
+          << (CI.isRegularKeywordAttribute() ||
+              EA->isRegularKeywordAttribute());
       Diag(CI.getLoc(), diag::note_conflicting_attribute);
       return nullptr;
     }
@@ -4201,8 +4214,8 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
     RD = dyn_cast<RecordDecl>(D);
 
   if (!RD || !RD->isUnion()) {
-    S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL
-                                                              << ExpectedUnion;
+    S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
+        << AL << AL.isRegularKeywordAttribute() << ExpectedUnion;
     return;
   }
 
@@ -4413,7 +4426,7 @@ static bool validateAlignasAppliedType(Sema &S, Decl *D,
       DiagKind = 4;
   } else if (!isa<TagDecl>(D)) {
     return S.Diag(AttrLoc, diag::err_attribute_wrong_decl_type)
-           << &Attr
+           << &Attr << Attr.isRegularKeywordAttribute()
            << (Attr.isC11() ? ExpectedVariableOrField
                             : ExpectedVariableFieldOrTag);
   }
@@ -4888,8 +4901,9 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl 
*D,
     // ImplicitParm or VarTemplateSpecialization).
     if (VD->getKind() != Decl::Var) {
       Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-          << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
-                                            : ExpectedVariableOrFunction);
+          << AL << AL.isRegularKeywordAttribute()
+          << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
+                                      : ExpectedVariableOrFunction);
       return nullptr;
     }
     // Attribute does not apply to non-static local variables.
@@ -4908,8 +4922,9 @@ Sema::mergeInternalLinkageAttr(Decl *D, const 
InternalLinkageAttr &AL) {
     // ImplicitParm or VarTemplateSpecialization).
     if (VD->getKind() != Decl::Var) {
       Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type)
-          << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
-                                             : ExpectedVariableOrFunction);
+          << &AL << AL.isRegularKeywordAttribute()
+          << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
+                                      : ExpectedVariableOrFunction);
       return nullptr;
     }
     // Attribute does not apply to non-static local variables.
@@ -4940,7 +4955,9 @@ SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const 
SwiftNameAttr &SNA,
   if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) {
     if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) {
       Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible)
-          << PrevSNA << &SNA;
+          << PrevSNA << &SNA
+          << (PrevSNA->isRegularKeywordAttribute() ||
+              SNA.isRegularKeywordAttribute());
       Diag(SNA.getLoc(), diag::note_conflicting_attribute);
     }
 
@@ -5105,7 +5122,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
 
   if (!isa<ObjCMethodDecl>(D)) {
     S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << AL << ExpectedFunctionOrMethod;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
     return;
   }
 
@@ -5236,7 +5253,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
                                           : nullptr;
       if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
         S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
-            << AL << OAttr;
+            << AL << OAttr
+            << (AL.isRegularKeywordAttribute() ||
+                OAttr->isRegularKeywordAttribute());
         S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
       }
       return;
@@ -5253,7 +5272,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
                                           : nullptr;
       if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
         S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
-            << AL << PAttr;
+            << AL << PAttr
+            << (AL.isRegularKeywordAttribute() ||
+                PAttr->isRegularKeywordAttribute());
         S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
       }
       return;
@@ -5488,7 +5509,9 @@ void Sema::AddParameterABIAttr(Decl *D, const 
AttributeCommonInfo &CI,
   if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
     if (existingAttr->getABI() != abi) {
       Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
-          << getParameterABISpelling(abi) << existingAttr;
+          << getParameterABISpelling(abi) << existingAttr
+          << (CI.isRegularKeywordAttribute() ||
+              existingAttr->isRegularKeywordAttribute());
       Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
       return;
     }
@@ -5680,7 +5703,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
 
   if (!isa<VarDecl>(D)) {
     S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type)
-        << AL << ExpectedVariable;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedVariable;
     return;
   }
 
@@ -5986,7 +6009,8 @@ static void handleXReturnsXRetainedAttr(Sema &S, Decl *D,
       break;
     }
     S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type)
-        << AL.getRange() << AL << ExpectedDeclKind;
+        << AL.getRange() << AL << AL.isRegularKeywordAttribute()
+        << ExpectedDeclKind;
     return;
   }
 
@@ -6258,10 +6282,12 @@ static void handleObjCBoxable(Sema &S, Decl *D, const 
ParsedAttr &AL) {
 }
 
 static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  if (hasDeclarator(D)) return;
+  if (hasDeclarator(D))
+    return;
 
   S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type)
-      << AL.getRange() << AL << ExpectedVariable;
+      << AL.getRange() << AL << AL.isRegularKeywordAttribute()
+      << ExpectedVariable;
 }
 
 static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
@@ -6754,7 +6780,8 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, 
SourceLocation Loc,
       Params = F->parameters();
 
       if (!F->hasWrittenPrototype()) {
-        Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL
+        Diag(Loc, diag::warn_attribute_wrong_decl_type)
+            << AL << AL.isRegularKeywordAttribute()
             << ExpectedFunctionWithProtoType;
         return false;
       }
@@ -6875,7 +6902,7 @@ static void handleSwiftNewType(Sema &S, Decl *D, const 
ParsedAttr &AL) {
 
   if (!isa<TypedefNameDecl>(D)) {
     S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
-        << AL << "typedefs";
+        << AL << AL.isRegularKeywordAttribute() << "typedefs";
     return;
   }
 
@@ -7350,7 +7377,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
   // a function with no parameters and void return type.
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << "'interrupt'" << ExpectedFunctionOrMethod;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
     return;
   }
 
@@ -7423,7 +7450,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
 
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << "'interrupt'" << ExpectedFunctionOrMethod;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
     return;
   }
 
@@ -7498,7 +7525,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
       CXXMethodDecl::isStaticOverloadedOperator(
           cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
     S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << AL << ExpectedFunctionWithProtoType;
+        << AL << AL.isRegularKeywordAttribute()
+        << ExpectedFunctionWithProtoType;
     return;
   }
   // Interrupt handler must have void return type.
@@ -7554,7 +7582,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
 static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << "'interrupt'" << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
     return;
   }
 
@@ -7567,7 +7595,7 @@ static void handleAVRInterruptAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
 static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << "'signal'" << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
     return;
   }
 
@@ -7620,10 +7648,11 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, 
const BTFDeclTagAttr &AL) {
   return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag());
 }
 
-static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr 
&AL) {
+static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D,
+                                            const ParsedAttr &AL) {
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-        << "'export_name'" << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
     return;
   }
 
@@ -7747,7 +7776,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D,
 
   if (D->getFunctionType() == nullptr) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
-      << "'interrupt'" << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
     return;
   }
 
@@ -7942,7 +7971,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, 
Decl *D,
   // Attribute can only be applied to function types.
   if (!isa<FunctionDecl>(D)) {
     S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
-        << AL << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
     return;
   }
 
@@ -8221,7 +8250,7 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
                                 .Case("no_sanitize_memory", "memory");
   if (isGlobalVar(D) && SanitizerName != "address")
     S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
-        << AL << ExpectedFunction;
+        << AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
 
   // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a
   // NoSanitizeAttr object; but we need to calculate the correct spelling list
@@ -8682,7 +8711,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, 
const ParsedAttr &AL,
   if (AL.getKind() == ParsedAttr::UnknownAttribute ||
       !AL.existsInTarget(S.Context.getTargetInfo())) {
     S.Diag(AL.getLoc(),
-           AL.isDeclspecAttribute()
+           AL.isRegularKeywordAttribute()
+               ? (unsigned)diag::err_keyword_not_supported_on_target
+           : AL.isDeclspecAttribute()
                ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
                : (unsigned)diag::warn_unknown_attribute_ignored)
         << AL << AL.getRange();
@@ -8711,7 +8742,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, 
const ParsedAttr &AL,
     if (AL.isTypeAttr()) {
       if (Options.IgnoreTypeAttributes)
         break;
-      if (!AL.isStandardAttributeSyntax()) {
+      if (!AL.isStandardAttributeSyntax() && !AL.isRegularKeywordAttribute()) {
         // Non-[[]] type attributes are handled in processTypeAttrs(); silently
         // move on.
         break;
@@ -8776,7 +8807,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, 
const ParsedAttr &AL,
     // needed for type attributes as well as statement attributes in Attr.td
     // that do not list any subjects.
     S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)
-        << AL << D->getLocation();
+        << AL << AL.isRegularKeywordAttribute() << D->getLocation();
     break;
   case ParsedAttr::AT_Interrupt:
     handleInterruptAttr(S, D, AL);
@@ -9487,19 +9518,19 @@ void Sema::ProcessDeclAttributeList(
     } else if (!D->hasAttr<CUDAGlobalAttr>()) {
       if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
         Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
-            << A << ExpectedKernelFunction;
+            << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction;
         D->setInvalidDecl();
       } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) {
         Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
-            << A << ExpectedKernelFunction;
+            << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction;
         D->setInvalidDecl();
       } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) {
         Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
-            << A << ExpectedKernelFunction;
+            << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction;
         D->setInvalidDecl();
       } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) {
         Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
-            << A << ExpectedKernelFunction;
+            << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction;
         D->setInvalidDecl();
       }
     }

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 65122c04c4b35..3169b381071bb 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2710,10 +2710,12 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, 
SourceRange SpecifierRange,
   for (const ParsedAttr &AL : Attributes) {
     if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
       continue;
-    Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute
-                          ? (unsigned)diag::warn_unknown_attribute_ignored
-                          : (unsigned)diag::err_base_specifier_attribute)
-        << AL << AL.getRange();
+    if (AL.getKind() == ParsedAttr::UnknownAttribute)
+      Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
+          << AL << AL.getRange();
+    else
+      Diag(AL.getLoc(), diag::err_base_specifier_attribute)
+          << AL << AL.isRegularKeywordAttribute() << AL.getRange();
   }
 
   TypeSourceInfo *TInfo = nullptr;

diff  --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 860a5a8524ec7..ad20bc8871f10 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -490,7 +490,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const 
ParsedAttr &A,
       !(A.existsInTarget(S.Context.getTargetInfo()) ||
         (S.Context.getLangOpts().SYCLIsDevice && Aux &&
          A.existsInTarget(*Aux)))) {
-    S.Diag(A.getLoc(), A.isDeclspecAttribute()
+    S.Diag(A.getLoc(), A.isRegularKeywordAttribute()
+                           ? 
(unsigned)diag::err_keyword_not_supported_on_target
+                       : A.isDeclspecAttribute()
                            ? 
(unsigned)diag::warn_unhandled_ms_attribute_ignored
                            : (unsigned)diag::warn_unknown_attribute_ignored)
         << A << A.getRange();
@@ -526,7 +528,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const 
ParsedAttr &A,
     // declaration attribute is not written on a statement, but this code is
     // needed for attributes in Attr.td that do not list any subjects.
     S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
-        << A << St->getBeginLoc();
+        << A << A.isRegularKeywordAttribute() << St->getBeginLoc();
     return nullptr;
   }
 }

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d54ac53dd4231..26ad4f97b0d03 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -103,8 +103,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const 
ParsedAttr &attr,
     }
   }
 
-  S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType
-    << type;
+  S.Diag(loc, attr.isRegularKeywordAttribute()
+                  ? diag::err_type_attribute_wrong_type
+                  : diag::warn_type_attribute_wrong_type)
+      << name << WhichType << type;
 }
 
 // objc_gc applies to Objective-C pointers or, otherwise, to the
@@ -685,7 +687,7 @@ static void 
distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
   for (ParsedAttr &attr : AttrsCopy) {
     // Do not distribute [[]] attributes. They have strict rules for what
     // they appertain to.
-    if (attr.isStandardAttributeSyntax())
+    if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute())
       continue;
 
     switch (attr.getKind()) {
@@ -7334,12 +7336,12 @@ static bool 
handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
   if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) {
     S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
         << "'__ptr32'"
-        << "'__ptr64'";
+        << "'__ptr64'" << /*isRegularKeyword=*/0;
     return true;
   } else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) {
     S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
         << "'__sptr'"
-        << "'__uptr'";
+        << "'__uptr'" << /*isRegularKeyword=*/0;
     return true;
   }
 
@@ -7862,8 +7864,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
     CallingConv CC = fn->getCallConv();
     if (CC == CC_X86FastCall) {
       S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
-        << FunctionType::getNameForCallConv(CC)
-        << "regparm";
+          << FunctionType::getNameForCallConv(CC) << "regparm"
+          << attr.isRegularKeywordAttribute();
       attr.setInvalid();
       return true;
     }
@@ -7942,8 +7944,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
     // and the CCs don't match.
     if (S.getCallingConvAttributedType(type)) {
       S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
-        << FunctionType::getNameForCallConv(CC)
-        << FunctionType::getNameForCallConv(CCOld);
+          << FunctionType::getNameForCallConv(CC)
+          << FunctionType::getNameForCallConv(CCOld)
+          << attr.isRegularKeywordAttribute();
       attr.setInvalid();
       return true;
     }
@@ -7975,7 +7978,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
   // Also diagnose fastcall with regparm.
   if (CC == CC_X86FastCall && fn->getHasRegParm()) {
     S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
-        << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall);
+        << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall)
+        << attr.isRegularKeywordAttribute();
     attr.setInvalid();
     return true;
   }
@@ -8491,12 +8495,13 @@ static void processTypeAttrs(TypeProcessingState 
&state, QualType &type,
     if (attr.isInvalid())
       continue;
 
-    if (attr.isStandardAttributeSyntax()) {
+    if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) {
       // [[gnu::...]] attributes are treated as declaration attributes, so may
       // not appertain to a DeclaratorChunk. If we handle them as type
       // attributes, accept them in that position and diagnose the GCC
       // incompatibility.
       if (attr.isGNUScope()) {
+        assert(attr.isStandardAttributeSyntax());
         bool IsTypeAttr = attr.isTypeAttr();
         if (TAL == TAL_DeclChunk) {
           state.getSema().Diag(attr.getLoc(),
@@ -8524,9 +8529,11 @@ static void processTypeAttrs(TypeProcessingState &state, 
QualType &type,
     switch (attr.getKind()) {
     default:
       // A [[]] attribute on a declarator chunk must appertain to a type.
-      if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) {
+      if ((attr.isStandardAttributeSyntax() ||
+           attr.isRegularKeywordAttribute()) &&
+          TAL == TAL_DeclChunk) {
         state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr)
-            << attr;
+            << attr << attr.isRegularKeywordAttribute();
         attr.setUsedAsTypeAttr();
       }
       break;
@@ -8707,7 +8714,8 @@ static void processTypeAttrs(TypeProcessingState &state, 
QualType &type,
 
       // Attributes with standard syntax have strict rules for what they
       // appertain to and hence should not use the "distribution" logic below.
-      if (attr.isStandardAttributeSyntax()) {
+      if (attr.isStandardAttributeSyntax() ||
+          attr.isRegularKeywordAttribute()) {
         if (!handleFunctionTypeAttr(state, attr, type)) {
           diagnoseBadTypeAttribute(state.getSema(), attr, type);
           attr.setInvalid();

diff  --git a/clang/test/Parser/c2x-attribute-keywords.c 
b/clang/test/Parser/c2x-attribute-keywords.c
new file mode 100644
index 0000000000000..757dc82860110
--- /dev/null
+++ b/clang/test/Parser/c2x-attribute-keywords.c
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu 
-target-feature +sme -verify=expected,notc2x -Wno-strict-prototypes %s
+// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu 
-target-feature +sme -verify=expected,c2x %s
+
+enum __arm_streaming E { // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+  One __arm_streaming, // expected-error {{'__arm_streaming' cannot be applied 
to a declaration}}
+  Two,
+  Three __arm_streaming // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+};
+
+enum __arm_streaming { Four }; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+__arm_streaming enum E2 { Five }; // expected-error {{misplaced 
'__arm_streaming'}}
+
+// FIXME: this diagnostic can be improved.
+enum { __arm_streaming Six }; // expected-error {{expected identifier}}
+
+// FIXME: this diagnostic can be improved.
+enum E3 __arm_streaming { Seven }; // expected-error {{expected identifier or 
'('}}
+
+struct __arm_streaming S1 { // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+  int i __arm_streaming; // expected-error {{'__arm_streaming' only applies to 
function types}}
+  int __arm_streaming j; // expected-error {{'__arm_streaming' only applies to 
function types}}
+  int k[10] __arm_streaming; // expected-error {{'__arm_streaming' only 
applies to function types}}
+  int l __arm_streaming[10]; // expected-error {{'__arm_streaming' only 
applies to function types}}
+  __arm_streaming int m, n; // expected-error {{'__arm_streaming' only applies 
to function types}}
+  int o __arm_streaming : 12; // expected-error {{'__arm_streaming' only 
applies to function types}}
+  int __arm_streaming : 0; // expected-error {{'__arm_streaming' only applies 
to function types}}
+  int p, __arm_streaming : 0; // expected-error {{'__arm_streaming' cannot 
appear here}}
+  int q, __arm_streaming r; // expected-error {{'__arm_streaming' cannot 
appear here}}
+  __arm_streaming int; // expected-error {{'__arm_streaming' cannot appear 
here}} \
+            // expected-warning {{declaration does not declare anything}}
+};
+
+__arm_streaming struct S2 { int a; }; // expected-error {{misplaced 
'__arm_streaming'}}
+struct S3 __arm_streaming { int a; }; // expected-error {{'__arm_streaming' 
cannot appear here}} \
+                                         expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+
+union __arm_streaming U { // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+  double d __arm_streaming; // expected-error {{'__arm_streaming' only applies 
to function types; type here is 'double'}}
+  __arm_streaming int i; // expected-error {{'__arm_streaming' only applies to 
function types; type here is 'int'}}
+};
+
+__arm_streaming union U2 { double d; }; // expected-error {{misplaced 
'__arm_streaming'}}
+union U3 __arm_streaming { double d; }; // expected-error {{'__arm_streaming' 
cannot appear here}} \
+                                           expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+
+struct __arm_streaming IncompleteStruct; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+union __arm_streaming IncompleteUnion; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+enum __arm_streaming IncompleteEnum; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+
+__arm_streaming void f1(void); // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+void __arm_streaming f2(void); // expected-error {{'__arm_streaming' only 
applies to function types}}
+void f3 __arm_streaming (void); // expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+void f4(void) __arm_streaming;
+
+void f5(int i __arm_streaming, __arm_streaming int j, int __arm_streaming k); 
// expected-error 3 {{'__arm_streaming' only applies to function types}}
+
+void f6(a, b) __arm_streaming int a; int b; { // expected-error 
{{'__arm_streaming' cannot appear here}} \
+                                                 c2x-warning {{deprecated}}
+}
+
+// FIXME: technically, an attribute list cannot appear here, but we currently
+// parse it as part of the return type of the function, which is reasonable
+// behavior given that we *don't* want to parse it as part of the K&R parameter
+// declarations. It is disallowed to avoid a parsing ambiguity we already
+// handle well.
+int (*f7(a, b))(int, int) __arm_streaming int a; int b; { // c2x-warning 
{{deprecated}}
+  return 0;
+}
+
+__arm_streaming int a, b; // expected-error {{'__arm_streaming' only applies 
to function types}}
+int c __arm_streaming, d __arm_streaming; // expected-error 2 
{{'__arm_streaming' only applies to function types}}
+
+void f8(void) __arm_streaming {
+  __arm_streaming int i, j; // expected-error {{'__arm_streaming' only applies 
to function types}}
+  int k, l __arm_streaming; // expected-error {{'__arm_streaming' only applies 
to function types}}
+}
+
+__arm_streaming void f9(void) { // expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+  int i[10] __arm_streaming; // expected-error {{'__arm_streaming' only 
applies to function types}}
+  int (*fp1)(void)__arm_streaming;
+  int (*fp2 __arm_streaming)(void); // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+
+  int * __arm_streaming *ipp; // expected-error {{'__arm_streaming' only 
applies to function types}}
+}
+
+void f10(int j[static 10] __arm_streaming, int k[*] __arm_streaming); // 
expected-error 2 {{'__arm_streaming' only applies to function types}}
+
+void f11(void) {
+  __arm_streaming {} // expected-error {{'__arm_streaming' cannot be applied 
to a statement}}
+  __arm_streaming if (1) {} // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+
+  __arm_streaming switch (1) { // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming case 1: __arm_streaming break; // expected-error 2 
{{'__arm_streaming' cannot be applied to a statement}}
+  __arm_streaming default: break; // expected-error {{'__arm_streaming' cannot 
be applied to a statement}}
+  }
+
+  goto foo;
+  __arm_streaming foo: (void)1; // expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+
+  __arm_streaming for (;;); // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming while (1); // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming do __arm_streaming { } while(1); // expected-error 2 
{{'__arm_streaming' cannot be applied to a statement}}
+
+  __arm_streaming (void)1; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+
+  __arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to 
a statement}}
+
+  (void)sizeof(int [4]__arm_streaming); // expected-error {{'__arm_streaming' 
only applies to function types}}
+  (void)sizeof(struct __arm_streaming S3 { int a __arm_streaming; }); // 
expected-error {{'__arm_streaming' cannot be applied to a declaration}} \
+                                                                      // 
expected-error {{'__arm_streaming' only applies to function types; type here is 
'int'}}
+
+  __arm_streaming return; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+
+  __arm_streaming asm (""); // expected-error {{'__arm_streaming' cannot 
appear here}}
+}
+
+struct __arm_streaming S4 *s; // expected-error {{'__arm_streaming' cannot 
appear here}}
+struct S5 {};
+int c = sizeof(struct __arm_streaming S5); // expected-error 
{{'__arm_streaming' cannot appear here}}

diff  --git a/clang/test/Parser/c2x-attribute-keywords.m 
b/clang/test/Parser/c2x-attribute-keywords.m
new file mode 100644
index 0000000000000..d1c45da34fbc6
--- /dev/null
+++ b/clang/test/Parser/c2x-attribute-keywords.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu 
-target-feature +sme -verify %s
+
+enum __arm_streaming E1 : int; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+
+@interface Base
+@end
+
+@interface S : Base
+- (void) bar;
+@end
+
+@interface T : Base
+- (S *) foo;
+@end
+
+
+void f(T *t) {
+  __arm_streaming[[t foo] bar]; // expected-error {{'__arm_streaming' cannot 
be applied to a statement}}
+}

diff  --git a/clang/test/Parser/cxx0x-keyword-attributes.cpp 
b/clang/test/Parser/cxx0x-keyword-attributes.cpp
new file mode 100644
index 0000000000000..256a834e9e546
--- /dev/null
+++ b/clang/test/Parser/cxx0x-keyword-attributes.cpp
@@ -0,0 +1,345 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fdeclspec -fexceptions -fsyntax-only 
-verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions -triple 
aarch64-none-linux-gnu %s
+
+// Need std::initializer_list
+namespace std {
+  typedef decltype(sizeof(int)) size_t;
+
+  // libc++'s implementation
+  template <class _E>
+  class initializer_list
+  {
+    const _E* __begin_;
+    size_t    __size_;
+
+    initializer_list(const _E* __b, size_t __s)
+      : __begin_(__b),
+        __size_(__s)
+    {}
+
+  public:
+    typedef _E        value_type;
+    typedef const _E& reference;
+    typedef const _E& const_reference;
+    typedef size_t    size_type;
+
+    typedef const _E* iterator;
+    typedef const _E* const_iterator;
+
+    initializer_list() : __begin_(nullptr), __size_(0) {}
+
+    size_t    size()  const {return __size_;}
+    const _E* begin() const {return __begin_;}
+    const _E* end()   const {return __begin_ + __size_;}
+  };
+}
+
+
+// Declaration syntax checks
+__arm_streaming int before_attr; // expected-error {{'__arm_streaming' only 
applies to function types}}
+int __arm_streaming between_attr; // expected-error {{'__arm_streaming' only 
applies to function types}}
+const __arm_streaming int between_attr_2 = 0; // expected-error 
{{'__arm_streaming' cannot appear here}}
+int after_attr __arm_streaming; // expected-error {{'__arm_streaming' only 
applies to function types}}
+int * __arm_streaming ptr_attr; // expected-error {{'__arm_streaming' only 
applies to function types}}
+int & __arm_streaming ref_attr = after_attr; // expected-error 
{{'__arm_streaming' only applies to function types}}
+int && __arm_streaming rref_attr = 0; // expected-error {{'__arm_streaming' 
only applies to function types}}
+int array_attr [1] __arm_streaming; // expected-error {{'__arm_streaming' only 
applies to function types}}
+void fn_attr () __arm_streaming;
+void noexcept_fn_attr () noexcept __arm_streaming;
+struct MemberFnOrder {
+  virtual void f() const volatile && noexcept __arm_streaming final = 0;
+};
+struct __arm_streaming struct_attr; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+class __arm_streaming class_attr {}; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+union __arm_streaming union_attr; // expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+enum __arm_streaming E { }; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+namespace test_misplacement {
+__arm_streaming struct struct_attr2;  // expected-error {{misplaced 
'__arm_streaming'}}
+__arm_streaming class class_attr2; // expected-error {{misplaced 
'__arm_streaming'}}
+__arm_streaming union union_attr2; // expected-error {{misplaced 
'__arm_streaming'}}
+__arm_streaming enum  E2 { }; // expected-error {{misplaced '__arm_streaming'}}
+}
+
+// Checks attributes placed at wrong syntactic locations of class specifiers.
+class __arm_streaming __arm_streaming // expected-error 2 {{'__arm_streaming' 
cannot be applied to a declaration}}
+  attr_after_class_name_decl __arm_streaming __arm_streaming; // 
expected-error {{'__arm_streaming' cannot appear here}} \
+                                                                 
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+
+class __arm_streaming __arm_streaming // expected-error 2 {{'__arm_streaming' 
cannot be applied to a declaration}}
+ attr_after_class_name_definition __arm_streaming __arm_streaming 
__arm_streaming{}; // expected-error {{'__arm_streaming' cannot appear here}} \
+                                                                               
         expected-error 3 {{'__arm_streaming' cannot be applied to a 
declaration}}
+
+class __arm_streaming c {}; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+class c __arm_streaming __arm_streaming x; // expected-error 2 
{{'__arm_streaming' only applies to function types}}
+class c __arm_streaming __arm_streaming y __arm_streaming __arm_streaming; // 
expected-error 4 {{'__arm_streaming' only applies to function types}}
+class c final [(int){0}];
+
+class base {};
+class __arm_streaming __arm_streaming final_class // expected-error 2 
{{'__arm_streaming' cannot be applied to a declaration}}
+  __arm_streaming alignas(float) final // expected-error {{'__arm_streaming' 
cannot appear here}} \
+                                          expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+  __arm_streaming alignas(float) __arm_streaming alignas(float): base{}; // 
expected-error {{'__arm_streaming' cannot appear here}}
+
+class __arm_streaming __arm_streaming final_class_another // expected-error 2 
{{'__arm_streaming' cannot be applied to a declaration}}
+  __arm_streaming __arm_streaming alignas(16) final // expected-error 
{{'__arm_streaming' cannot appear here}} \
+                                                       expected-error 2 
{{'__arm_streaming' cannot be applied to a declaration}}
+  __arm_streaming __arm_streaming alignas(16) __arm_streaming{}; // 
expected-error {{'__arm_streaming' cannot appear here}}
+
+class after_class_close {} __arm_streaming; // expected-error 
{{'__arm_streaming' cannot appear here, place it after "class" to apply it to 
the type declaration}}
+
+class C {};
+
+__arm_streaming struct with_init_declarators {} init_declarator; // 
expected-error {{'__arm_streaming' only applies to function types}}
+__arm_streaming struct no_init_declarators; // expected-error {{misplaced 
'__arm_streaming'}}
+template<typename> __arm_streaming struct no_init_declarators_template; // 
expected-error {{'__arm_streaming' cannot appear here}}
+void fn_with_structs() {
+  __arm_streaming struct with_init_declarators {} init_declarator; // 
expected-error {{'__arm_streaming' only applies to function types}}
+  __arm_streaming struct no_init_declarators; // expected-error 
{{'__arm_streaming' cannot appear here}}
+}
+__arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a 
declaration}}
+struct ctordtor {
+  __arm_streaming ctordtor __arm_streaming () __arm_streaming; // 
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+  ctordtor (C) __arm_streaming;
+  __arm_streaming ~ctordtor __arm_streaming () __arm_streaming; // 
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+};
+__arm_streaming ctordtor::ctordtor __arm_streaming () __arm_streaming {} // 
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+__arm_streaming ctordtor::ctordtor (C) __arm_streaming try {} catch (...) {} 
// expected-error {{'__arm_streaming' cannot be applied to a declaration}}
+__arm_streaming ctordtor::~ctordtor __arm_streaming () __arm_streaming {} // 
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+extern "C++" __arm_streaming int extern_attr; // expected-error 
{{'__arm_streaming' only applies to function types}}
+template <typename T> __arm_streaming void template_attr (); // expected-error 
{{'__arm_streaming' cannot be applied to a declaration}}
+__arm_streaming __arm_streaming int __arm_streaming __arm_streaming multi_attr 
__arm_streaming __arm_streaming; // expected-error 6 {{'__arm_streaming' only 
applies to function types}}
+
+int (paren_attr) __arm_streaming; // expected-error {{'__arm_streaming' cannot 
appear here}}
+unsigned __arm_streaming int attr_in_decl_spec; // expected-error 
{{'__arm_streaming' cannot appear here}}
+unsigned __arm_streaming int __arm_streaming const double_decl_spec = 0; // 
expected-error 2 {{'__arm_streaming' cannot appear here}}
+class foo {
+  void const_after_attr () __arm_streaming const; // expected-error {{expected 
';'}}
+};
+extern "C++" __arm_streaming { } // expected-error {{'__arm_streaming' cannot 
appear here}}
+__arm_streaming extern "C++" { } // expected-error {{'__arm_streaming' cannot 
appear here}}
+__arm_streaming template <typename T> void before_template_attr (); // 
expected-error {{'__arm_streaming' cannot appear here}}
+__arm_streaming namespace ns { int i; } // expected-error {{'__arm_streaming' 
cannot appear here}}
+__arm_streaming static_assert(true, ""); //expected-error {{'__arm_streaming' 
cannot appear here}}
+__arm_streaming asm(""); // expected-error {{'__arm_streaming' cannot appear 
here}}
+
+__arm_streaming using ns::i; // expected-warning {{ISO C++}} \
+                                expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+__arm_streaming using namespace ns; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+namespace __arm_streaming ns2 {} // expected-warning {{attributes on a 
namespace declaration are a C++17 extension}} \
+                                    expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+
+using __arm_streaming alignas(4)__arm_streaming ns::i;          // 
expected-warning 2 {{ISO C++}} \
+                                                                   
expected-error {{'__arm_streaming' cannot appear here}} \
+                                                                   
expected-error {{'alignas' attribute only applies to variables, data members 
and tag types}} \
+                                                                   
expected-warning {{ISO C++}} \
+                                                                   
expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}}
+using __arm_streaming alignas(4) __arm_streaming foobar = int; // 
expected-error {{'__arm_streaming' cannot appear here}} \
+                                                                  
expected-error {{'alignas' attribute only applies to}} \
+                                                                  
expected-error 2 {{'__arm_streaming' only applies to function types}}
+
+__arm_streaming using T = int; // expected-error {{'__arm_streaming' cannot 
appear here}}
+using T __arm_streaming = int; // expected-error {{'__arm_streaming' only 
applies to function types}}
+template<typename T> using U __arm_streaming = T; // expected-error 
{{'__arm_streaming' only applies to function types}}
+using ns::i __arm_streaming; // expected-warning {{ISO C++}} \
+                                expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+using ns::i __arm_streaming, ns::i __arm_streaming; // expected-warning 2 
{{ISO C++}} \
+                                                       expected-warning {{use 
of multiple declarators in a single using declaration is a C++17 extension}} \
+                                                       expected-error 2 
{{'__arm_streaming' cannot be applied to a declaration}}
+struct using_in_struct_base {
+  typedef int i, j, k, l;
+};
+struct using_in_struct : using_in_struct_base {
+  __arm_streaming using using_in_struct_base::i; // expected-warning {{ISO 
C++}} \
+                                                    expected-error 
{{'__arm_streaming' cannot be applied to a declaration}}
+  using using_in_struct_base::j __arm_streaming; // expected-warning {{ISO 
C++}} \
+                                                    expected-error 
{{'__arm_streaming' cannot be applied to a declaration}}
+  __arm_streaming using using_in_struct_base::k __arm_streaming, 
using_in_struct_base::l __arm_streaming; // expected-warning 3 {{ISO C++}} \
+                                                                               
                              expected-warning {{use of multiple declarators in 
a single using declaration is a C++17 extension}} \
+                                                                               
                              expected-error 4 {{'__arm_streaming' cannot be 
applied to a declaration}}
+};
+using __arm_streaming ns::i; // expected-warning {{ISO C++}} \
+                                expected-error {{'__arm_streaming' cannot 
appear here}} \
+                                expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+using T __arm_streaming = int; // expected-error {{'__arm_streaming' only 
applies to function types}}
+
+auto trailing() -> __arm_streaming const int; // expected-error 
{{'__arm_streaming' cannot appear here}}
+auto trailing() -> const __arm_streaming int; // expected-error 
{{'__arm_streaming' cannot appear here}}
+auto trailing() -> const int __arm_streaming; // expected-error 
{{'__arm_streaming' only applies to function types}}
+auto trailing_2() -> struct struct_attr __arm_streaming; // expected-error 
{{'__arm_streaming' only applies to function types}}
+
+namespace N {
+  struct S {};
+};
+template<typename> struct Template {};
+
+// FIXME: Improve this diagnostic
+struct __arm_streaming N::S s; // expected-error {{'__arm_streaming' cannot 
appear here}}
+struct __arm_streaming Template<int> t; // expected-error {{'__arm_streaming' 
cannot appear here}}
+struct __arm_streaming ::template Template<int> u; // expected-error 
{{'__arm_streaming' cannot appear here}}
+template struct __arm_streaming Template<char>; // expected-error 
{{'__arm_streaming' cannot appear here}}
+template struct __attribute__((pure)) Template<std::size_t>; // We still allow 
GNU-style attributes here
+template <> struct __arm_streaming Template<void>; // expected-error 
{{'__arm_streaming' cannot be applied to a declaration}}
+
+enum __arm_streaming E1 {}; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+enum __arm_streaming E2; // expected-error {{forbids forward references}} \
+                            expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+enum __arm_streaming E1; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+enum __arm_streaming E3 : int; // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+enum __arm_streaming { // expected-error {{'__arm_streaming' cannot be applied 
to a declaration}}
+  k_123 __arm_streaming = 123 // expected-warning {{attributes on an 
enumerator declaration are a C++17 extension}} \
+                                 expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+};
+enum __arm_streaming E1 e; // expected-error {{'__arm_streaming' cannot appear 
here}}
+enum __arm_streaming class E4 { }; // expected-error {{'__arm_streaming' 
cannot appear here}}
+enum struct __arm_streaming E5; // expected-error {{'__arm_streaming' cannot 
be applied to a declaration}}
+enum E6 {} __arm_streaming; // expected-error {{'__arm_streaming' cannot 
appear here, place it after "enum" to apply it to the type declaration}}
+
+struct S {
+  friend int f __arm_streaming (); // expected-error {{'__arm_streaming' 
cannot appear here}} \
+                                      expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+  friend int f2 __arm_streaming () {} // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+  __arm_streaming friend int g(); // expected-error {{'__arm_streaming' cannot 
appear here}}
+  __arm_streaming friend int h() { // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}}
+  }
+  __arm_streaming friend int f3(), f4(), f5(); // expected-error 
{{'__arm_streaming' cannot appear here}}
+  friend int f6 __arm_streaming (), f7 __arm_streaming (), f8 __arm_streaming 
(); // expected-error3 {{'__arm_streaming' cannot appear here}} \
+                                                                               
      expected-error 3 {{'__arm_streaming' cannot be applied to a declaration}}
+  friend class __arm_streaming C; // expected-error {{'__arm_streaming' cannot 
appear here}}
+  __arm_streaming friend class D; // expected-error {{'__arm_streaming' cannot 
appear here}}
+  __arm_streaming friend int; // expected-error {{'__arm_streaming' cannot 
appear here}}
+};
+template<typename T> void tmpl (T) {}
+template __arm_streaming void tmpl(char); // expected-error 
{{'__arm_streaming' cannot appear here}}
+template void __arm_streaming tmpl(short); // expected-error 
{{'__arm_streaming' only applies to function types}}
+
+// Statement tests
+void foo () {
+  __arm_streaming ; // expected-error {{'__arm_streaming' cannot be applied to 
a statement}}
+  __arm_streaming { } // expected-error {{'__arm_streaming' cannot be applied 
to a statement}}
+  __arm_streaming if (0) { } // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming for (;;); // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming do { // expected-error {{'__arm_streaming' cannot be applied 
to a statement}}
+    __arm_streaming continue; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  } while (0);
+  __arm_streaming while (0); // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+
+  __arm_streaming switch (i) { // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+    __arm_streaming case 0: // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+    __arm_streaming default: // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+      __arm_streaming break; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  }
+
+  __arm_streaming goto there; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  __arm_streaming there: // expected-error {{'__arm_streaming' cannot be 
applied to a declaration}}
+
+  __arm_streaming try { // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+  } __arm_streaming catch (...) { // expected-error {{'__arm_streaming' cannot 
appear here}}
+  }
+
+  void bar __arm_streaming (__arm_streaming int i, __arm_streaming int j); // 
expected-error 2 {{'__arm_streaming' only applies to function types}} \
+                                                                              
expected-error {{'__arm_streaming' cannot be applied to a declaration}}
+  using FuncType = void (__arm_streaming int); // expected-error 
{{'__arm_streaming' only applies to function types}}
+  void baz(__arm_streaming...); // expected-error {{expected parameter 
declarator}}
+
+  __arm_streaming return; // expected-error {{'__arm_streaming' cannot be 
applied to a statement}}
+}
+
+// Expression tests
+void bar () {
+  new int[42]__arm_streaming[5]__arm_streaming{}; // expected-error 
{{'__arm_streaming' only applies to function types}}
+}
+
+// Condition tests
+void baz () {
+  if (__arm_streaming bool b = true) { // expected-error {{'__arm_streaming' 
only applies to function types}}
+    switch (__arm_streaming int n { 42 }) { // expected-error 
{{'__arm_streaming' only applies to function types}}
+    default:
+      for (__arm_streaming int n = 0; __arm_streaming char b = n < 5; ++b) { 
// expected-error 2 {{'__arm_streaming' only applies to function types}}
+      }
+    }
+  }
+  int x;
+  // An attribute can be applied to an expression-statement, such as the first
+  // statement in a for. But it can't be applied to a condition which is an
+  // expression.
+  for (__arm_streaming x = 0; ; ) {} // expected-error {{'__arm_streaming' 
cannot appear here}}
+  for (; __arm_streaming x < 5; ) {} // expected-error {{'__arm_streaming' 
cannot appear here}}
+  while (__arm_streaming bool k { false }) { // expected-error 
{{'__arm_streaming' only applies to function types}}
+  }
+  while (__arm_streaming true) { // expected-error {{'__arm_streaming' cannot 
appear here}}
+  }
+  do {
+  } while (__arm_streaming false); // expected-error {{'__arm_streaming' 
cannot appear here}}
+
+  for (__arm_streaming int n : { 1, 2, 3 }) { // expected-error 
{{'__arm_streaming' only applies to function types}}
+  }
+}
+
+enum class __attribute__((visibility("hidden"))) SecretKeepers {
+  one, /* rest are deprecated */ two, three
+};
+enum class __arm_streaming EvenMoreSecrets {}; // expected-error 
{{'__arm_streaming' cannot be applied to a declaration}}
+
+// Forbid attributes on decl specifiers.
+unsigned __arm_streaming static int __arm_streaming v1; // expected-error 
{{'__arm_streaming' only applies to function types}} \
+           expected-error {{'__arm_streaming' cannot appear here}}
+typedef __arm_streaming unsigned long __arm_streaming v2; // expected-error 
{{'__arm_streaming' only applies to function types}} \
+          expected-error {{'__arm_streaming' cannot appear here}}
+int __arm_streaming foo(int __arm_streaming x); // expected-error 2 
{{'__arm_streaming' only applies to function types}}
+
+__arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a 
declaration}}
+
+class A {
+  A(__arm_streaming int a); // expected-error {{'__arm_streaming' only applies 
to function types}}
+};
+A::A(__arm_streaming int a) {} // expected-error {{'__arm_streaming' only 
applies to function types}}
+
+template<typename T> struct TemplateStruct {};
+class FriendClassesWithAttributes {
+  // We allow GNU-style attributes here
+  template <class _Tp, class _Alloc> friend class 
__attribute__((__type_visibility__("default"))) vector;
+  template <class _Tp, class _Alloc> friend class 
__declspec(code_seg("foo,whatever")) vector2;
+  // But not C++11 ones
+  template <class _Tp, class _Alloc> friend class __arm_streaming vector3;     
                                    // expected-error {{'__arm_streaming' 
cannot appear here}}
+
+  // Also allowed
+  friend struct __attribute__((__type_visibility__("default"))) 
TemplateStruct<FriendClassesWithAttributes>;
+  friend struct __declspec(code_seg("foo,whatever")) 
TemplateStruct<FriendClassesWithAttributes>;
+  friend struct __arm_streaming TemplateStruct<FriendClassesWithAttributes>;   
                                    // expected-error {{'__arm_streaming' 
cannot appear here}}
+};
+
+// Check ordering: C++11 attributes must appear before GNU attributes.
+class Ordering {
+  void f1(
+    int (__arm_streaming __attribute__(()) int n) // expected-error 
{{'__arm_streaming' only applies to function types}}
+  ) {
+  }
+
+  void f2(
+      int (*)(__arm_streaming __attribute__(()) int n) // expected-error 
{{'__arm_streaming' only applies to function types}}
+  ) {
+  }
+
+  void f3(
+    int (__attribute__(()) __arm_streaming int n) // expected-error 
{{'__arm_streaming' cannot appear here}}
+  ) {
+  }
+
+  void f4(
+      int (*)(__attribute__(()) __arm_streaming int n) // expected-error 
{{'__arm_streaming' cannot appear here}}
+  ) {
+  }
+};
+
+namespace base_specs {
+struct A {};
+struct B : __arm_streaming A {}; // expected-error {{'__arm_streaming' cannot 
be applied to a base specifier}}
+struct C : __arm_streaming virtual A {}; // expected-error {{'__arm_streaming' 
cannot be applied to a base specifier}}
+struct D : __arm_streaming public virtual A {}; // expected-error 
{{'__arm_streaming' cannot be applied to a base specifier}}
+struct E : public __arm_streaming virtual A {}; // expected-error 
{{'__arm_streaming' cannot appear here}} \
+                                                   expected-error 
{{'__arm_streaming' cannot be applied to a base specifier}}
+struct F : virtual __arm_streaming public A {}; // expected-error 
{{'__arm_streaming' cannot appear here}} \
+                                                   expected-error 
{{'__arm_streaming' cannot be applied to a base specifier}}
+}
+
+namespace __arm_streaming ns_attr {}; // expected-error {{'__arm_streaming' 
cannot be applied to a declaration}} \
+                                         expected-warning {{attributes on a 
namespace declaration are a C++17 extension}}

diff  --git a/clang/utils/TableGen/ClangAttrEmitter.cpp 
b/clang/utils/TableGen/ClangAttrEmitter.cpp
index a05c7ab66a7a1..dc3434d61d329 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3882,7 +3882,8 @@ static void GenerateAppertainsTo(const Record &Attr, 
raw_ostream &OS) {
       OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
       OS << "const Decl *D) const override {\n";
       OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
-      OS << "    << AL << D->getLocation();\n";
+      OS << "    << AL << AL.isRegularKeywordAttribute() << "
+            "D->getLocation();\n";
       OS << "  return false;\n";
       OS << "}\n\n";
     }
@@ -3911,7 +3912,7 @@ static void GenerateAppertainsTo(const Record &Attr, 
raw_ostream &OS) {
     OS << (Warn ? "warn_attribute_wrong_decl_type_str"
                 : "err_attribute_wrong_decl_type_str");
     OS << ")\n";
-    OS << "      << Attr << ";
+    OS << "      << Attr << Attr.isRegularKeywordAttribute() << ";
     OS << CalculateDiagnostic(*SubjectObj) << ";\n";
     OS << "    return false;\n";
     OS << "  }\n";
@@ -3926,7 +3927,8 @@ static void GenerateAppertainsTo(const Record &Attr, 
raw_ostream &OS) {
       OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, ";
       OS << "const Stmt *St) const override {\n";
       OS << "  S.Diag(AL.getLoc(), 
diag::err_decl_attribute_invalid_on_stmt)\n";
-      OS << "    << AL << St->getBeginLoc();\n";
+      OS << "    << AL << AL.isRegularKeywordAttribute() << "
+            "St->getBeginLoc();\n";
       OS << "  return false;\n";
       OS << "}\n\n";
     }
@@ -3945,7 +3947,7 @@ static void GenerateAppertainsTo(const Record &Attr, 
raw_ostream &OS) {
     OS << (Warn ? "warn_attribute_wrong_decl_type_str"
                 : "err_attribute_wrong_decl_type_str");
     OS << ")\n";
-    OS << "      << Attr << ";
+    OS << "      << Attr << Attr.isRegularKeywordAttribute() << ";
     OS << CalculateDiagnostic(*SubjectObj) << ";\n";
     OS << "    return false;\n";
     OS << "  }\n";
@@ -4016,7 +4018,8 @@ static void GenerateMutualExclusionsChecks(const Record 
&Attr,
     for (const std::string &A : DeclAttrs) {
       OS << "    if (const auto *A = D->getAttr<" << A << ">()) {\n";
       OS << "      S.Diag(AL.getLoc(), 
diag::err_attributes_are_not_compatible)"
-         << " << AL << A;\n";
+         << " << AL << A << (AL.isRegularKeywordAttribute() ||"
+         << " A->isRegularKeywordAttribute());\n";
       OS << "      S.Diag(A->getLocation(), 
diag::note_conflicting_attribute);";
       OS << "      \nreturn false;\n";
       OS << "    }\n";
@@ -4037,7 +4040,8 @@ static void GenerateMutualExclusionsChecks(const Record 
&Attr,
                     << ">()) {\n";
         MergeDeclOS << "      S.Diag(First->getLocation(), "
                     << "diag::err_attributes_are_not_compatible) << First << "
-                    << "Second;\n";
+                    << "Second << (First->isRegularKeywordAttribute() || "
+                    << "Second->isRegularKeywordAttribute());\n";
         MergeDeclOS << "      S.Diag(Second->getLocation(), "
                     << "diag::note_conflicting_attribute);\n";
         MergeDeclOS << "      return false;\n";
@@ -4077,7 +4081,8 @@ static void GenerateMutualExclusionsChecks(const Record 
&Attr,
     MergeStmtOS << "      if (Iter != C.end()) {\n";
     MergeStmtOS << "        S.Diag((*Iter)->getLocation(), "
                 << "diag::err_attributes_are_not_compatible) << *Iter << "
-                << "Second;\n";
+                << "Second << ((*Iter)->isRegularKeywordAttribute() || "
+                << "Second->isRegularKeywordAttribute());\n";
     MergeStmtOS << "        S.Diag(Second->getLocation(), "
                 << "diag::note_conflicting_attribute);\n";
     MergeStmtOS << "        return false;\n";


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to