[clang] 8c7b64b - [clang] Reject non-declaration C++11 attributes on declarations

Martin Boehme via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 15 02:58:35 PDT 2022


Author: Martin Boehme
Date: 2022-06-15T11:58:26+02:00
New Revision: 8c7b64b5ae2a09027c38db969a04fc9ddd0cd6bb

URL: https://github.com/llvm/llvm-project/commit/8c7b64b5ae2a09027c38db969a04fc9ddd0cd6bb
DIFF: https://github.com/llvm/llvm-project/commit/8c7b64b5ae2a09027c38db969a04fc9ddd0cd6bb.diff

LOG: [clang] Reject non-declaration C++11 attributes on declarations

For backwards compatiblity, we emit only a warning instead of an error if the
attribute is one of the existing type attributes that we have historically
allowed to "slide" to the `DeclSpec` just as if it had been specified in GNU
syntax. (We will call these "legacy type attributes" below.)

The high-level changes that achieve this are:

- We introduce a new field `Declarator::DeclarationAttrs` (with appropriate
  accessors) to store C++11 attributes occurring in the attribute-specifier-seq
  at the beginning of a simple-declaration (and other similar declarations).
  Previously, these attributes were placed on the `DeclSpec`, which made it
  impossible to reconstruct later on whether the attributes had in fact been
  placed on the decl-specifier-seq or ahead of the declaration.

- In the parser, we propgate declaration attributes and decl-specifier-seq
  attributes separately until we can place them in
  `Declarator::DeclarationAttrs` or `DeclSpec::Attrs`, respectively.

- In `ProcessDeclAttributes()`, in addition to processing declarator attributes,
  we now also process the attributes from `Declarator::DeclarationAttrs` (except
  if they are legacy type attributes).

- In `ConvertDeclSpecToType()`, in addition to processing `DeclSpec` attributes,
  we also process any legacy type attributes that occur in
  `Declarator::DeclarationAttrs` (and emit a warning).

- We make `ProcessDeclAttribute` emit an error if it sees any non-declaration
  attributes in C++11 syntax, except in the following cases:
  - If it is being called for attributes on a `DeclSpec` or `DeclaratorChunk`
  - If the attribute is a legacy type attribute (in which case we only emit
    a warning)

The standard justifies treating attributes at the beginning of a
simple-declaration and attributes after a declarator-id the same. Here are some
relevant parts of the standard:

- The attribute-specifier-seq at the beginning of a simple-declaration
  "appertains to each of the entities declared by the declarators of the
  init-declarator-list" (https://eel.is/c++draft/dcl.dcl#dcl.pre-3)

- "In the declaration for an entity, attributes appertaining to that entity can
  appear at the start of the declaration and after the declarator-id for that
  declaration." (https://eel.is/c++draft/dcl.dcl#dcl.pre-note-2)

- "The optional attribute-specifier-seq following a declarator-id appertains to
  the entity that is declared."
  (https://eel.is/c++draft/dcl.dcl#dcl.meaning.general-1)

The standard contains similar wording to that for a simple-declaration in other
similar types of declarations, for example:

- "The optional attribute-specifier-seq in a parameter-declaration appertains to
  the parameter." (https://eel.is/c++draft/dcl.fct#3)

- "The optional attribute-specifier-seq in an exception-declaration appertains
  to the parameter of the catch clause" (https://eel.is/c++draft/except.pre#1)

The new behavior is tested both on the newly added type attribute
`annotate_type`, for which we emit errors, and for the legacy type attribute
`address_space` (chosen somewhat randomly from the various legacy type
attributes), for which we emit warnings.

Depends On D111548

Reviewed By: aaron.ballman, rsmith

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

Added: 
    clang/test/SemaCXX/address-space-placement.cpp

Modified: 
    clang/include/clang/Basic/AttributeCommonInfo.h
    clang/include/clang/Basic/DiagnosticCommonKinds.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Parse/RAIIObjectsForParser.h
    clang/include/clang/Sema/DeclSpec.h
    clang/include/clang/Sema/ParsedAttr.h
    clang/include/clang/Sema/Sema.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseExpr.cpp
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Parse/ParseObjc.cpp
    clang/lib/Parse/ParseOpenMP.cpp
    clang/lib/Parse/ParseStmt.cpp
    clang/lib/Parse/ParseTemplate.cpp
    clang/lib/Parse/Parser.cpp
    clang/lib/Sema/ParsedAttr.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaDeclObjC.cpp
    clang/lib/Sema/SemaType.cpp
    clang/test/AST/language_address_space_attribute.cpp
    clang/test/CodeGen/attr-btf_type_tag-func.c
    clang/test/CodeGen/attr-btf_type_tag-var.c
    clang/test/Frontend/noderef.c
    clang/test/Parser/MicrosoftExtensions.cpp
    clang/test/Parser/asm.c
    clang/test/Parser/asm.cpp
    clang/test/Parser/attributes.c
    clang/test/Parser/c2x-attributes.c
    clang/test/Parser/cxx0x-attributes.cpp
    clang/test/Sema/annotate-type.c
    clang/test/Sema/attr-declspec-ignored.c
    clang/test/Sema/attr-regparm.c
    clang/test/Sema/matrix-type-builtins.c
    clang/test/Sema/neon-vector-types.c
    clang/test/Sema/overload-arm-mve.c
    clang/test/Sema/vector-gcc-compat.c
    clang/test/SemaCXX/annotate-type.cpp
    clang/test/SemaObjC/attr-objc-gc.m
    clang/test/SemaOpenCL/address-spaces.cl
    clang/utils/TableGen/ClangAttrEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index afa8a893e921..81a8d2134193 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -150,6 +150,21 @@ class AttributeCommonInfo {
 
   bool isAlignasAttribute() const {
     // FIXME: Use a better mechanism to determine this.
+    // We use this in `isCXX11Attribute` below, so it _should_ only return
+    // true for the `alignas` spelling, but it currently also returns true
+    // for the `_Alignas` spelling, which only exists in C11. Distinguishing
+    // between the two is important because they behave 
diff erently:
+    // - `alignas` may only appear in the attribute-specifier-seq before
+    //   the decl-specifier-seq and is therefore associated with the
+    //   declaration.
+    // - `_Alignas` may appear anywhere within the declaration-specifiers
+    //   and is therefore associated with the `DeclSpec`.
+    // It's not clear how best to fix this:
+    // - We have the necessary information in the form of the `SpellingIndex`,
+    //   but we would need to compare against AlignedAttr::Keyword_alignas,
+    //   and we can't depend on clang/AST/Attr.h here.
+    // - We could test `getAttrName()->getName() == "alignas"`, but this is
+    //   inefficient.
     return getParsedKind() == AT_Aligned && isKeywordAttribute();
   }
 

diff  --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index c140a33694f3..39dee7e683ff 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -163,6 +163,8 @@ def err_opencl_unknown_type_specifier : Error<
 
 def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
+def warn_attribute_ignored : Warning<"%0 attribute ignored">,
+  InGroup<IgnoredAttributes>;
 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/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0e6573241b55..f2190613d740 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3354,8 +3354,6 @@ def warn_redeclaration_without_import_attribute : Warning<
 def warn_dllimport_dropped_from_inline_function : Warning<
   "%q0 redeclared inline; %1 attribute ignored">,
   InGroup<IgnoredAttributes>;
-def warn_attribute_ignored : Warning<"%0 attribute ignored">,
-  InGroup<IgnoredAttributes>;
 def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts with"
   " exception specification; attribute ignored">,
   InGroup<IgnoredAttributes>;
@@ -3392,8 +3390,11 @@ 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">;
-def err_stmt_attribute_invalid_on_decl : Error<
+def err_attribute_invalid_on_decl : Error<
   "%0 attribute 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>;
 def warn_declspec_attribute_ignored : Warning<
   "attribute %0 is ignored, place it after "
   "\"%select{class|struct|interface|union|enum}1\" to apply attribute to "

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 5bf7b276c328..0eb6f7104a55 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2075,7 +2075,8 @@ class Parser : public CodeCompletionHandler {
       SourceLocation *TrailingElseLoc = nullptr);
   StmtResult ParseStatementOrDeclarationAfterAttributes(
       StmtVector &Stmts, ParsedStmtContext StmtCtx,
-      SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs);
+      SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
+      ParsedAttributes &DeclSpecAttrs);
   StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
   StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
                                    ParsedStmtContext StmtCtx);
@@ -2324,15 +2325,18 @@ class Parser : public CodeCompletionHandler {
 
   DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
                                   SourceLocation &DeclEnd,
-                                  ParsedAttributes &Attrs,
+                                  ParsedAttributes &DeclAttrs,
+                                  ParsedAttributes &DeclSpecAttrs,
                                   SourceLocation *DeclSpecStart = nullptr);
   DeclGroupPtrTy
   ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
-                         ParsedAttributes &Attrs, bool RequireSemi,
+                         ParsedAttributes &DeclAttrs,
+                         ParsedAttributes &DeclSpecAttrs, bool RequireSemi,
                          ForRangeInit *FRI = nullptr,
                          SourceLocation *DeclSpecStart = nullptr);
   bool MightBeDeclarator(DeclaratorContext Context);
   DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
+                                ParsedAttributes &Attrs,
                                 SourceLocation *DeclEnd = nullptr,
                                 ForRangeInit *FRI = nullptr);
   Decl *ParseDeclarationAfterDeclarator(Declarator &D,

diff  --git a/clang/include/clang/Parse/RAIIObjectsForParser.h b/clang/include/clang/Parse/RAIIObjectsForParser.h
index 8e6e03685c50..5ae609e60073 100644
--- a/clang/include/clang/Parse/RAIIObjectsForParser.h
+++ b/clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -201,9 +201,11 @@ namespace clang {
     ParsingDeclRAIIObject ParsingRAII;
 
   public:
-    ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, DeclaratorContext C)
-      : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
-    }
+    ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS,
+                      const ParsedAttributes &DeclarationAttrs,
+                      DeclaratorContext C)
+        : Declarator(DS, DeclarationAttrs, C),
+          ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
 
     const ParsingDeclSpec &getDeclSpec() const {
       return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
@@ -228,9 +230,10 @@ namespace clang {
     ParsingDeclRAIIObject ParsingRAII;
 
   public:
-    ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
-      : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
-    }
+    ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS,
+                           const ParsedAttributes &DeclarationAttrs)
+        : FieldDeclarator(DS, DeclarationAttrs),
+          ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
 
     const ParsingDeclSpec &getDeclSpec() const {
       return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());

diff  --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index dc1fbf098a8a..21d4a53d8e22 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1852,9 +1852,13 @@ class Declarator {
   /// Indicates whether this declarator has an initializer.
   unsigned HasInitializer : 1;
 
-  /// Attrs - Attributes.
+  /// Attributes attached to the declarator.
   ParsedAttributes Attrs;
 
+  /// Attributes attached to the declaration. See also documentation for the
+  /// corresponding constructor parameter.
+  const ParsedAttributesView &DeclarationAttrs;
+
   /// The asm label, if specified.
   Expr *AsmLabel;
 
@@ -1893,16 +1897,40 @@ class Declarator {
   friend struct DeclaratorChunk;
 
 public:
-  Declarator(const DeclSpec &ds, DeclaratorContext C)
-      : DS(ds), Range(ds.getSourceRange()), Context(C),
+  /// `DS` and `DeclarationAttrs` must outlive the `Declarator`. In particular,
+  /// take care not to pass temporary objects for these parameters.
+  ///
+  /// `DeclarationAttrs` contains [[]] attributes from the
+  /// attribute-specifier-seq at the beginning of a declaration, which appertain
+  /// to the declared entity itself. Attributes with other syntax (e.g. GNU)
+  /// should not be placed in this attribute list; if they occur at the
+  /// beginning of a declaration, they apply to the `DeclSpec` and should be
+  /// attached to that instead.
+  ///
+  /// Here is an example of an attribute associated with a declaration:
+  ///
+  ///  [[deprecated]] int x, y;
+  ///
+  /// This attribute appertains to all of the entities declared in the
+  /// declaration, i.e. `x` and `y` in this case.
+  Declarator(const DeclSpec &DS, const ParsedAttributesView &DeclarationAttrs,
+             DeclaratorContext C)
+      : DS(DS), Range(DS.getSourceRange()), Context(C),
         InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
         GroupingParens(false), FunctionDefinition(static_cast<unsigned>(
                                    FunctionDefinitionKind::Declaration)),
         Redeclaration(false), Extension(false), ObjCIvar(false),
         ObjCWeakProperty(false), InlineStorageUsed(false),
-        HasInitializer(false), Attrs(ds.getAttributePool().getFactory()),
-        AsmLabel(nullptr), TrailingRequiresClause(nullptr),
-        InventedTemplateParameterList(nullptr) {}
+        HasInitializer(false), Attrs(DS.getAttributePool().getFactory()),
+        DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr),
+        TrailingRequiresClause(nullptr),
+        InventedTemplateParameterList(nullptr) {
+    assert(llvm::all_of(DeclarationAttrs,
+                        [](const ParsedAttr &AL) {
+                          return AL.isStandardAttributeSyntax();
+                        }) &&
+           "DeclarationAttrs may only contain [[]] attributes");
+  }
 
   ~Declarator() {
     clear();
@@ -2531,9 +2559,14 @@ class Declarator {
   const ParsedAttributes &getAttributes() const { return Attrs; }
   ParsedAttributes &getAttributes() { return Attrs; }
 
+  const ParsedAttributesView &getDeclarationAttributes() const {
+    return DeclarationAttrs;
+  }
+
   /// hasAttributes - do we contain any attributes?
   bool hasAttributes() const {
-    if (!getAttributes().empty() || getDeclSpec().hasAttributes())
+    if (!getAttributes().empty() || !getDeclarationAttributes().empty() ||
+        getDeclSpec().hasAttributes())
       return true;
     for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i)
       if (!getTypeObject(i).getAttrs().empty())
@@ -2615,8 +2648,10 @@ class Declarator {
 struct FieldDeclarator {
   Declarator D;
   Expr *BitfieldSize;
-  explicit FieldDeclarator(const DeclSpec &DS)
-      : D(DS, DeclaratorContext::Member), BitfieldSize(nullptr) {}
+  explicit FieldDeclarator(const DeclSpec &DS,
+                           const ParsedAttributes &DeclarationAttrs)
+      : D(DS, DeclarationAttrs, DeclaratorContext::Member),
+        BitfieldSize(nullptr) {}
 };
 
 /// Represents a C++11 virt-specifier-seq.

diff  --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index 554d73b8901d..2fe5d7c5c715 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -651,6 +651,18 @@ class ParsedAttr final
   bool isKnownToGCC() const;
   bool isSupportedByPragmaAttribute() const;
 
+  /// Returns whether a [[]] attribute, if specified ahead of a declaration,
+  /// should be applied to the decl-specifier-seq instead (i.e. whether it
+  /// "slides" to the decl-specifier-seq).
+  ///
+  /// By the standard, attributes specified before the declaration always
+  /// appertain to the declaration, but historically we have allowed some of
+  /// these attributes to slide to the decl-specifier-seq, so we need to keep
+  /// supporting this behavior.
+  ///
+  /// This may only be called if isStandardAttributeSyntax() returns true.
+  bool slidesFromDeclToDeclSpecLegacyBehavior() const;
+
   /// If the parsed attribute has a semantic equivalent, and it would
   /// have a semantic Spelling enumeration (due to having semantically-distinct
   /// spelling variations), return the value of that semantic spelling. If the
@@ -901,6 +913,12 @@ class ParsedAttributesView {
 
 public:
   SourceRange Range;
+
+  static const ParsedAttributesView &none() {
+    static const ParsedAttributesView Attrs;
+    return Attrs;
+  }
+
   bool empty() const { return AttrList.empty(); }
   SizeType size() const { return AttrList.size(); }
   ParsedAttr &operator[](SizeType pos) { return *AttrList[pos]; }
@@ -1103,6 +1121,11 @@ class ParsedAttributes : public ParsedAttributesView {
   mutable AttributePool pool;
 };
 
+/// Consumes the attributes from `First` and `Second` and concatenates them into
+/// `Result`. Sets `Result.Range` to the combined range of `First` and `Second`.
+void takeAndConcatenateAttrs(ParsedAttributes &First, ParsedAttributes &Second,
+                             ParsedAttributes &Result);
+
 /// These constants match the enumerated choices of
 /// err_attribute_argument_n_type and err_attribute_argument_type.
 enum AttributeArgumentNType {

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index aeb0a43e872e..8c2a56ab282b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4429,8 +4429,38 @@ class Sema final {
   // Helper for delayed processing of attributes.
   void ProcessDeclAttributeDelayed(Decl *D,
                                    const ParsedAttributesView &AttrList);
-  void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL,
-                             bool IncludeCXX11Attributes = true);
+
+  // Options for ProcessDeclAttributeList().
+  struct ProcessDeclAttributeOptions {
+    ProcessDeclAttributeOptions()
+        : IncludeCXX11Attributes(true), IgnoreTypeAttributes(false) {}
+
+    ProcessDeclAttributeOptions WithIncludeCXX11Attributes(bool Val) {
+      ProcessDeclAttributeOptions Result = *this;
+      Result.IncludeCXX11Attributes = Val;
+      return Result;
+    }
+
+    ProcessDeclAttributeOptions WithIgnoreTypeAttributes(bool Val) {
+      ProcessDeclAttributeOptions Result = *this;
+      Result.IgnoreTypeAttributes = Val;
+      return Result;
+    }
+
+    // Should C++11 attributes be processed?
+    bool IncludeCXX11Attributes;
+
+    // Should any type attributes encountered be ignored?
+    // If this option is false, a diagnostic will be emitted for any type
+    // attributes of a kind that does not "slide" from the declaration to
+    // the decl-specifier-seq.
+    bool IgnoreTypeAttributes;
+  };
+
+  void ProcessDeclAttributeList(Scope *S, Decl *D,
+                                const ParsedAttributesView &AttrList,
+                                const ProcessDeclAttributeOptions &Options =
+                                    ProcessDeclAttributeOptions());
   bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
                                    const ParsedAttributesView &AttrList);
 

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 12af519c0919..a90d5d9cc485 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -57,7 +57,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context,
     *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : nullptr;
 
   // Parse the abstract-declarator, if present.
-  Declarator DeclaratorInfo(DS, Context);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);
   ParseDeclarator(DeclaratorInfo);
   if (Range)
     *Range = DeclaratorInfo.getSourceRange();
@@ -1760,7 +1760,8 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs,
 ///
 Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
                                                 SourceLocation &DeclEnd,
-                                                ParsedAttributes &Attrs,
+                                                ParsedAttributes &DeclAttrs,
+                                                ParsedAttributes &DeclSpecAttrs,
                                                 SourceLocation *DeclSpecStart) {
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
   // Must temporarily exit the objective-c container scope for
@@ -1771,32 +1772,40 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
   switch (Tok.getKind()) {
   case tok::kw_template:
   case tok::kw_export:
-    ProhibitAttributes(Attrs);
-    SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, Attrs);
+    ProhibitAttributes(DeclAttrs);
+    ProhibitAttributes(DeclSpecAttrs);
+    SingleDecl =
+        ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
     break;
   case tok::kw_inline:
     // Could be the start of an inline namespace. Allowed as an ext in C++03.
     if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
-      ProhibitAttributes(Attrs);
+      ProhibitAttributes(DeclAttrs);
+      ProhibitAttributes(DeclSpecAttrs);
       SourceLocation InlineLoc = ConsumeToken();
       return ParseNamespace(Context, DeclEnd, InlineLoc);
     }
-    return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr,
-                                  DeclSpecStart);
+    return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
+                                  true, nullptr, DeclSpecStart);
   case tok::kw_namespace:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(DeclAttrs);
+    ProhibitAttributes(DeclSpecAttrs);
     return ParseNamespace(Context, DeclEnd);
-  case tok::kw_using:
+  case tok::kw_using: {
+    ParsedAttributes Attrs(AttrFactory);
+    takeAndConcatenateAttrs(DeclAttrs, DeclSpecAttrs, Attrs);
     return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
                                             DeclEnd, Attrs);
+  }
   case tok::kw_static_assert:
   case tok::kw__Static_assert:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(DeclAttrs);
+    ProhibitAttributes(DeclSpecAttrs);
     SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
     break;
   default:
-    return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr,
-                                  DeclSpecStart);
+    return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
+                                  true, nullptr, DeclSpecStart);
   }
 
   // This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1826,10 +1835,17 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
 /// the Declaration. The SourceLocation for this Decl is set to
 /// DeclSpecStart if DeclSpecStart is non-null.
 Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
-    DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &Attrs,
+    DeclaratorContext Context, SourceLocation &DeclEnd,
+    ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs,
     bool RequireSemi, ForRangeInit *FRI, SourceLocation *DeclSpecStart) {
+  // Need to retain these for diagnostics before we add them to the DeclSepc.
+  ParsedAttributesView OriginalDeclSpecAttrs;
+  OriginalDeclSpecAttrs.addAll(DeclSpecAttrs.begin(), DeclSpecAttrs.end());
+  OriginalDeclSpecAttrs.Range = DeclSpecAttrs.Range;
+
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
+  DS.takeAttributesFrom(DeclSpecAttrs);
 
   DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
@@ -1843,7 +1859,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
   // declaration-specifiers init-declarator-list[opt] ';'
   if (Tok.is(tok::semi)) {
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(DeclAttrs);
     DeclEnd = Tok.getLocation();
     if (RequireSemi) ConsumeToken();
     RecordDecl *AnonRecord = nullptr;
@@ -1860,8 +1876,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
   if (DeclSpecStart)
     DS.SetRangeStart(*DeclSpecStart);
 
-  DS.takeAttributesFrom(Attrs);
-  return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
+  return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
 }
 
 /// Returns true if this might be the start of a declarator, or a common typo
@@ -2016,10 +2031,16 @@ void Parser::SkipMalformedDecl() {
 /// result.
 Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
                                               DeclaratorContext Context,
+                                              ParsedAttributes &Attrs,
                                               SourceLocation *DeclEnd,
                                               ForRangeInit *FRI) {
   // Parse the first declarator.
-  ParsingDeclarator D(*this, DS, Context);
+  // Consume all of the attributes from `Attrs` by moving them to our own local
+  // list. This ensures that we will not attempt to interpret them as statement
+  // attributes higher up the callchain.
+  ParsedAttributes LocalAttrs(AttrFactory);
+  LocalAttrs.takeAllFrom(Attrs);
+  ParsingDeclarator D(*this, DS, LocalAttrs, Context);
   ParseDeclarator(D);
 
   // Bail out if the first declarator didn't seem well-formed.
@@ -3176,11 +3197,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       if (!AttrsLastTime)
         ProhibitAttributes(attrs);
       else {
-        // Reject most C++11 / C2x attributes on the decl-specifier-seq, but
-        // allow `annotate_type` as a special case.
-        // FIXME: We should more generally allow type attributes to be placed
-        // on the decl-specifier-seq; https://reviews.llvm.org/D126061 will
-        // make this change.
+        // Reject C++11 / C2x attributes that aren't type attributes.
         for (const ParsedAttr &PA : attrs) {
           if (!PA.isCXX11Attribute() && !PA.isC2xAttribute())
             continue;
@@ -3188,7 +3205,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
             // We will warn about the unknown attribute elsewhere (in
             // SemaDeclAttr.cpp)
             continue;
-          if (PA.getKind() == ParsedAttr::AT_AnnotateType)
+          // GCC ignores this attribute when placed on the DeclSpec in [[]]
+          // syntax, so we do the same.
+          if (PA.getKind() == ParsedAttr::AT_VectorSize) {
+            Diag(PA.getLoc(), diag::warn_attribute_ignored) << PA;
+            PA.setInvalid();
+            continue;
+          }
+          // We reject AT_LifetimeBound and AT_AnyX86NoCfCheck, even though they
+          // are type attributes, because we historically haven't allowed these
+          // to be used as type attributes in C++11 / C2x syntax.
+          if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound &&
+              PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck)
             continue;
           Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
           PA.setInvalid();
@@ -4317,7 +4345,6 @@ void Parser::ParseStructDeclaration(
   // Parse leading attributes.
   ParsedAttributes Attrs(AttrFactory);
   MaybeParseCXX11Attributes(Attrs);
-  DS.takeAttributesFrom(Attrs);
 
   // Parse the common specifier-qualifiers-list piece.
   ParseSpecifierQualifierList(DS);
@@ -4325,6 +4352,11 @@ void Parser::ParseStructDeclaration(
   // If there are no declarators, this is a free-standing declaration
   // specifier. Let the actions module cope with it.
   if (Tok.is(tok::semi)) {
+    // C2x 6.7.2.1p9 : "The optional attribute specifier sequence in a
+    // member declaration appertains to each of the members declared by the
+    // member declarator list; it shall not appear if the optional member
+    // declarator list is omitted."
+    ProhibitAttributes(Attrs);
     RecordDecl *AnonRecord = nullptr;
     Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
                                                        DS, AnonRecord);
@@ -4337,7 +4369,7 @@ void Parser::ParseStructDeclaration(
   bool FirstDeclarator = true;
   SourceLocation CommaLoc;
   while (true) {
-    ParsingFieldDeclarator DeclaratorInfo(*this, DS);
+    ParsingFieldDeclarator DeclaratorInfo(*this, DS, Attrs);
     DeclaratorInfo.D.setCommaLoc(CommaLoc);
 
     // Attributes are only allowed here on successive declarators.
@@ -4696,7 +4728,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
       // declares 'enum E : int; E *p;' not 'enum E : int*; E p;'.
       DeclSpec DS(AttrFactory);
       ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier);
-      Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+      Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                                DeclaratorContext::TypeName);
       BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
 
       BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
@@ -6618,9 +6651,9 @@ void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
 /// declarator D up to a paren, which indicates that we are parsing function
 /// arguments.
 ///
-/// If FirstArgAttrs is non-null, then the caller parsed those arguments
-/// immediately after the open paren - they should be considered to be the
-/// first argument of a parameter.
+/// If FirstArgAttrs is non-null, then the caller parsed those attributes
+/// immediately after the open paren - they will be applied to the DeclSpec
+/// of the first parameter.
 ///
 /// If RequiresArg is true, then the first argument of the function is required
 /// to be present and required to not be an identifier list.
@@ -6922,7 +6955,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
 ///
 /// DeclContext is the context of the declarator being parsed.  If FirstArgAttrs
 /// is non-null, then the caller parsed those attributes immediately after the
-/// open paren - they should be considered to be part of the first parameter.
+/// open paren - they will be applied to the DeclSpec of the first parameter.
 ///
 /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
 /// be the location of the ellipsis, if any was parsed.
@@ -6974,33 +7007,37 @@ void Parser::ParseParameterDeclarationClause(
     // Just use the ParsingDeclaration "scope" of the declarator.
     DeclSpec DS(AttrFactory);
 
-    // Parse any C++11 attributes.
-    MaybeParseCXX11Attributes(DS.getAttributes());
+    ParsedAttributes ArgDeclAttrs(AttrFactory);
+    ParsedAttributes ArgDeclSpecAttrs(AttrFactory);
+
+    if (FirstArgAttrs.Range.isValid()) {
+      // If the caller parsed attributes for the first argument, add them now.
+      // Take them so that we only apply the attributes to the first parameter.
+      // We have already started parsing the decl-specifier sequence, so don't
+      // parse any parameter-declaration pieces that precede it.
+      ArgDeclSpecAttrs.takeAllFrom(FirstArgAttrs);
+    } else {
+      // Parse any C++11 attributes.
+      MaybeParseCXX11Attributes(ArgDeclAttrs);
 
-    // Skip any Microsoft attributes before a param.
-    MaybeParseMicrosoftAttributes(DS.getAttributes());
+      // Skip any Microsoft attributes before a param.
+      MaybeParseMicrosoftAttributes(ArgDeclSpecAttrs);
+    }
 
     SourceLocation DSStart = Tok.getLocation();
 
-    // If the caller parsed attributes for the first argument, add them now.
-    // Take them so that we only apply the attributes to the first parameter.
-    // FIXME: If we can leave the attributes in the token stream somehow, we can
-    // get rid of a parameter (FirstArgAttrs) and this statement. It might be
-    // too much hassle.
-    DS.takeAttributesFrom(FirstArgAttrs);
-
     ParseDeclarationSpecifiers(DS);
-
+    DS.takeAttributesFrom(ArgDeclSpecAttrs);
 
     // Parse the declarator.  This is "PrototypeContext" or
     // "LambdaExprParameterContext", because we must accept either
     // 'declarator' or 'abstract-declarator' here.
-    Declarator ParmDeclarator(
-        DS, DeclaratorCtx == DeclaratorContext::RequiresExpr
-                ? DeclaratorContext::RequiresExpr
-                : DeclaratorCtx == DeclaratorContext::LambdaExpr
-                      ? DeclaratorContext::LambdaExprParameter
-                      : DeclaratorContext::Prototype);
+    Declarator ParmDeclarator(DS, ArgDeclAttrs,
+                              DeclaratorCtx == DeclaratorContext::RequiresExpr
+                                  ? DeclaratorContext::RequiresExpr
+                              : DeclaratorCtx == DeclaratorContext::LambdaExpr
+                                  ? DeclaratorContext::LambdaExprParameter
+                                  : DeclaratorContext::Prototype);
     ParseDeclarator(ParmDeclarator);
 
     // Parse GNU attributes, if present.
@@ -7299,7 +7336,8 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
   assert(!D.mayOmitIdentifier() && "Declarator cannot omit identifier");
 
   SourceLocation StartBracketLoc = Tok.getLocation();
-  Declarator TempDeclarator(D.getDeclSpec(), D.getContext());
+  Declarator TempDeclarator(D.getDeclSpec(), ParsedAttributesView::none(),
+                            D.getContext());
 
   while (Tok.is(tok::l_square)) {
     ParseBracketDeclarator(TempDeclarator);

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 1afe1995237a..8b55b4c57aa6 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -355,8 +355,8 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
                 getCurScope(), DS.getSourceRange().getBegin(), Lang.get(),
                 Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
 
-  ParsedAttributes attrs(AttrFactory);
-  MaybeParseCXX11Attributes(attrs);
+  ParsedAttributes DeclAttrs(AttrFactory);
+  MaybeParseCXX11Attributes(DeclAttrs);
 
   if (Tok.isNot(tok::l_brace)) {
     // Reset the source range in DS, as the leading "extern"
@@ -365,7 +365,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
     DS.SetRangeEnd(SourceLocation());
     // ... but anyway remember that such an "extern" was seen.
     DS.setExternInLinkageSpec(true);
-    ParseExternalDeclaration(attrs, &DS);
+    ParseExternalDeclaration(DeclAttrs, &DS);
     return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
                              getCurScope(), LinkageSpec, SourceLocation())
                        : nullptr;
@@ -373,7 +373,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
 
   DS.abort();
 
-  ProhibitAttributes(attrs);
+  ProhibitAttributes(DeclAttrs);
 
   BalancedDelimiterTracker T(*this, tok::l_brace);
   T.consumeOpen();
@@ -1217,7 +1217,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
 
     EndLocation = ParseDecltypeSpecifier(DS);
 
-    Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+    Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                              DeclaratorContext::TypeName);
     return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
   }
 
@@ -1309,7 +1310,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
   DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type,
                      Actions.getASTContext().getPrintingPolicy());
 
-  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::TypeName);
   return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
 }
 
@@ -2680,23 +2682,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
                                           TemplateInfo, TemplateDiags);
   }
 
-  ParsedAttributes attrs(AttrFactory);
-  ParsedAttributesView FnAttrs;
+  ParsedAttributes DeclAttrs(AttrFactory);
   // Optional C++11 attribute-specifier
-  MaybeParseCXX11Attributes(attrs);
+  MaybeParseCXX11Attributes(DeclAttrs);
 
   // The next token may be an OpenMP pragma annotation token. That would
   // normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in
   // this case, it came from an *attribute* rather than a pragma. Handle it now.
   if (Tok.is(tok::annot_attr_openmp))
-    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
-
-  // We need to keep these attributes for future diagnostic
-  // before they are taken over by declaration specifier.
-  FnAttrs.addAll(attrs.begin(), attrs.end());
-  FnAttrs.Range = attrs.Range;
-
-  MaybeParseMicrosoftAttributes(attrs);
+    return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs);
 
   if (Tok.is(tok::kw_using)) {
     // Eat 'using'.
@@ -2717,16 +2711,20 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     SourceLocation DeclEnd;
     // Otherwise, it must be a using-declaration or an alias-declaration.
     return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo,
-                                 UsingLoc, DeclEnd, attrs, AS);
+                                 UsingLoc, DeclEnd, DeclAttrs, AS);
   }
 
+  ParsedAttributes DeclSpecAttrs(AttrFactory);
+  MaybeParseMicrosoftAttributes(DeclSpecAttrs);
+
   // Hold late-parsed attributes so we can attach a Decl to them later.
   LateParsedAttrList CommonLateParsedAttrs;
 
   // decl-specifier-seq:
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this, TemplateDiags);
-  DS.takeAttributesFrom(attrs);
+  DS.takeAttributesFrom(DeclSpecAttrs);
+
   if (MalformedTypeSpec)
     DS.SetTypeSpecError();
 
@@ -2764,7 +2762,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 
   if (TryConsumeToken(tok::semi)) {
     if (DS.isFriendSpecified())
-      ProhibitAttributes(FnAttrs);
+      ProhibitAttributes(DeclAttrs);
 
     RecordDecl *AnonRecord = nullptr;
     Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
@@ -2777,7 +2775,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
 
-  ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member);
+  ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs,
+                                   DeclaratorContext::Member);
   if (TemplateInfo.TemplateParams)
     DeclaratorInfo.setTemplateParameterLists(TemplateParams);
   VirtSpecifiers VS;
@@ -2869,7 +2868,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
         DS.isFriendSpecified()) {
       // Diagnose attributes that appear before decl specifier:
       // [[]] friend int foo();
-      ProhibitAttributes(FnAttrs);
+      ProhibitAttributes(DeclAttrs);
     }
 
     if (DefinitionKind != FunctionDefinitionKind::Declaration) {

diff  --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 6d0fd7e2f601..a6a946d7f31b 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1212,7 +1212,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
             DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ,
                                Actions.getASTContext().getPrintingPolicy());
 
-            Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+            Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                                      DeclaratorContext::TypeName);
             TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
                                                   DeclaratorInfo);
             if (Ty.isInvalid())
@@ -1490,7 +1491,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
                          PrevSpec, DiagID, Type,
                          Actions.getASTContext().getPrintingPolicy());
 
-      Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+      Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                                DeclaratorContext::TypeName);
       TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
       if (Ty.isInvalid())
         break;
@@ -2296,7 +2298,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
       if (isTypeIdUnambiguously()) {
         DeclSpec DS(AttrFactory);
         ParseSpecifierQualifierList(DS);
-        Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+        Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                                  DeclaratorContext::TypeName);
         ParseDeclarator(DeclaratorInfo);
 
         SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation());
@@ -2959,7 +2962,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
     // Parse the type declarator.
     DeclSpec DS(AttrFactory);
     ParseSpecifierQualifierList(DS);
-    Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+    Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                              DeclaratorContext::TypeName);
     ParseDeclarator(DeclaratorInfo);
 
     // If our type is followed by an identifier and either ':' or ']', then
@@ -3494,7 +3498,8 @@ void Parser::ParseBlockId(SourceLocation CaretLoc) {
   ParseSpecifierQualifierList(DS);
 
   // Parse the block-declarator.
-  Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteral);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::BlockLiteral);
   DeclaratorInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
   ParseDeclarator(DeclaratorInfo);
 
@@ -3533,7 +3538,8 @@ ExprResult Parser::ParseBlockLiteralExpression() {
 
   // Parse the return type if present.
   DeclSpec DS(AttrFactory);
-  Declarator ParamInfo(DS, DeclaratorContext::BlockLiteral);
+  Declarator ParamInfo(DS, ParsedAttributesView::none(),
+                       DeclaratorContext::BlockLiteral);
   ParamInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
   // FIXME: Since the return type isn't actually parsed, it can't be used to
   // fill ParamInfo with an initial valid range, so do it manually.

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 7b66f6c46339..c2dc71f5f875 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1248,7 +1248,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
-  Declarator D(DS, DeclaratorContext::LambdaExpr);
+  Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr);
   TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
   Actions.PushLambdaScope();
 
@@ -1523,7 +1523,8 @@ ExprResult Parser::ParseCXXCasts() {
   ParseSpecifierQualifierList(DS);
 
   // Parse the abstract-declarator, if present.
-  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::TypeName);
   ParseDeclarator(DeclaratorInfo);
 
   SourceLocation RAngleBracketLoc = Tok.getLocation();
@@ -1849,7 +1850,8 @@ ExprResult Parser::ParseCXXThis() {
 /// In C++1z onwards, the type specifier can also be a template-name.
 ExprResult
 Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
-  Declarator DeclaratorInfo(DS, DeclaratorContext::FunctionalCast);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::FunctionalCast);
   ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
 
   assert((Tok.is(tok::l_paren) ||
@@ -2048,9 +2050,11 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
     if (Tok.is(tok::kw_using))
       DG = ParseAliasDeclarationInInitStatement(
           DeclaratorContext::SelectionInit, attrs);
-    else
+    else {
+      ParsedAttributes DeclSpecAttrs(AttrFactory);
       DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd,
-                                  attrs, /*RequireSemi=*/true);
+                                  attrs, DeclSpecAttrs, /*RequireSemi=*/true);
+    }
     *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
     return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
   }
@@ -2061,8 +2065,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
     // permitted here.
     assert(FRI && "should not parse a for range declaration here");
     SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-    DeclGroupPtrTy DG = ParseSimpleDeclaration(DeclaratorContext::ForInit,
-                                               DeclEnd, attrs, false, FRI);
+    ParsedAttributes DeclSpecAttrs(AttrFactory);
+    DeclGroupPtrTy DG = ParseSimpleDeclaration(
+        DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, FRI);
     FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
     assert((FRI->ColonLoc.isValid() || !DG) &&
            "cannot find for range declaration");
@@ -2079,11 +2084,10 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
 
   // type-specifier-seq
   DeclSpec DS(AttrFactory);
-  DS.takeAttributesFrom(attrs);
   ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
 
   // declarator
-  Declarator DeclaratorInfo(DS, DeclaratorContext::Condition);
+  Declarator DeclaratorInfo(DS, attrs, DeclaratorContext::Condition);
   ParseDeclarator(DeclaratorInfo);
 
   // simple-asm-expr[opt]
@@ -2736,7 +2740,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
 
   // Parse the conversion-declarator, which is merely a sequence of
   // ptr-operators.
-  Declarator D(DS, DeclaratorContext::ConversionId);
+  Declarator D(DS, ParsedAttributesView::none(),
+               DeclaratorContext::ConversionId);
   ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr);
 
   // Finish up the type.
@@ -3094,7 +3099,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
 
   SourceRange TypeIdParens;
   DeclSpec DS(AttrFactory);
-  Declarator DeclaratorInfo(DS, DeclaratorContext::CXXNew);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::CXXNew);
   if (Tok.is(tok::l_paren)) {
     // If it turns out to be a placement, we change the type location.
     BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -3945,7 +3951,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
   if (ParseAs >= CompoundLiteral) {
     // Parse the type declarator.
     DeclSpec DS(AttrFactory);
-    Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+    Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                              DeclaratorContext::TypeName);
     {
       ColonProtectionRAIIObject InnerColonProtection(*this);
       ParseSpecifierQualifierList(DS);
@@ -4023,7 +4030,8 @@ ExprResult Parser::ParseBuiltinBitCast() {
   ParseSpecifierQualifierList(DS);
 
   // Parse the abstract-declarator, if present.
-  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::TypeName);
   ParseDeclarator(DeclaratorInfo);
 
   if (ExpectAndConsume(tok::comma)) {

diff  --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 15cec81ef1b3..734c66f65dc2 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -650,19 +650,21 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
       if (Tok.is(tok::r_brace))
         break;
 
-      ParsedAttributes attrs(AttrFactory);
+      ParsedAttributes EmptyAttrs(AttrFactory);
 
       // Since we call ParseDeclarationOrFunctionDefinition() instead of
       // ParseExternalDeclaration() below (so that this doesn't parse nested
       // @interfaces), this needs to duplicate some code from the latter.
       if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
         SourceLocation DeclEnd;
-        allTUVariables.push_back(
-            ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs));
+        ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+        allTUVariables.push_back(ParseDeclaration(
+            DeclaratorContext::File, DeclEnd, EmptyAttrs, EmptyDeclSpecAttrs));
         continue;
       }
 
-      allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
+      allTUVariables.push_back(
+          ParseDeclarationOrFunctionDefinition(EmptyAttrs));
       continue;
     }
 
@@ -1225,6 +1227,10 @@ static void takeDeclAttributes(ParsedAttributesView &attrs,
 /// declarator and add them to the given list.
 static void takeDeclAttributes(ParsedAttributes &attrs,
                                Declarator &D) {
+  // This gets called only from Parser::ParseObjCTypeName(), and that should
+  // never add declaration attributes to the Declarator.
+  assert(D.getDeclarationAttributes().empty());
+
   // First, take ownership of all attributes.
   attrs.getPool().takeAllFrom(D.getAttributePool());
   attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
@@ -1268,7 +1274,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
     if (context == DeclaratorContext::ObjCResult)
       dsContext = DeclSpecContext::DSC_objc_method_result;
     ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
-    Declarator declarator(declSpec, context);
+    Declarator declarator(declSpec, ParsedAttributesView::none(), context);
     ParseDeclarator(declarator);
 
     // If that's not invalid, extract a type.
@@ -1487,7 +1493,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
     DeclSpec DS(AttrFactory);
     ParseDeclarationSpecifiers(DS);
     // Parse the declarator.
-    Declarator ParmDecl(DS, DeclaratorContext::Prototype);
+    Declarator ParmDecl(DS, ParsedAttributesView::none(),
+                        DeclaratorContext::Prototype);
     ParseDeclarator(ParmDecl);
     IdentifierInfo *ParmII = ParmDecl.getIdentifier();
     Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
@@ -1693,7 +1700,8 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
                          typeArg, Actions.getASTContext().getPrintingPolicy());
 
       // Form a declarator to turn this into a type.
-      Declarator D(DS, DeclaratorContext::TypeName);
+      Declarator D(DS, ParsedAttributesView::none(),
+                   DeclaratorContext::TypeName);
       TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
       if (fullTypeArg.isUsable()) {
         typeArgs.push_back(fullTypeArg.get());
@@ -2538,7 +2546,8 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
         if (Tok.isNot(tok::ellipsis)) {
           DeclSpec DS(AttrFactory);
           ParseDeclarationSpecifiers(DS);
-          Declarator ParmDecl(DS, DeclaratorContext::ObjCCatch);
+          Declarator ParmDecl(DS, ParsedAttributesView::none(),
+                              DeclaratorContext::ObjCCatch);
           ParseDeclarator(ParmDecl);
 
           // Inform the actions module about the declarator, so it
@@ -2954,7 +2963,8 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
   // We have a class message. Turn the simple-type-specifier or
   // typename-specifier we parsed into a type and parse the
   // remainder of the class message.
-  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
+                            DeclaratorContext::TypeName);
   TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
   if (Type.isInvalid())
     return true;

diff  --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 0385d5f1586e..e8d0c1528b52 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -639,7 +639,7 @@ TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
 
   // Parse the declarator.
   DeclaratorContext Context = DeclaratorContext::Prototype;
-  Declarator DeclaratorInfo(DS, Context);
+  Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);
   ParseDeclarator(DeclaratorInfo);
   Range = DeclaratorInfo.getSourceRange();
   if (DeclaratorInfo.getIdentifier() == nullptr) {

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index ce5541a966d1..f43e5b4c8922 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -105,15 +105,21 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
   // statement are 
diff erent from [[]] attributes that follow an __attribute__
   // at the start of the statement. Thus, we're not using MaybeParseAttributes
   // here because we don't want to allow arbitrary orderings.
-  ParsedAttributes Attrs(AttrFactory);
-  MaybeParseCXX11Attributes(Attrs, /*MightBeObjCMessageSend*/ true);
+  ParsedAttributes CXX11Attrs(AttrFactory);
+  MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
+  ParsedAttributes GNUAttrs(AttrFactory);
   if (getLangOpts().OpenCL)
-    MaybeParseGNUAttributes(Attrs);
+    MaybeParseGNUAttributes(GNUAttrs);
 
   StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
-      Stmts, StmtCtx, TrailingElseLoc, Attrs);
+      Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUAttrs);
   MaybeDestroyTemplateIds();
 
+  // Attributes that are left should all go on the statement, so concatenate the
+  // two lists.
+  ParsedAttributes Attrs(AttrFactory);
+  takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs);
+
   assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
          "attributes on empty statement");
 
@@ -158,7 +164,8 @@ class StatementFilterCCC final : public CorrectionCandidateCallback {
 
 StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     StmtVector &Stmts, ParsedStmtContext StmtCtx,
-    SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs) {
+    SourceLocation *TrailingElseLoc, ParsedAttributes &CXX11Attrs,
+    ParsedAttributes &GNUAttrs) {
   const char *SemiError = nullptr;
   StmtResult Res;
   SourceLocation GNUAttributeLoc;
@@ -184,6 +191,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
   case tok::identifier: {
     Token Next = NextToken();
     if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
+      // Both C++11 and GNU attributes preceding the label appertain to the
+      // label, so put them in a single list to pass on to
+      // ParseLabeledStatement().
+      ParsedAttributes Attrs(AttrFactory);
+      takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs);
+
       // identifier ':' statement
       return ParseLabeledStatement(Attrs, StmtCtx);
     }
@@ -213,25 +226,33 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
   }
 
   default: {
+    bool HaveAttrs = !CXX11Attrs.empty() || !GNUAttrs.empty();
+    auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
+    bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) &&
+                                llvm::all_of(GNUAttrs, IsStmtAttr);
     if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
          (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
              ParsedStmtContext()) &&
-        ((GNUAttributeLoc.isValid() &&
-          !(!Attrs.empty() &&
-            llvm::all_of(
-                Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) ||
+        ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
          isDeclarationStatement())) {
       SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
       DeclGroupPtrTy Decl;
       if (GNUAttributeLoc.isValid()) {
         DeclStart = GNUAttributeLoc;
-        Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs,
-                                &GNUAttributeLoc);
+        Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs,
+                                GNUAttrs, &GNUAttributeLoc);
       } else {
-        Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs);
+        Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs,
+                                GNUAttrs);
       }
-      if (Attrs.Range.getBegin().isValid())
-        DeclStart = Attrs.Range.getBegin();
+      if (CXX11Attrs.Range.getBegin().isValid()) {
+        // The caller must guarantee that the CXX11Attrs appear before the
+        // GNUAttrs, and we rely on that here.
+        assert(GNUAttrs.Range.getBegin().isInvalid() ||
+               GNUAttrs.Range.getBegin() > CXX11Attrs.Range.getBegin());
+        DeclStart = CXX11Attrs.Range.getBegin();
+      } else if (GNUAttrs.Range.getBegin().isValid())
+        DeclStart = GNUAttrs.Range.getBegin();
       return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
     }
 
@@ -245,7 +266,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
 
   case tok::kw___attribute: {
     GNUAttributeLoc = Tok.getLocation();
-    ParseGNUAttributes(Attrs);
+    ParseGNUAttributes(GNUAttrs);
     goto Retry;
   }
 
@@ -297,7 +318,11 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     break;
 
   case tok::kw_asm: {
-    ProhibitAttributes(Attrs);
+    for (const ParsedAttr &AL : CXX11Attrs)
+      Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
+    // Prevent these from being interpreted as statement attributes later on.
+    CXX11Attrs.clear();
+    ProhibitAttributes(GNUAttrs);
     bool msAsm = false;
     Res = ParseAsmStatement(msAsm);
     Res = Actions.ActOnFinishFullStmt(Res.get());
@@ -308,7 +333,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
 
   case tok::kw___if_exists:
   case tok::kw___if_not_exists:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     ParseMicrosoftIfExistsStatement(Stmts);
     // An __if_exists block is like a compound statement, but it doesn't create
     // a new scope.
@@ -318,7 +344,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     return ParseCXXTryBlock();
 
   case tok::kw___try:
-    ProhibitAttributes(Attrs); // TODO: is it correct?
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     return ParseSEHTryBlock();
 
   case tok::kw___leave:
@@ -327,55 +354,65 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     break;
 
   case tok::annot_pragma_vis:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaVisibility();
     return StmtEmpty();
 
   case tok::annot_pragma_pack:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaPack();
     return StmtEmpty();
 
   case tok::annot_pragma_msstruct:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaMSStruct();
     return StmtEmpty();
 
   case tok::annot_pragma_align:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaAlign();
     return StmtEmpty();
 
   case tok::annot_pragma_weak:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaWeak();
     return StmtEmpty();
 
   case tok::annot_pragma_weakalias:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaWeakAlias();
     return StmtEmpty();
 
   case tok::annot_pragma_redefine_extname:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaRedefineExtname();
     return StmtEmpty();
 
   case tok::annot_pragma_fp_contract:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
     ConsumeAnnotationToken();
     return StmtError();
 
   case tok::annot_pragma_fp:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
     ConsumeAnnotationToken();
     return StmtError();
 
   case tok::annot_pragma_fenv_access:
   case tok::annot_pragma_fenv_access_ms:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     Diag(Tok, diag::err_pragma_file_or_compound_scope)
         << (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS"
                                                     : "fenv_access");
@@ -383,53 +420,62 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     return StmtEmpty();
 
   case tok::annot_pragma_fenv_round:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC FENV_ROUND";
     ConsumeAnnotationToken();
     return StmtError();
 
   case tok::annot_pragma_float_control:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
     ConsumeAnnotationToken();
     return StmtError();
 
   case tok::annot_pragma_opencl_extension:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaOpenCLExtension();
     return StmtEmpty();
 
   case tok::annot_pragma_captured:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     return HandlePragmaCaptured();
 
   case tok::annot_pragma_openmp:
     // Prohibit attributes that are not OpenMP attributes, but only before
     // processing a #pragma omp clause.
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     LLVM_FALLTHROUGH;
   case tok::annot_attr_openmp:
     // Do not prohibit attributes if they were OpenMP attributes.
     return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
 
   case tok::annot_pragma_ms_pointers_to_members:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaMSPointersToMembers();
     return StmtEmpty();
 
   case tok::annot_pragma_ms_pragma:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaMSPragma();
     return StmtEmpty();
 
   case tok::annot_pragma_ms_vtordisp:
-    ProhibitAttributes(Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
     HandlePragmaMSVtorDisp();
     return StmtEmpty();
 
   case tok::annot_pragma_loop_hint:
-    ProhibitAttributes(Attrs);
-    return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs);
+    ProhibitAttributes(CXX11Attrs);
+    ProhibitAttributes(GNUAttrs);
+    return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs);
 
   case tok::annot_pragma_dump:
     HandlePragmaDump();
@@ -658,8 +704,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
       Attrs.takeAllFrom(TempAttrs);
     else {
       StmtVector Stmts;
-      SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
-                                                           nullptr, TempAttrs);
+      ParsedAttributes EmptyCXX11Attrs(AttrFactory);
+      SubStmt = ParseStatementOrDeclarationAfterAttributes(
+          Stmts, StmtCtx, nullptr, EmptyCXX11Attrs, TempAttrs);
       if (!TempAttrs.empty() && !SubStmt.isInvalid())
         SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get());
     }
@@ -1128,8 +1175,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
         ExtensionRAIIObject O(Diags);
 
         SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-        DeclGroupPtrTy Res =
-            ParseDeclaration(DeclaratorContext::Block, DeclEnd, attrs);
+        ParsedAttributes DeclSpecAttrs(AttrFactory);
+        DeclGroupPtrTy Res = ParseDeclaration(DeclaratorContext::Block, DeclEnd,
+                                              attrs, DeclSpecAttrs);
         R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
       } else {
         // Otherwise this was a unary __extension__ marker.
@@ -1975,8 +2023,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
       ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
 
       SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+      ParsedAttributes DeclSpecAttrs(AttrFactory);
       DG = ParseSimpleDeclaration(
-          DeclaratorContext::ForInit, DeclEnd, attrs, false,
+          DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false,
           MightBeForRangeStmt ? &ForRangeInfo : nullptr);
       FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
       if (ForRangeInfo.ParsedForRangeDecl()) {
@@ -2347,8 +2396,9 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
   // Get the next statement.
   MaybeParseCXX11Attributes(Attrs);
 
+  ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
   StmtResult S = ParseStatementOrDeclarationAfterAttributes(
-      Stmts, StmtCtx, TrailingElseLoc, Attrs);
+      Stmts, StmtCtx, TrailingElseLoc, Attrs, EmptyDeclSpecAttrs);
 
   Attrs.takeAllFrom(TempAttrs);
 
@@ -2584,12 +2634,11 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
     MaybeParseCXX11Attributes(Attributes);
 
     DeclSpec DS(AttrFactory);
-    DS.takeAttributesFrom(Attributes);
 
     if (ParseCXXTypeSpecifierSeq(DS))
       return StmtError();
 
-    Declarator ExDecl(DS, DeclaratorContext::CXXCatch);
+    Declarator ExDecl(DS, Attributes, DeclaratorContext::CXXCatch);
     ParseDeclarator(ExDecl);
     ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
   } else

diff  --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index e66329e3bfc7..97be8115989e 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -245,11 +245,10 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
   // Move the attributes from the prefix into the DS.
   if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
     ProhibitAttributes(prefixAttrs);
-  else
-    DS.takeAttributesFrom(prefixAttrs);
 
   // Parse the declarator.
-  ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
+  ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs,
+                                   (DeclaratorContext)Context);
   if (TemplateInfo.TemplateParams)
     DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
 
@@ -669,7 +668,8 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
     // probably meant to write the type of a NTTP.
     DeclSpec DS(getAttrFactory());
     DS.SetTypeSpecError();
-    Declarator D(DS, DeclaratorContext::TemplateParam);
+    Declarator D(DS, ParsedAttributesView::none(),
+                 DeclaratorContext::TemplateParam);
     D.SetIdentifier(nullptr, Tok.getLocation());
     D.setInvalidType(true);
     NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter(
@@ -993,7 +993,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
                              DeclSpecContext::DSC_template_param);
 
   // Parse this as a typename.
-  Declarator ParamDecl(DS, DeclaratorContext::TemplateParam);
+  Declarator ParamDecl(DS, ParsedAttributesView::none(),
+                       DeclaratorContext::TemplateParam);
   ParseDeclarator(ParamDecl);
   if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
     Diag(Tok.getLocation(), diag::err_expected_template_parameter);

diff  --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 7ffaf057623f..7fad3b2388ce 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -740,6 +740,9 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
 
 /// ParseExternalDeclaration:
 ///
+/// The `Attrs` that are passed in are C++11 attributes and appertain to the
+/// declaration.
+///
 ///       external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
 ///         function-definition
 ///         declaration
@@ -929,7 +932,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
     // A function definition cannot start with any of these keywords.
     {
       SourceLocation DeclEnd;
-      return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
+      ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+      return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+                              EmptyDeclSpecAttrs);
     }
 
   case tok::kw_static:
@@ -939,7 +944,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
       Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
         << 0;
       SourceLocation DeclEnd;
-      return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
+      ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+      return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+                              EmptyDeclSpecAttrs);
     }
     goto dont_know;
 
@@ -950,7 +957,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
       // Inline namespaces. Allowed as an extension even in C++03.
       if (NextKind == tok::kw_namespace) {
         SourceLocation DeclEnd;
-        return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
+        ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+        return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+                                EmptyDeclSpecAttrs);
       }
 
       // Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -959,7 +968,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
         Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
           << 1;
         SourceLocation DeclEnd;
-        return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
+        ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+        return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+                                EmptyDeclSpecAttrs);
       }
     }
     goto dont_know;
@@ -1112,8 +1123,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
 
-  DS.takeAttributesFrom(Attrs);
-
   // ObjC2 allows prefix attributes on class interfaces and protocols.
   // FIXME: This still needs better diagnostics. We should only accept
   // attributes here, no types, etc.
@@ -1128,6 +1137,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
     }
 
     DS.abort();
+    DS.takeAttributesFrom(Attrs);
 
     const char *PrevSpec = nullptr;
     unsigned DiagID;
@@ -1151,11 +1161,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
   if (getLangOpts().CPlusPlus && isTokenStringLiteral() &&
       DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
       DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
+    ProhibitAttributes(Attrs);
     Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File);
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
 
-  return ParseDeclGroup(DS, DeclaratorContext::File);
+  return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
 }
 
 Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
@@ -1473,7 +1484,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
     }
 
     // Parse the first declarator attached to this declspec.
-    Declarator ParmDeclarator(DS, DeclaratorContext::KNRTypeList);
+    Declarator ParmDeclarator(DS, ParsedAttributesView::none(),
+                              DeclaratorContext::KNRTypeList);
     ParseDeclarator(ParmDeclarator);
 
     // Handle the full declarator list.

diff  --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index c2742c7db0dc..4b9a694270c5 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -212,6 +212,39 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const {
   return getInfo().IsSupportedByPragmaAttribute;
 }
 
+bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
+  assert(isStandardAttributeSyntax());
+
+  // We have historically allowed some type attributes with standard attribute
+  // syntax to slide to the decl-specifier-seq, so we have to keep supporting
+  // it. This property is consciously not defined as a flag in Attr.td because
+  // we don't want new attributes to specify it.
+  //
+  // Note: No new entries should be added to this list. Entries should be
+  // removed from this list after a suitable deprecation period, provided that
+  // there are no compatibility considerations with other compilers. If
+  // possible, we would like this list to go away entirely.
+  switch (getParsedKind()) {
+  case AT_AddressSpace:
+  case AT_OpenCLPrivateAddressSpace:
+  case AT_OpenCLGlobalAddressSpace:
+  case AT_OpenCLGlobalDeviceAddressSpace:
+  case AT_OpenCLGlobalHostAddressSpace:
+  case AT_OpenCLLocalAddressSpace:
+  case AT_OpenCLConstantAddressSpace:
+  case AT_OpenCLGenericAddressSpace:
+  case AT_NeonPolyVectorType:
+  case AT_NeonVectorType:
+  case AT_ArmMveStrictPolymorphism:
+  case AT_BTFTypeTag:
+  case AT_ObjCGC:
+  case AT_MatrixType:
+    return true;
+  default:
+    return false;
+  }
+}
+
 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
 
 unsigned ParsedAttr::getSemanticSpelling() const {
@@ -265,3 +298,20 @@ bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
                                    diag::err_attribute_too_many_arguments,
                                    std::greater<unsigned>());
 }
+
+void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
+                                    ParsedAttributes &Second,
+                                    ParsedAttributes &Result) {
+  // Note that takeAllFrom() puts the attributes at the beginning of the list,
+  // so to obtain the correct ordering, we add `Second`, then `First`.
+  Result.takeAllFrom(Second);
+  Result.takeAllFrom(First);
+  if (First.Range.getBegin().isValid())
+    Result.Range.setBegin(First.Range.getBegin());
+  else
+    Result.Range.setBegin(Second.Range.getBegin());
+  if (Second.Range.getEnd().isValid())
+    Result.Range.setEnd(Second.Range.getEnd());
+  else
+    Result.Range.setEnd(First.Range.getEnd());
+}

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cfba17d6e23d..d8f2f332857f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5461,7 +5461,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
     Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange();
 
   // Mock up a declarator.
-  Declarator Dc(DS, DeclaratorContext::Member);
+  Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::Member);
   TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
   assert(TInfo && "couldn't build declarator info for anonymous struct/union");
 
@@ -5558,7 +5558,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
   assert(Record && "expected a record!");
 
   // Mock up a declarator.
-  Declarator Dc(DS, DeclaratorContext::TypeName);
+  Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
   TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
   assert(TInfo && "couldn't build declarator info for anonymous struct");
 
@@ -7000,7 +7000,8 @@ static bool hasParsedAttr(Scope *S, const Declarator &PD,
   }
 
   // Finally, check attributes on the decl itself.
-  return PD.getAttributes().hasAttribute(Kind);
+  return PD.getAttributes().hasAttribute(Kind) ||
+         PD.getDeclarationAttributes().hasAttribute(Kind);
 }
 
 /// Adjust the \c DeclContext for a function or variable that might be a
@@ -13332,7 +13333,7 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
   DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID,
                      getPrintingPolicy());
 
-  Declarator D(DS, DeclaratorContext::ForInit);
+  Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::ForInit);
   D.SetIdentifier(Ident, IdentLoc);
   D.takeAttributes(Attrs);
 
@@ -14330,7 +14331,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
         // Use the identifier location for the type source range.
         DS.SetRangeStart(FTI.Params[i].IdentLoc);
         DS.SetRangeEnd(FTI.Params[i].IdentLoc);
-        Declarator ParamD(DS, DeclaratorContext::KNRTypeList);
+        Declarator ParamD(DS, ParsedAttributesView::none(),
+                          DeclaratorContext::KNRTypeList);
         ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc);
         FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD);
       }
@@ -15352,7 +15354,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
   (void)Error; // Silence warning.
   assert(!Error && "Error setting up implicit decl!");
   SourceLocation NoLoc;
-  Declarator D(DS, DeclaratorContext::Block);
+  Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::Block);
   D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
                                              /*IsAmbiguous=*/false,
                                              /*LParenLoc=*/NoLoc,

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 2e62cc0c242a..af8dc853eba6 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -8316,15 +8316,21 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
 /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
 /// the attribute applies to decls.  If the attribute is a type attribute, just
 /// silently ignore it if a GNU attribute.
-static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
-                                 const ParsedAttr &AL,
-                                 bool IncludeCXX11Attributes) {
+static void
+ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
+                     const Sema::ProcessDeclAttributeOptions &Options) {
   if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
     return;
 
   // Ignore C++11 attributes on declarator chunks: they appertain to the type
   // instead.
-  if (AL.isCXX11Attribute() && !IncludeCXX11Attributes)
+  // FIXME: We currently check the attribute syntax directly instead of using
+  // isCXX11Attribute(), which currently erroneously classifies the C11
+  // `_Alignas` attribute as a C++11 attribute. `_Alignas` can appear on the
+  // `DeclSpec`, so we need to let it through here to make sure it is processed
+  // appropriately. Once the behavior of isCXX11Attribute() is fixed, we can
+  // go back to using that here.
+  if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes)
     return;
 
   // Unknown attributes are automatically warned on. Target-specific attributes
@@ -8357,14 +8363,76 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
     if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled)
       break;
     if (!AL.isStmtAttr()) {
-      // Type attributes are handled elsewhere; silently move on.
       assert(AL.isTypeAttr() && "Non-type attribute not handled");
-      break;
+    }
+    if (AL.isTypeAttr()) {
+      if (Options.IgnoreTypeAttributes)
+        break;
+      if (!AL.isStandardAttributeSyntax()) {
+        // Non-[[]] type attributes are handled in processTypeAttrs(); silently
+        // move on.
+        break;
+      }
+
+      // According to the C and C++ standards, we should never see a
+      // [[]] type attribute on a declaration. However, we have in the past
+      // allowed some type attributes to "slide" to the `DeclSpec`, so we need
+      // to continue to support this legacy behavior. We only do this, however,
+      // if
+      // - we actually have a `DeclSpec`, i.e. if we're looking at a
+      //   `DeclaratorDecl`, or
+      // - we are looking at an alias-declaration, where historically we have
+      //   allowed type attributes after the identifier to slide to the type.
+      if (AL.slidesFromDeclToDeclSpecLegacyBehavior() &&
+          isa<DeclaratorDecl, TypeAliasDecl>(D)) {
+        // Suggest moving the attribute to the type instead, but only for our
+        // own vendor attributes; moving other vendors' attributes might hurt
+        // portability.
+        if (AL.isClangScope()) {
+          S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+              << AL << D->getLocation();
+        }
+
+        // Allow this type attribute to be handled in processTypeAttrs();
+        // silently move on.
+        break;
+      }
+
+      if (AL.getKind() == ParsedAttr::AT_Regparm) {
+        // `regparm` is a special case: It's a type attribute but we still want
+        // to treat it as if it had been written on the declaration because that
+        // way we'll be able to handle it directly in `processTypeAttr()`.
+        // If we treated `regparm` it as if it had been written on the
+        // `DeclSpec`, the logic in `distributeFunctionTypeAttrFromDeclSepc()`
+        // would try to move it to the declarator, but that doesn't work: We
+        // can't remove the attribute from the list of declaration attributes
+        // because it might be needed by other declarators in the same
+        // declaration.
+        break;
+      }
+
+      if (AL.getKind() == ParsedAttr::AT_VectorSize) {
+        // `vector_size` is a special case: It's a type attribute semantically,
+        // but GCC expects the [[]] syntax to be written on the declaration (and
+        // warns that the attribute has no effect if it is placed on the
+        // decl-specifier-seq).
+        // Silently move on and allow the attribute to be handled in
+        // processTypeAttr().
+        break;
+      }
+
+      if (AL.getKind() == ParsedAttr::AT_NoDeref) {
+        // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
+        // See https://github.com/llvm/llvm-project/issues/55790 for details.
+        // We allow processTypeAttrs() to emit a warning and silently move on.
+        break;
+      }
     }
     // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
     // statement attribute is not written on a declaration, but this code is
-    // needed for attributes in Attr.td that do not list any subjects.
-    S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
+    // 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();
     break;
   case ParsedAttr::AT_Interrupt:
@@ -9010,14 +9078,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
 
 /// ProcessDeclAttributeList - Apply all the decl attributes in the specified
 /// attribute list to the specified decl, ignoring any type attributes.
-void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
-                                    const ParsedAttributesView &AttrList,
-                                    bool IncludeCXX11Attributes) {
+void Sema::ProcessDeclAttributeList(
+    Scope *S, Decl *D, const ParsedAttributesView &AttrList,
+    const ProcessDeclAttributeOptions &Options) {
   if (AttrList.empty())
     return;
 
   for (const ParsedAttr &AL : AttrList)
-    ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes);
+    ProcessDeclAttribute(*this, S, D, AL, Options);
 
   // FIXME: We should be able to handle these cases in TableGen.
   // GCC accepts
@@ -9105,7 +9173,8 @@ bool Sema::ProcessAccessDeclAttributeList(
     AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
   for (const ParsedAttr &AL : AttrList) {
     if (AL.getKind() == ParsedAttr::AT_Annotate) {
-      ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
+      ProcessDeclAttribute(*this, nullptr, ASDecl, AL,
+                           ProcessDeclAttributeOptions());
     } else {
       Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
       return true;
@@ -9138,6 +9207,7 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
 /// used to build a declaration, complain about any decl attributes
 /// which might be lying around on it.
 void Sema::checkUnusedDeclAttributes(Declarator &D) {
+  ::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
   ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
   ::checkUnusedDeclAttributes(*this, D.getAttributes());
   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
@@ -9246,17 +9316,43 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
 /// it, apply them to D.  This is a bit tricky because PD can have attributes
 /// specified in many 
diff erent places, and we need to find and apply them all.
 void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
+  // Ordering of attributes can be important, so we take care to process
+  // attributes in the order in which they appeared in the source code.
+
+  // First, process attributes that appeared on the declaration itself (but
+  // only if they don't have the legacy behavior of "sliding" to the DeclSepc).
+  ParsedAttributesView NonSlidingAttrs;
+  for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
+    if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+      // Skip processing the attribute, but do check if it appertains to the
+      // declaration. This is needed for the `MatrixType` attribute, which,
+      // despite being a type attribute, defines a `SubjectList` that only
+      // allows it to be used on typedef declarations.
+      AL.diagnoseAppertainsTo(*this, D);
+    } else {
+      NonSlidingAttrs.addAtEnd(&AL);
+    }
+  }
+  ProcessDeclAttributeList(S, D, NonSlidingAttrs);
+
   // Apply decl attributes from the DeclSpec if present.
-  if (!PD.getDeclSpec().getAttributes().empty())
-    ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes());
+  if (!PD.getDeclSpec().getAttributes().empty()) {
+    ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes(),
+                             ProcessDeclAttributeOptions()
+                                 .WithIncludeCXX11Attributes(false)
+                                 .WithIgnoreTypeAttributes(true));
+  }
 
   // Walk the declarator structure, applying decl attributes that were in a type
   // position to the decl itself.  This handles cases like:
   //   int *__attr__(x)** D;
   // when X is a decl attribute.
-  for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
+  for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) {
     ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(),
-                             /*IncludeCXX11Attributes=*/false);
+                             ProcessDeclAttributeOptions()
+                                 .WithIncludeCXX11Attributes(false)
+                                 .WithIgnoreTypeAttributes(true));
+  }
 
   // Finally, apply any attributes on the decl itself.
   ProcessDeclAttributeList(S, D, PD.getAttributes());

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 214332e53c0f..6c8704cd0b78 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16860,7 +16860,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
   // Try to convert the decl specifier to a type.  This works for
   // friend templates because ActOnTag never produces a ClassTemplateDecl
   // for a TUK_Friend.
-  Declarator TheDeclarator(DS, DeclaratorContext::Member);
+  Declarator TheDeclarator(DS, ParsedAttributesView::none(),
+                           DeclaratorContext::Member);
   TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S);
   QualType T = TSI->getType();
   if (TheDeclarator.isInvalidType())

diff  --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 5c3903e652a5..aa0034e616f2 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -1588,7 +1588,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
     DS.SetRangeEnd(loc);
 
     // Form the declarator.
-    Declarator D(DS, DeclaratorContext::TypeName);
+    Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
 
     // If we have a typedef of an Objective-C class type that is missing a '*',
     // add the '*'.

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index e487c892e569..0c84673b3479 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -629,15 +629,6 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
                                                    QualType &declSpecType) {
   state.saveDeclSpecAttrs();
 
-  // C++11 attributes before the decl specifiers actually appertain to
-  // the declarators. Move them straight there. We don't support the
-  // 'put them wherever you like' semantics we allow for GNU attributes.
-  if (attr.isStandardAttributeSyntax()) {
-    moveAttrFromListToList(attr, state.getCurrentAttributes(),
-                           state.getDeclarator().getAttributes());
-    return;
-  }
-
   // Try to distribute to the innermost.
   if (distributeFunctionTypeAttrToInnermost(
           state, attr, state.getCurrentAttributes(), declSpecType))
@@ -648,8 +639,10 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
   state.addIgnoredTypeAttr(attr);
 }
 
-/// A function type attribute was written on the declarator.  Try to
-/// apply it somewhere.
+/// A function type attribute was written on the declarator or declaration.
+/// Try to apply it somewhere.
+/// `Attrs` is the attribute list containing the declaration (either of the
+/// declarator or the declaration).
 static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
                                                      ParsedAttr &attr,
                                                      QualType &declSpecType) {
@@ -666,7 +659,7 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
   state.addIgnoredTypeAttr(attr);
 }
 
-/// Given that there are attributes written on the declarator
+/// Given that there are attributes written on the declarator or declaration
 /// itself, try to distribute any type attributes to the appropriate
 /// declarator chunk.
 ///
@@ -675,11 +668,11 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
 ///   int (f ATTR)();
 /// but not necessarily this:
 ///   int f() ATTR;
+///
+/// `Attrs` is the attribute list containing the declaration (either of the
+/// declarator or the declaration).
 static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
                                               QualType &declSpecType) {
-  // Collect all the type attributes from the declarator itself.
-  assert(!state.getDeclarator().getAttributes().empty() &&
-         "declarator has no attrs!");
   // The called functions in this loop actually remove things from the current
   // list, so iterating over the existing list isn't possible.  Instead, make a
   // non-owning copy and iterate over that.
@@ -1792,8 +1785,42 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
   // list of type attributes to be temporarily saved while the type
   // attributes are pushed around.
   // pipe attributes will be handled later ( at GetFullTypeForDeclarator )
-  if (!DS.isTypeSpecPipe())
+  if (!DS.isTypeSpecPipe()) {
+    // We also apply declaration attributes that "slide" to the decl spec.
+    // Ordering can be important for attributes. The decalaration attributes
+    // come syntactically before the decl spec attributes, so we process them
+    // in that order.
+    ParsedAttributesView SlidingAttrs;
+    for (ParsedAttr &AL : declarator.getDeclarationAttributes()) {
+      if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+        SlidingAttrs.addAtEnd(&AL);
+
+        // For standard syntax attributes, which would normally appertain to the
+        // declaration here, suggest moving them to the type instead. But only
+        // do this for our own vendor attributes; moving other vendors'
+        // attributes might hurt portability.
+        // There's one special case that we need to deal with here: The
+        // `MatrixType` attribute may only be used in a typedef declaration. If
+        // it's being used anywhere else, don't output the warning as
+        // ProcessDeclAttributes() will output an error anyway.
+        if (AL.isStandardAttributeSyntax() && AL.isClangScope() &&
+            !(AL.getKind() == ParsedAttr::AT_MatrixType &&
+              DS.getStorageClassSpec() != DeclSpec::SCS_typedef)) {
+          S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+              << AL;
+        }
+      }
+    }
+    // During this call to processTypeAttrs(),
+    // TypeProcessingState::getCurrentAttributes() will erroneously return a
+    // reference to the DeclSpec attributes, rather than the declaration
+    // attributes. However, this doesn't matter, as getCurrentAttributes()
+    // is only called when distributing attributes from one attribute list
+    // to another. Declaration attributes are always C++11 attributes, and these
+    // are never distributed.
+    processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs);
     processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes());
+  }
 
   // Apply const/volatile/restrict qualifiers to T.
   if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -3400,8 +3427,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     break;
   }
 
-  if (!D.getAttributes().empty())
-    distributeTypeAttrsFromDeclarator(state, T);
+  // Note: We don't need to distribute declaration attributes (i.e.
+  // D.getDeclarationAttributes()) because those are always C++11 attributes,
+  // and those don't get distributed.
+  distributeTypeAttrsFromDeclarator(state, T);
 
   // Find the deduced type in this type. Look in the trailing return type if we
   // have one, otherwise in the DeclSpec type.
@@ -4702,7 +4731,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                    AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained);
           };
           if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) {
-            if (hasCFReturnsAttr(D.getAttributes()) ||
+            if (hasCFReturnsAttr(D.getDeclarationAttributes()) ||
+                hasCFReturnsAttr(D.getAttributes()) ||
                 hasCFReturnsAttr(InnermostChunk->getAttrs()) ||
                 hasCFReturnsAttr(D.getDeclSpec().getAttributes())) {
               inferNullability = NullabilityKind::Nullable;
@@ -5273,7 +5303,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
         // function is marked with the "overloadable" attribute. Scan
         // for this attribute now.
         if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus)
-          if (!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
+          if (!D.getDeclarationAttributes().hasAttribute(
+                  ParsedAttr::AT_Overloadable) &&
+              !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
               !D.getDeclSpec().getAttributes().hasAttribute(
                   ParsedAttr::AT_Overloadable))
             S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
@@ -5689,7 +5721,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     }
   }
 
-  // Apply any undistributed attributes from the declarator.
+  // Apply any undistributed attributes from the declaration or declarator.
+  ParsedAttributesView NonSlidingAttrs;
+  for (ParsedAttr &AL : D.getDeclarationAttributes()) {
+    if (!AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+      NonSlidingAttrs.addAtEnd(&AL);
+    }
+  }
+  processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs);
   processTypeAttrs(state, T, TAL_DeclName, D.getAttributes());
 
   // Diagnose any ignored type attributes.
@@ -8234,12 +8273,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
           if (!IsTypeAttr)
             continue;
         }
-      } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr) &&
-                 attr.getKind() != ParsedAttr::AT_AnnotateType) {
+      } else if (TAL != TAL_DeclSpec && TAL != TAL_DeclChunk &&
+                 !attr.isTypeAttr()) {
         // Otherwise, only consider type processing for a C++11 attribute if
-        // it's actually been applied to a type.
-        // We also allow C++11 address_space and annotate_type and
-        // OpenCL language address space attributes to pass through.
+        // - it has actually been applied to a type (decl-specifier-seq or
+        //   declarator chunk), or
+        // - it is a type attribute, irrespective of where it was applied (so
+        //   that we can support the legacy behavior of some type attributes
+        //   that can be applied to the declaration name).
         continue;
       }
     }
@@ -8257,10 +8298,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
       break;
 
     case ParsedAttr::UnknownAttribute:
-      if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk)
+      if (attr.isStandardAttributeSyntax()) {
         state.getSema().Diag(attr.getLoc(),
                              diag::warn_unknown_attribute_ignored)
             << attr << attr.getRange();
+        // Mark the attribute as invalid so we don't emit the same diagnostic
+        // multiple times.
+        attr.setInvalid();
+      }
       break;
 
     case ParsedAttr::IgnoredAttribute:
@@ -8329,6 +8374,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
       break;
 
     case ParsedAttr::AT_NoDeref: {
+      // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
+      // See https://github.com/llvm/llvm-project/issues/55790 for details.
+      // For the time being, we simply emit a warning that the attribute is
+      // ignored.
+      if (attr.isStandardAttributeSyntax()) {
+        state.getSema().Diag(attr.getLoc(), diag::warn_attribute_ignored)
+            << attr;
+        break;
+      }
       ASTContext &Ctx = state.getSema().Context;
       type = state.getAttributedType(createSimpleAttr<NoDerefAttr>(Ctx, attr),
                                      type, type);
@@ -8406,6 +8460,16 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
     FUNCTION_TYPE_ATTRS_CASELIST:
       attr.setUsedAsTypeAttr();
 
+      // 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 (!handleFunctionTypeAttr(state, attr, type)) {
+          diagnoseBadTypeAttribute(state.getSema(), attr, type);
+          attr.setInvalid();
+        }
+        break;
+      }
+
       // Never process function type attributes as part of the
       // declaration-specifiers.
       if (TAL == TAL_DeclSpec)

diff  --git a/clang/test/AST/language_address_space_attribute.cpp b/clang/test/AST/language_address_space_attribute.cpp
index 93a23304d9a6..fcc293ab5e70 100644
--- a/clang/test/AST/language_address_space_attribute.cpp
+++ b/clang/test/AST/language_address_space_attribute.cpp
@@ -14,42 +14,63 @@ void langas() {
   // CHECK: VarDecl {{.*}} x_global '__global int *'
   __attribute__((opencl_global)) int *x_global;
 
+  // CHECK: VarDecl {{.*}} y_global '__global int *'
+  int [[clang::opencl_global]] *y_global;
+
   // CHECK: VarDecl {{.*}} z_global '__global int *'
   [[clang::opencl_global]] int *z_global;
 
   // CHECK: VarDecl {{.*}} x_global_device '__global_device int *'
   __attribute__((opencl_global_device)) int *x_global_device;
 
+  // CHECK: VarDecl {{.*}} y_global_device '__global_device int *'
+  int [[clang::opencl_global_device]] *y_global_device;
+
   // CHECK: VarDecl {{.*}} z_global_device '__global_device int *'
   [[clang::opencl_global_device]] int *z_global_device;
 
   // CHECK: VarDecl {{.*}} x_global_host '__global_host int *'
   __attribute__((opencl_global_host)) int *x_global_host;
 
+  // CHECK: VarDecl {{.*}} y_global_host '__global_host int *'
+  int [[clang::opencl_global_host]] *y_global_host;
+
   // CHECK: VarDecl {{.*}} z_global_host '__global_host int *'
   [[clang::opencl_global_host]] int *z_global_host;
 
   // CHECK: VarDecl {{.*}} x_local '__local int *'
   __attribute__((opencl_local)) int *x_local;
 
+  // CHECK: VarDecl {{.*}} y_local '__local int *'
+  int [[clang::opencl_local]] *y_local;
+
   // CHECK: VarDecl {{.*}} z_local '__local int *'
   [[clang::opencl_local]] int *z_local;
 
   // CHECK: VarDecl {{.*}} x_constant '__constant int *'
   __attribute__((opencl_constant)) int *x_constant;
 
+  // CHECK: VarDecl {{.*}} y_constant '__constant int *'
+  int [[clang::opencl_constant]] *y_constant;
+
   // CHECK: VarDecl {{.*}} z_constant '__constant int *'
   [[clang::opencl_constant]] int *z_constant;
 
   // CHECK: VarDecl {{.*}} x_private '__private int *'
   __attribute__((opencl_private)) int *x_private;
 
+  // CHECK: VarDecl {{.*}} y_private '__private int *'
+  int [[clang::opencl_private]] *y_private;
+
   // CHECK: VarDecl {{.*}} z_private '__private int *'
   [[clang::opencl_private]] int *z_private;
 
   // CHECK: VarDecl {{.*}} x_generic '__generic int *'
   __attribute__((opencl_generic)) int *x_generic;
 
+  // CHECK: VarDecl {{.*}} y_generic '__generic int *'
+  int [[clang::opencl_generic]] *y_generic;
+
   // CHECK: VarDecl {{.*}} z_generic '__generic int *'
   [[clang::opencl_generic]] int *z_generic;
 }

diff  --git a/clang/test/CodeGen/attr-btf_type_tag-func.c b/clang/test/CodeGen/attr-btf_type_tag-func.c
index 016e1064eb86..a4a22f36c1bb 100644
--- a/clang/test/CodeGen/attr-btf_type_tag-func.c
+++ b/clang/test/CodeGen/attr-btf_type_tag-func.c
@@ -1,9 +1,17 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -fdouble-square-bracket-attributes -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
 
+#if DOUBLE_BRACKET_ATTRS
+#define __tag1 [[clang::btf_type_tag("tag1")]]
+#define __tag2 [[clang::btf_type_tag("tag2")]]
+#define __tag3 [[clang::btf_type_tag("tag3")]]
+#define __tag4 [[clang::btf_type_tag("tag4")]]
+#else
 #define __tag1 __attribute__((btf_type_tag("tag1")))
 #define __tag2 __attribute__((btf_type_tag("tag2")))
 #define __tag3 __attribute__((btf_type_tag("tag3")))
 #define __tag4 __attribute__((btf_type_tag("tag4")))
+#endif
 
 int __tag1 * __tag2 *foo(int __tag1 * __tag2 *arg) { return arg; }
 

diff  --git a/clang/test/CodeGen/attr-btf_type_tag-var.c b/clang/test/CodeGen/attr-btf_type_tag-var.c
index 3493d8f6d366..0bb0a6172810 100644
--- a/clang/test/CodeGen/attr-btf_type_tag-var.c
+++ b/clang/test/CodeGen/attr-btf_type_tag-var.c
@@ -1,5 +1,16 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -fdouble-square-bracket-attributes -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
 
+#if DOUBLE_BRACKET_ATTRS
+#define __tag1 [[clang::btf_type_tag("tag1")]]
+#define __tag2 [[clang::btf_type_tag("tag2")]]
+#define __tag3 [[clang::btf_type_tag("tag3")]]
+#define __tag4 [[clang::btf_type_tag("tag4")]]
+#define __tag5 [[clang::btf_type_tag("tag5")]]
+#define __tag6 [[clang::btf_type_tag("tag6")]]
+
+const volatile int __tag1 __tag2 * __tag3 __tag4 const volatile  * __tag5 __tag6 const volatile * g;
+#else
 #define __tag1 __attribute__((btf_type_tag("tag1")))
 #define __tag2 __attribute__((btf_type_tag("tag2")))
 #define __tag3 __attribute__((btf_type_tag("tag3")))
@@ -8,6 +19,7 @@
 #define __tag6 __attribute__((btf_type_tag("tag6")))
 
 const int __tag1 __tag2 volatile * const __tag3  __tag4  volatile * __tag5  __tag6 const volatile * g;
+#endif
 
 // CHECK:  distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L6:[0-9]+]]
 // CHECK:  ![[L6]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L7:[0-9]+]], size: [[#]], annotations: ![[L22:[0-9]+]]

diff  --git a/clang/test/Frontend/noderef.c b/clang/test/Frontend/noderef.c
index 6b9a14316817..daf2d6006b2d 100644
--- a/clang/test/Frontend/noderef.c
+++ b/clang/test/Frontend/noderef.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -Wno-unused-value -fdouble-square-bracket-attributes -verify %s
 
 #define NODEREF __attribute__((noderef))
 
@@ -221,3 +221,24 @@ int test(void) {
   do {} while (*p);   // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
   return *p;          // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
 }
+
+// FIXME: Currently, [[]] syntax does not work for the `noderef` atribute.
+// For the time being, test that we consistently diagnose the attribute as
+// ignored.
+// For details see https://github.com/llvm/llvm-project/issues/55790
+void test_standard_syntax() {
+  [[clang::noderef]] int i; // expected-warning {{'noderef' attribute ignored}}
+
+  [[clang::noderef]] int *p1; // expected-warning {{'noderef' attribute ignored}}
+  *p1;
+
+  int *p2 [[clang::noderef]]; // expected-warning {{'noderef' attribute ignored}}
+  *p2;
+
+  int * [[clang::noderef]] p3; // expected-warning {{'noderef' attribute ignored}}
+  *p3;
+
+  typedef int* IntPtr;
+  [[clang::noderef]] IntPtr p4; // expected-warning {{'noderef' attribute ignored}}
+  *p4;
+}

diff  --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp
index c625bf3d6bef..01e59aa1945a 100644
--- a/clang/test/Parser/MicrosoftExtensions.cpp
+++ b/clang/test/Parser/MicrosoftExtensions.cpp
@@ -57,6 +57,14 @@ struct __declspec(uuid("000000A0-0000-0000-C000-000000000046"))
 struct_with_uuid { };
 struct struct_without_uuid { };
 
+struct base {
+  int a;
+};
+struct derived : base {
+  // Can't apply a UUID to a using declaration.
+  [uuid("000000A0-0000-0000-C000-00000000004A")] using base::a; // expected-error {{expected member name}}
+};
+
 struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
 struct_with_uuid2;
 

diff  --git a/clang/test/Parser/asm.c b/clang/test/Parser/asm.c
index 37b3ba3f4656..480acb7b6ffd 100644
--- a/clang/test/Parser/asm.c
+++ b/clang/test/Parser/asm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
 
 #if !__has_extension(gnu_asm)
 #error Extension 'gnu_asm' should be available by default
@@ -12,6 +12,9 @@ void f1(void) {
 void f2(void) {
   asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
   asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}} 
+
+  [[]] asm("");
+  [[gnu::deprecated]] asm(""); // expected-warning {{'deprecated' attribute ignored}}
 }
 
 void a(void) __asm__(""); // expected-error {{cannot use an empty string literal in 'asm'}}

diff  --git a/clang/test/Parser/asm.cpp b/clang/test/Parser/asm.cpp
index 9f64dfea476e..de156877ec47 100644
--- a/clang/test/Parser/asm.cpp
+++ b/clang/test/Parser/asm.cpp
@@ -7,3 +7,8 @@ int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in
 int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
 int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
 int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
+
+void f() {
+  [[]] asm("");
+  [[gnu::deprecated]] asm(""); // expected-warning {{'deprecated' attribute ignored}}
+}

diff  --git a/clang/test/Parser/attributes.c b/clang/test/Parser/attributes.c
index 9f017c6958c2..fe22c7e98a53 100644
--- a/clang/test/Parser/attributes.c
+++ b/clang/test/Parser/attributes.c
@@ -113,3 +113,10 @@ __attribute__((,,,const)) int PR38352_1(void);
 __attribute__((const,,,)) int PR38352_2(void);
 __attribute__((const,,,const)) int PR38352_3(void);
 __attribute__((,,,const,,,const,,,)) int PR38352_4(void);
+
+// Test that we allow attributes on free-standing decl-specifier-seqs.
+// GCC appears to allow this.
+__attribute__(()) struct t;
+void f5() {
+  __attribute__(()) struct t;
+}

diff  --git a/clang/test/Parser/c2x-attributes.c b/clang/test/Parser/c2x-attributes.c
index e1265f73a476..f8ed1eda1488 100644
--- a/clang/test/Parser/c2x-attributes.c
+++ b/clang/test/Parser/c2x-attributes.c
@@ -34,6 +34,8 @@ struct [[]] S1 {
   int [[]] : 0; // OK, attribute applies to the type.
   int p, [[]] : 0; // expected-error {{an attribute list cannot appear here}}
   int q, [[]] r; // expected-error {{an attribute list cannot appear here}}
+  [[]] int; // expected-error {{an attribute list cannot appear here}} \
+            // expected-warning {{declaration does not declare anything}}
 };
 
 [[]] struct S2 { int a; }; // expected-error {{misplaced attributes}}

diff  --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index 25113d35b854..3cb4e180e5f5 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -126,6 +126,7 @@ class foo {
   void const_after_attr () [[]] const; // expected-error {{expected ';'}}
 };
 extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
+[[]] extern "C++" { } // expected-error {{an attribute list cannot appear here}}
 [[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
 [[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}} expected-note {{declared here}}
 [[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
@@ -421,3 +422,26 @@ class FriendClassesWithAttributes {
 // prefered "protected" vendor namespace. We support __clang__ only for
 // people expecting it to behave the same as __gnu__.
 [[__clang__::annotate("test")]] void annotate3();  // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}}
+
+// Check ordering: C++11 attributes must appear before GNU attributes.
+class Ordering {
+  void f1(
+    int ([[]] __attribute__(()) int n)
+  ) {
+  }
+
+  void f2(
+      int (*)([[]] __attribute__(()) int n)
+  ) {
+  }
+
+  void f3(
+    int (__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}}
+  ) {
+  }
+
+  void f4(
+      int (*)(__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}}
+  ) {
+  }
+};

diff  --git a/clang/test/Sema/annotate-type.c b/clang/test/Sema/annotate-type.c
index bbf26dd1793b..266e13885389 100644
--- a/clang/test/Sema/annotate-type.c
+++ b/clang/test/Sema/annotate-type.c
@@ -17,11 +17,8 @@ void foo(float *[[clang::annotate_type("foo")]] a) {
   int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
 
   // Various error cases
-  // FIXME: We would want to prohibit the attribute on the following two lines.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("bar")]] int *z1;
-  int *z2 [[clang::annotate_type("bar")]];
+  [[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
   int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
   int *[[clang::annotate_type()]] z4; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
@@ -33,15 +30,13 @@ void foo(float *[[clang::annotate_type("foo")]] a) {
 }
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit 
diff erent code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-[[clang::annotate_type("bar")]] int *global;
-void annotated_function([[clang::annotate_type("bar")]] int);
-void g([[clang::annotate_type("bar")]] int);
-struct [[clang::annotate_type("foo")]] S;
-struct [[clang::annotate_type("foo")]] S{
-  [[clang::annotate_type("foo")]] int member;
-  [[clang::annotate_type("foo")]] union {
+[[clang::annotate_type("bar")]] int *global; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+[[clang::annotate_type("bar")]] void annotated_function(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+void g([[clang::annotate_type("bar")]] int); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  [[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  [[clang::annotate_type("foo")]] union { // expected-error {{an attribute list cannot appear here}}
     int i;
     float f;
   };

diff  --git a/clang/test/Sema/attr-declspec-ignored.c b/clang/test/Sema/attr-declspec-ignored.c
index 6fd35c0bd783..7e5cebf5f45c 100644
--- a/clang/test/Sema/attr-declspec-ignored.c
+++ b/clang/test/Sema/attr-declspec-ignored.c
@@ -7,6 +7,16 @@ __attribute__((visibility("hidden")))  __attribute__((aligned)) union B; // expe
 __attribute__((visibility("hidden")))  __attribute__((aligned)) enum C {C}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
 // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
 
+// Make sure that we produce the same warnings on block declarations.
+void func() {
+  __attribute__((visibility("hidden")))  __attribute__((aligned)) struct A; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+  // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+  __attribute__((visibility("hidden")))  __attribute__((aligned)) union B; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+  // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+  __attribute__((visibility("hidden")))  __attribute__((aligned)) enum C {C}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+  // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+}
+
 __attribute__((visibility("hidden")))  __attribute__((aligned)) struct D {} d;
 __attribute__((visibility("hidden")))  __attribute__((aligned)) union E {} e;
 __attribute__((visibility("hidden")))  __attribute__((aligned)) enum F {F} f;

diff  --git a/clang/test/Sema/attr-regparm.c b/clang/test/Sema/attr-regparm.c
index d50dd113f70f..c18367993d65 100644
--- a/clang/test/Sema/attr-regparm.c
+++ b/clang/test/Sema/attr-regparm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
 
 __attribute((regparm(2))) int x0(void);
 __attribute((regparm(1.0))) int x1(void); // expected-error{{'regparm' attribute requires an integer constant}}
@@ -9,3 +9,9 @@ __attribute((regparm(5,3))) int x4(void); // expected-error{{'regparm' attribute
 void __attribute__((regparm(3))) x5(int);
 void x5(int); // expected-note{{previous declaration is here}}
 void __attribute__((regparm(2))) x5(int); // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
+
+[[gnu::regparm(3)]] void x6(int); // expected-note{{previous declaration is here}}
+[[gnu::regparm(2)]] void x6(int); // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
+void x6 [[gnu::regparm(3)]] (int);
+void [[gnu::regparm(3)]] x6(int); // expected-warning{{'regparm' only applies to function types; type here is 'void'}}
+void x6(int) [[gnu::regparm(3)]]; // expected-warning{{GCC does not allow the 'regparm' attribute to be written on a type}}

diff  --git a/clang/test/Sema/matrix-type-builtins.c b/clang/test/Sema/matrix-type-builtins.c
index c58384613e79..afe85d31a098 100644
--- a/clang/test/Sema/matrix-type-builtins.c
+++ b/clang/test/Sema/matrix-type-builtins.c
@@ -1,10 +1,26 @@
-// RUN: %clang_cc1 %s -fenable-matrix -pedantic -verify -triple=x86_64-apple-darwin9
+// RUN: %clang_cc1 %s -fenable-matrix -fdouble-square-bracket-attributes -pedantic -verify -triple=x86_64-apple-darwin9
 
 typedef float sx5x10_t __attribute__((matrix_type(5, 10)));
 typedef int ix3x2_t __attribute__((matrix_type(3, 2)));
 typedef double dx3x3 __attribute__((matrix_type(3, 3)));
 typedef unsigned ix3x3 __attribute__((matrix_type(3, 3)));
 
+// Verify that we can use the [[]] spelling of the attribute.
+// We intentionally use the same type alias name to check that both versions
+// define the same type.
+typedef float [[clang::matrix_type(5, 10)]] sx5x10_t;
+typedef int [[clang::matrix_type(3, 2)]] ix3x2_t;
+[[clang::matrix_type(5, 10)]] typedef float sx5x10_t;
+// expected-warning at -1 {{applying attribute 'matrix_type' to a declaration is deprecated; apply it to the type instead}}
+[[clang::matrix_type(3, 2)]] typedef int ix3x2_t;
+// expected-warning at -1 {{applying attribute 'matrix_type' to a declaration is deprecated; apply it to the type instead}}
+
+// Attribute may not be used outside typedefs.
+[[clang::matrix_type(3, 2)]] int ix3x2_var;
+// expected-error at -1 {{'matrix_type' attribute only applies to typedefs}}
+int [[clang::matrix_type(3, 2)]] ix3x2_var;
+// expected-error at -1 {{'matrix_type' attribute only applies to typedefs}}
+
 void transpose(sx5x10_t a, ix3x2_t b, dx3x3 c, int *d, int e) {
   a = __builtin_matrix_transpose(b);
   // expected-error at -1 {{assigning to 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') from incompatible type 'int __attribute__((matrix_type(2, 3)))'}}

diff  --git a/clang/test/Sema/neon-vector-types.c b/clang/test/Sema/neon-vector-types.c
index 03f669eb8416..c79c73919a92 100644
--- a/clang/test/Sema/neon-vector-types.c
+++ b/clang/test/Sema/neon-vector-types.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple armv7 -target-feature +neon -fsyntax-only -verify
-// RUN: %clang_cc1 %s -triple armv8 -target-feature +neon -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple armv7 -target-feature +neon -fsyntax-only -fdouble-square-bracket-attributes -verify
+// RUN: %clang_cc1 %s -triple armv8 -target-feature +neon -fsyntax-only -fdouble-square-bracket-attributes -verify
 
 typedef float float32_t;
 typedef signed char poly8_t;
@@ -16,6 +16,16 @@ typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
 typedef __attribute__((neon_polyvector_type(16))) poly8_t  poly8x16_t;
 typedef __attribute__((neon_polyvector_type(8)))  poly16_t poly16x8_t;
 
+// Verify that we can use the [[]] spelling of the attributes.
+// We intentionally use the same type alias names to check that both versions
+// define the same type.
+typedef int [[clang::neon_vector_type(2)]] int32x2_t;
+typedef poly8_t [[clang::neon_polyvector_type(16)]] poly8x16_t;
+
+// Verify that we can use the attributes outside of a typedef.
+int [[clang::neon_vector_type(2)]] int32x2_var;
+poly8_t [[clang::neon_polyvector_type(16)]] poly8x16_var;
+
 // The attributes must have a single argument.
 typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{'neon_vector_type' attribute takes one argument}}
 

diff  --git a/clang/test/Sema/overload-arm-mve.c b/clang/test/Sema/overload-arm-mve.c
index 3b1a4430747f..9ad1bfcc882f 100644
--- a/clang/test/Sema/overload-arm-mve.c
+++ b/clang/test/Sema/overload-arm-mve.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -Werror -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -verify -fsyntax-only -DERROR_CHECK %s
+// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -fdouble-square-bracket-attributes -Werror -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -fdouble-square-bracket-attributes -verify -fsyntax-only -DERROR_CHECK %s
 
 typedef   signed short      int16_t;
 typedef   signed int        int32_t;
@@ -15,6 +15,14 @@ typedef __attribute__((neon_vector_type(8), __clang_arm_mve_strict_polymorphism)
 typedef __attribute__((neon_vector_type(4), __clang_arm_mve_strict_polymorphism)) uint32_t uint32x4_t;
 typedef __attribute__((neon_vector_type(2), __clang_arm_mve_strict_polymorphism)) uint64_t uint64x2_t;
 
+// Verify that we can use the [[]] spelling of the attribute.
+// We intentionally use the same type alias name to check that both versions
+// define the same type.
+typedef int16_t [[clang::neon_vector_type(8), clang::__clang_arm_mve_strict_polymorphism]] int16x8_t;
+
+// Verify that we can use the attribute outside of a typedef.
+void test_param(int16_t [[clang::neon_vector_type(8), clang::__clang_arm_mve_strict_polymorphism]] int16x8);
+
 __attribute__((overloadable))
 int overload(int16x8_t x, int16_t y); // expected-note {{candidate function}}
 __attribute__((overloadable))

diff  --git a/clang/test/Sema/vector-gcc-compat.c b/clang/test/Sema/vector-gcc-compat.c
index 78132f7f0963..36feb7fd1422 100644
--- a/clang/test/Sema/vector-gcc-compat.c
+++ b/clang/test/Sema/vector-gcc-compat.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -Weverything -Wno-unused-but-set-variable -triple x86_64-apple-darwin10
+// RUN: %clang_cc1 %s -verify -fsyntax-only -fdouble-square-bracket-attributes -Weverything -Wno-unused-but-set-variable -triple x86_64-apple-darwin10
 
 // Test the compatibility of clang's vector extensions with gcc's vector
 // extensions for C. Notably &&, ||, ?: and ! are not available.
@@ -17,6 +17,32 @@ typedef double v2f64 __attribute__((vector_size(16)));
 typedef double v4f64 __attribute__((vector_size(32)));
 typedef int v4i32 __attribute((vector_size(16)));
 
+// Verify that we can use the [[]] spelling of the attribute.
+// We intentionally use the same type alias name to check that both versions
+// define the same type.
+// FIXME: Warnings are nuisance warnings due to the `-Weverything` flag, but
+// we shouldn't really be emitting them in C mode with the
+// `-fdouble-square-bracket-attributes` flag.
+typedef long long v2i64 [[gnu::vector_size(16)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
+typedef int v2i32 [[gnu::vector_size(8)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
+
+// Check various positions where the [[]] spelling can or cannot be used.
+[[gnu::vector_size(16)]] typedef long long v2i64; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
+typedef long long [[gnu::vector_size(16)]] v2i64_ignored;
+  // expected-warning at -1{{'vector_size' attribute ignored}}
+  // expected-warning at -2{{C++11 attribute syntax is incompatible with C++98}}
+// FIXME: Contrary to the error message that we emit, GCC does actually allow
+// the attribute in the following position. Somewhat surprisingly, the attribute
+// is applied not to the pointer but to the base type, i.e. this declaration has
+// the same effect in GCC as the other declarations for `v2i64`.
+typedef long long *[[gnu::vector_size(16)]] v2i64_doesnt_work;
+  // expected-error at -1{{invalid vector element type 'long long *'}}
+  // expected-warning at -2{{GCC does not allow the 'vector_size' attribute to be written on a type}}
+  // expected-warning at -3{{C++11 attribute syntax is incompatible with C++98}}
+
+// Verify that we can use the attribute outside of a typedef.
+static int v2i32_var [[gnu::vector_size(8)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
+
 void arithmeticTest(void);
 void logicTest(void);
 void comparisonTest(void);

diff  --git a/clang/test/SemaCXX/address-space-placement.cpp b/clang/test/SemaCXX/address-space-placement.cpp
new file mode 100644
index 000000000000..2d8b94041259
--- /dev/null
+++ b/clang/test/SemaCXX/address-space-placement.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s
+
+// Check that we emit the correct warnings in various situations where the C++11
+// spelling of the `address_space` attribute is applied to a declaration instead
+// of a type. Also check that the attribute can instead be applied to the type.
+
+void f([[clang::address_space(1)]] int* param) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  [[clang::address_space(1)]] int* local1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  int* local2 [[clang::address_space(1)]]; // expected-error {{automatic variable qualified with an address space}} expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  int [[clang::address_space(1)]] * local3;
+  int* [[clang::address_space(1)]] local4; // expected-error {{automatic variable qualified with an address space}}
+
+  for ([[clang::address_space(1)]] int* p = nullptr; p; ++p) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  for (; [[clang::address_space(1)]] int* p = nullptr; ) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  while([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  if ([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  try {
+  } catch([[clang::address_space(1)]] int& i) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  }
+
+  for (int [[clang::address_space(1)]] * p = nullptr; p; ++p) {}
+  for (; int [[clang::address_space(1)]] * p = nullptr; ) {}
+  while(int [[clang::address_space(1)]] * p = nullptr) {}
+  if (int [[clang::address_space(1)]] * p = nullptr) {}
+  try {
+  } catch(int [[clang::address_space(1)]] & i) {
+  }
+}
+
+[[clang::address_space(1)]] int* return_value(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+int [[clang::address_space(1)]] * return_value();
+
+[[clang::address_space(1)]] int global1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+int global2 [[clang::address_space(1)]]; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+int [[clang::address_space(1)]] global3;
+int [[clang::address_space(1)]] global4;
+
+struct [[clang::address_space(1)]] S { // expected-error {{'address_space' attribute cannot be applied to a declaration}}
+  [[clang::address_space(1)]] int* member_function_1(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+  int [[clang::address_space(1)]] * member_function_2();
+};
+
+template <class T>
+[[clang::address_space(1)]] T var_template_1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+template <class T>
+T [[clang::address_space(1)]] var_template_2;
+
+using void_ptr [[clang::address_space(1)]] = void *; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+// Intentionally using the same alias name to check that the aliases define the
+// same type.
+using void_ptr = void [[clang::address_space(1)]] *;
+
+namespace N {}
+[[clang::address_space(1)]] using namespace N; // expected-error {{'address_space' attribute cannot be applied to a declaration}}

diff  --git a/clang/test/SemaCXX/annotate-type.cpp b/clang/test/SemaCXX/annotate-type.cpp
index c76b1767e7d3..545b3ccfdef8 100644
--- a/clang/test/SemaCXX/annotate-type.cpp
+++ b/clang/test/SemaCXX/annotate-type.cpp
@@ -2,10 +2,7 @@
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 
 template <typename T1, typename T2> struct is_same {
@@ -48,23 +45,21 @@ void f3() {
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit 
diff erent code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3;
-struct [[clang::annotate_type("foo")]] S3{
-  [[clang::annotate_type("foo")]] int member;
+namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  [[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 void f4() {
-  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {}
-  for (; [[clang::annotate_type("foo")]] bool b = false;) {}
-  while ([[clang::annotate_type("foo")]] bool b = false) {}
-  if ([[clang::annotate_type("foo")]] bool b = false) {}
+  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  for (; [[clang::annotate_type("foo")]] bool b = false;) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  while ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  if ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   try {
-  } catch ([[clang::annotate_type("foo")]] int i) {
+  } catch ([[clang::annotate_type("foo")]] int i) { // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   }
 }
 template <class T>
-[[clang::annotate_type("foo")]] T var_template;
-[[clang::annotate_type("foo")]] extern "C" int extern_c_func();
-extern "C" [[clang::annotate_type("foo")]] int extern_c_func();
+[[clang::annotate_type("foo")]] T var_template; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+[[clang::annotate_type("foo")]] extern "C" int extern_c_func(); // expected-error {{an attribute list cannot appear here}}
+extern "C" [[clang::annotate_type("foo")]] int extern_c_func(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}

diff  --git a/clang/test/SemaObjC/attr-objc-gc.m b/clang/test/SemaObjC/attr-objc-gc.m
index 303dce0d8752..e9dcbd993cb3 100644
--- a/clang/test/SemaObjC/attr-objc-gc.m
+++ b/clang/test/SemaObjC/attr-objc-gc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
 static id __attribute((objc_gc(weak))) a;
 static id __attribute((objc_gc(strong))) b;
 
@@ -18,6 +18,10 @@
 /* expected-warning {{'__weak' only applies to Objective-C object or block pointer types; type here is 'int'}}*/ static __we\
 ak int i;
 
+static id [[clang::objc_gc(weak)]] j;
+[[clang::objc_gc(weak)]] static id k; // expected-warning {{applying attribute 'objc_gc' to a declaration is deprecated; apply it to the type instead}}
+static id l [[clang::objc_gc(weak)]]; // expected-warning {{applying attribute 'objc_gc' to a declaration is deprecated; apply it to the type instead}}
+
 // rdar://problem/9126213
 void test2(id __attribute((objc_gc(strong))) *strong,
            id __attribute((objc_gc(weak))) *weak) {

diff  --git a/clang/test/SemaOpenCL/address-spaces.cl b/clang/test/SemaOpenCL/address-spaces.cl
index 41f5a3365325..70b6d0753528 100644
--- a/clang/test/SemaOpenCL/address-spaces.cl
+++ b/clang/test/SemaOpenCL/address-spaces.cl
@@ -266,9 +266,9 @@ void func_multiple_addr2(void) {
   __attribute__((opencl_private)) private_int_t var5;  // expected-warning {{multiple identical address spaces specified for type}}
   __attribute__((opencl_private)) private_int_t *var6; // expected-warning {{multiple identical address spaces specified for type}}
 #if __OPENCL_CPP_VERSION__
-  [[clang::opencl_private]] __global int var7;         // expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] __global int *var8;        // expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t var9;        // expected-warning {{multiple identical address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t *var10;      // expected-warning {{multiple identical address spaces specified for type}}
+  __global int [[clang::opencl_private]] var7;         // expected-error {{multiple address spaces specified for type}}
+  __global int [[clang::opencl_private]] *var8;        // expected-error {{multiple address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] var9;        // expected-warning {{multiple identical address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] *var10;      // expected-warning {{multiple identical address spaces specified for type}}
 #endif // !__OPENCL_CPP_VERSION__
 }

diff  --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index fae821f265e5..1a73b300cf9d 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3739,7 +3739,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
     if (!StmtSubjects.empty()) {
       OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
       OS << "const Decl *D) const override {\n";
-      OS << "  S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
+      OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
       OS << "    << AL << D->getLocation();\n";
       OS << "  return false;\n";
       OS << "}\n\n";


        


More information about the cfe-commits mailing list