mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
For backwards compatiblity, we only emit a warning 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 two high-level changes that achieve this are:

- We move any C++11 attributes (except legacy type attributes) that occur in 
the attribute-specifier-seq at the beginning of a simple-declaration (and other 
similar declarations) to `Declarator::Attrs`. This means that we treat them the 
same as if they had been placed after the declarator-id. (Justification below.)

- We make `ProcessDeclAttribute` emit a warning 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

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)

Things that remain to be done:

- Emit warnings when a legacy type attribute occurs on a declaration. (This is 
not hard to do but will likely require updating a large number of tests, so I'd 
first like to get confirmation that the general direction of this change makes 
sense.)

- Move additional tests added to annotate-type.cpp to 
https://reviews.llvm.org/D111548 instead.

- Various other TODOs in the code

Depends On D111548 <https://reviews.llvm.org/D111548>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124919

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.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/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp

Index: clang/test/SemaCXX/annotate-type.cpp
===================================================================
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -1,11 +1,10 @@
-// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -fcxx-exceptions -verify
 
 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 {
@@ -53,11 +52,31 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different 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{};
+namespace [[clang::annotate_type("foo")]] my_namespace {
+} // namespace my_namespace
+struct [[clang::annotate_type(
+    "foo")]] S3{}; // expected-error {{'annotate_type' attribute cannot be
+                   // applied to a declaration}}
 void f4() {
   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) { // expected-error {{'annotate_type' attribute cannot be
+                        // applied to a declaration}}
   }
 }
+template <class T>
+[[clang::annotate_type(
+    "foo")]] T var_template; // expected-error {{'annotate_type' attribute
+                             // cannot be applied to a declaration}}
Index: clang/test/Sema/annotate-type.c
===================================================================
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -17,10 +17,7 @@
   int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
 
   // Various error cases
-  // 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("bar")]] int *z1;
+  [[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}}
@@ -33,7 +30,6 @@
 }
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different 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 g([[clang::annotate_type("bar")]] int);
+[[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}}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -8439,13 +8439,6 @@
       break;
     }
     case ParsedAttr::AT_AnnotateType: {
-      if (TAL == TAL_DeclName) {
-        state.getSema().Diag(attr.getLoc(),
-                             diag::err_type_attribute_invalid_on_decl)
-            << attr;
-        return;
-      }
-
       HandleAnnotateTypeAttr(state, type, attr);
       attr.setUsedAsTypeAttr();
       break;
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8312,15 +8312,15 @@
 /// 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)
+  if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes)
     return;
 
   // Unknown attributes are automatically warned on. Target-specific attributes
@@ -8353,9 +8353,21 @@
     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.slidesFromDeclToDeclSpec()) {
+        if (AL.isStandardAttributeSyntax()) {
+          // TODO: We're looking at one of a number of type attributes that we
+          // have historically allowed to be applied to a declaration in C++11
+          // syntax, "sliding" them to the DeclSpec. Emit a warning that type
+          // attributes aren't allowed in this position.
+        }
+        // GNU type attributes are handled elsewhere; 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
@@ -9004,14 +9016,14 @@
 
 /// 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
@@ -9099,7 +9111,9 @@
     AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
   for (const ParsedAttr &AL : AttrList) {
     if (AL.getKind() == ParsedAttr::AT_Annotate) {
-      ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
+      ProcessDeclAttributeOptions Options;
+      Options.IncludeCXX11Attributes = AL.isCXX11Attribute();
+      ProcessDeclAttribute(*this, nullptr, ASDecl, AL, Options);
     } else {
       Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
       return true;
@@ -9241,16 +9255,22 @@
 /// specified in many different places, and we need to find and apply them all.
 void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
   // 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().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());
Index: clang/lib/Sema/ParsedAttr.cpp
===================================================================
--- clang/lib/Sema/ParsedAttr.cpp
+++ clang/lib/Sema/ParsedAttr.cpp
@@ -212,6 +212,46 @@
   return getInfo().IsSupportedByPragmaAttribute;
 }
 
+bool ParsedAttr::slidesFromDeclToDeclSpec() const {
+  if (!isStandardAttributeSyntax())
+    return true;
+
+  // TODO: Document that these are due to legacy behavior.
+  switch (getParsedKind()) {
+  case AT_AddressSpace:
+  case AT_CmseNSCall:
+  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_ArmSveVectorBits:
+  case AT_ArmMveStrictPolymorphism:
+  case AT_BTFTypeTag:
+  case AT_TypeNonNull:
+  case AT_TypeNullable:
+  case AT_TypeNullableResult:
+  case AT_TypeNullUnspecified:
+  case AT_ObjCInertUnsafeUnretained:
+  case AT_Regparm:
+  case AT_NoDeref:
+  case AT_ObjCGC:
+  case AT_VectorSize:
+  case AT_MatrixType:
+  case AT_Ptr32:
+  case AT_Ptr64:
+  case AT_SPtr:
+  case AT_UPtr:
+    return true;
+  default:
+    return false;
+  }
+}
+
 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
 
 unsigned ParsedAttr::getSemanticSpelling() const {
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -1112,8 +1112,11 @@
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
 
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(Attrs, DeclAttrs);
   DS.takeAttributesFrom(Attrs);
 
+  // TODO: Plumb attributes through to here?
   // ObjC2 allows prefix attributes on class interfaces and protocols.
   // FIXME: This still needs better diagnostics. We should only accept
   // attributes here, no types, etc.
@@ -1145,6 +1148,7 @@
             ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()));
   }
 
+  // TODO: Plumb attributes through to here?
   // If the declspec consisted only of 'extern' and we have a string
   // literal following it, this must be a C++ linkage specifier like
   // 'extern "C"'.
@@ -1155,7 +1159,7 @@
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
 
-  return ParseDeclGroup(DS, DeclaratorContext::File);
+  return ParseDeclGroup(DS, DeclaratorContext::File, DeclAttrs);
 }
 
 Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -239,6 +239,9 @@
     return Decl;
   }
 
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(prefixAttrs, DeclAttrs);
+
   // Move the attributes from the prefix into the DS.
   if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
     ProhibitAttributes(prefixAttrs);
@@ -247,6 +250,7 @@
 
   // Parse the declarator.
   ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
+  DeclaratorInfo.takeAttributes(DeclAttrs);
   if (TemplateInfo.TemplateParams)
     DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
 
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -2583,6 +2583,9 @@
     ParsedAttributes Attributes(AttrFactory);
     MaybeParseCXX11Attributes(Attributes);
 
+    ParsedAttributes DeclAttrs(AttrFactory);
+    ExtractDefiniteDeclAttrs(Attributes, DeclAttrs);
+
     DeclSpec DS(AttrFactory);
     DS.takeAttributesFrom(Attributes);
 
@@ -2590,6 +2593,7 @@
       return StmtError();
 
     Declarator ExDecl(DS, DeclaratorContext::CXXCatch);
+    ExDecl.takeAttributes(DeclAttrs);
     ParseDeclarator(ExDecl);
     ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
   } else
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2077,6 +2077,9 @@
   // If this is a for loop, we're entering its condition.
   ForConditionScope.enter(/*IsConditionVariable=*/true);
 
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(attrs, DeclAttrs);
+
   // type-specifier-seq
   DeclSpec DS(AttrFactory);
   DS.takeAttributesFrom(attrs);
@@ -2084,6 +2087,7 @@
 
   // declarator
   Declarator DeclaratorInfo(DS, DeclaratorContext::Condition);
+  DeclaratorInfo.takeAttributes(DeclAttrs);
   ParseDeclarator(DeclaratorInfo);
 
   // simple-asm-expr[opt]
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -2687,11 +2687,6 @@
   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);
 
   if (Tok.is(tok::kw_using)) {
@@ -2722,6 +2717,19 @@
   // decl-specifier-seq:
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this, TemplateDiags);
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(attrs, DeclAttrs);
+
+  // We need to keep these attributes for future diagnostic
+  // before they are taken over by declaration specifier.
+  FnAttrs.addAll(attrs.begin(), attrs.end());
+  // TODO: Explain the reason for this.
+  if (DeclAttrs.empty()) {
+    FnAttrs.Range = attrs.Range;
+  } else {
+    FnAttrs.updateRange();
+  }
+
   DS.takeAttributesFrom(attrs);
   if (MalformedTypeSpec)
     DS.SetTypeSpecError();
@@ -2774,6 +2782,8 @@
   }
 
   ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member);
+  AttributeLender AttrLender;
+  AttrLender.Lend(DeclAttrs, DeclaratorInfo);
   if (TemplateInfo.TemplateParams)
     DeclaratorInfo.setTemplateParameterLists(TemplateParams);
   VirtSpecifiers VS;
@@ -3072,7 +3082,9 @@
     }
 
     // Parse the next declarator.
+    AttrLender.Return(DeclAttrs, DeclaratorInfo);
     DeclaratorInfo.clear();
+    AttrLender.Lend(DeclAttrs, DeclaratorInfo);
     VS.clear();
     BitfieldSize = ExprResult(/*Invalid=*/false);
     EqualLoc = PureSpecLoc = SourceLocation();
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -1732,6 +1732,20 @@
   }
 }
 
+// TODO: Documentation
+void Parser::ExtractDefiniteDeclAttrs(ParsedAttributes &Attrs,
+                                      ParsedAttributes &DeclAttrs) {
+  llvm::SmallVector<ParsedAttr *, 1> ToBeMoved;
+  for (ParsedAttr &AL : Attrs) {
+    if (!AL.slidesFromDeclToDeclSpec()) {
+      ToBeMoved.push_back(&AL);
+    }
+  }
+  for (ParsedAttr *AL : ToBeMoved) {
+    DeclAttrs.takeOneFrom(Attrs, AL);
+  }
+}
+
 /// ParseDeclaration - Parse a full 'declaration', which consists of
 /// declaration-specifiers, some number of declarators, and a semicolon.
 /// 'Context' should be a DeclaratorContext value.  This returns the
@@ -1850,8 +1864,10 @@
   if (DeclSpecStart)
     DS.SetRangeStart(*DeclSpecStart);
 
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(Attrs, DeclAttrs);
   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
@@ -2006,10 +2022,13 @@
 /// result.
 Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
                                               DeclaratorContext Context,
+                                              ParsedAttributes &Attrs,
                                               SourceLocation *DeclEnd,
                                               ForRangeInit *FRI) {
   // Parse the first declarator.
   ParsingDeclarator D(*this, DS, Context);
+  AttributeLender AttrLender;
+  AttrLender.Lend(Attrs, D);
   ParseDeclarator(D);
 
   // Bail out if the first declarator didn't seem well-formed.
@@ -2172,7 +2191,9 @@
     }
 
     // Parse the next declarator.
+    AttrLender.Return(Attrs, D);
     D.clear();
+    AttrLender.Lend(Attrs, D);
     D.setCommaLoc(CommaLoc);
 
     // Accept attributes in an init-declarator.  In the first declarator in a
@@ -3168,19 +3189,18 @@
         for (const ParsedAttr &PA : attrs) {
           if (!PA.isCXX11Attribute() && !PA.isC2xAttribute())
             continue;
+          if (PA.getKind() == ParsedAttr::UnknownAttribute)
+            // We will warn about the unused attribute elsewhere (in
+            // SemaDeclAttr.cpp)
+            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;
-          if (PA.getKind() == ParsedAttr::UnknownAttribute)
-            Diag(PA.getLoc(), diag::warn_unknown_attribute_ignored)
-                << PA << PA.getRange();
-          else {
-            Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
-            PA.setInvalid();
-          }
+          Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
+          PA.setInvalid();
         }
 
         DS.takeAttributesFrom(attrs);
@@ -4301,6 +4321,8 @@
   // Parse leading attributes.
   ParsedAttributes Attrs(AttrFactory);
   MaybeParseCXX11Attributes(Attrs);
+  ParsedAttributes DeclAttrs(AttrFactory);
+  ExtractDefiniteDeclAttrs(Attrs, DeclAttrs);
   DS.takeAttributesFrom(Attrs);
 
   // Parse the common specifier-qualifiers-list piece.
@@ -4310,6 +4332,7 @@
   // specifier. Let the actions module cope with it.
   if (Tok.is(tok::semi)) {
     RecordDecl *AnonRecord = nullptr;
+    // TODO: Pass on DeclAttrs
     Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
                                                        DS, AnonRecord);
     assert(!AnonRecord && "Did not expect anonymous struct or union here");
@@ -4322,6 +4345,8 @@
   SourceLocation CommaLoc;
   while (true) {
     ParsingFieldDeclarator DeclaratorInfo(*this, DS);
+    AttributeLender AttrLender;
+    AttrLender.Lend(DeclAttrs, DeclaratorInfo.D);
     DeclaratorInfo.D.setCommaLoc(CommaLoc);
 
     // Attributes are only allowed here on successive declarators.
@@ -4362,6 +4387,8 @@
       return;
 
     FirstDeclarator = false;
+
+    AttrLender.Return(DeclAttrs, DeclaratorInfo.D);
   }
 }
 
@@ -6954,20 +6981,26 @@
     // Just use the ParsingDeclaration "scope" of the declarator.
     DeclSpec DS(AttrFactory);
 
-    // Parse any C++11 attributes.
-    MaybeParseCXX11Attributes(DS.getAttributes());
-
-    // Skip any Microsoft attributes before a param.
-    MaybeParseMicrosoftAttributes(DS.getAttributes());
-
-    SourceLocation DSStart = Tok.getLocation();
+    ParsedAttributes ArgAttrs(AttrFactory);
 
     // 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);
+    ArgAttrs.takeAllFrom(FirstArgAttrs);
+
+    // Parse any C++11 attributes.
+    MaybeParseCXX11Attributes(ArgAttrs);
+
+    // Skip any Microsoft attributes before a param.
+    MaybeParseMicrosoftAttributes(ArgAttrs);
+
+    ParsedAttributes DeclAttrs(AttrFactory);
+    ExtractDefiniteDeclAttrs(ArgAttrs, DeclAttrs);
+    DS.takeAttributesFrom(ArgAttrs);
+
+    SourceLocation DSStart = Tok.getLocation();
 
     ParseDeclarationSpecifiers(DS);
 
@@ -6981,6 +7014,7 @@
                 : DeclaratorCtx == DeclaratorContext::LambdaExpr
                       ? DeclaratorContext::LambdaExprParameter
                       : DeclaratorContext::Prototype);
+    ParmDeclarator.takeAttributes(DeclAttrs);
     ParseDeclarator(ParmDeclarator);
 
     // Parse GNU attributes, if present.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4423,8 +4423,26 @@
   // 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);
+  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;
+    }
+    bool IncludeCXX11Attributes;
+    bool IgnoreTypeAttributes;
+  };
+  void ProcessDeclAttributeList(Scope *S, Decl *D,
+                                const ParsedAttributesView &AL,
+                                const ProcessDeclAttributeOptions &Options =
+                                    ProcessDeclAttributeOptions());
   bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
                                    const ParsedAttributesView &AttrList);
 
Index: clang/include/clang/Sema/ParsedAttr.h
===================================================================
--- clang/include/clang/Sema/ParsedAttr.h
+++ clang/include/clang/Sema/ParsedAttr.h
@@ -650,6 +650,8 @@
   bool existsInTarget(const TargetInfo &Target) const;
   bool isKnownToGCC() const;
   bool isSupportedByPragmaAttribute() const;
+  // TODO: Document
+  bool slidesFromDeclToDeclSpec() const;
 
   /// If the parsed attribute has a semantic equivalent, and it would
   /// have a semantic Spelling enumeration (due to having semantically-distinct
@@ -906,6 +908,22 @@
   ParsedAttr &operator[](SizeType pos) { return *AttrList[pos]; }
   const ParsedAttr &operator[](SizeType pos) const { return *AttrList[pos]; }
 
+  void updateRange() {
+    Range = SourceRange();
+    for (const ParsedAttr &PA : *this) {
+      if (Range.isInvalid()) {
+        Range = PA.getRange();
+        continue;
+      }
+      if (PA.getRange().getBegin() < Range.getBegin()) {
+        Range.setBegin(PA.getRange().getBegin());
+      }
+      if (PA.getRange().getEnd() > Range.getEnd()) {
+        Range.setEnd(PA.getRange().getEnd());
+      }
+    }
+  }
+
   void addAtEnd(ParsedAttr *newAttr) {
     assert(newAttr);
     AttrList.push_back(newAttr);
Index: clang/include/clang/Parse/RAIIObjectsForParser.h
===================================================================
--- clang/include/clang/Parse/RAIIObjectsForParser.h
+++ clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -459,6 +459,27 @@
     }
     void skipToEnd();
   };
+
+  // TODO: Document and explain how this isn't actually a RAII object.
+  class AttributeLender {
+  public:
+    void Lend(ParsedAttributes &Attrs, Declarator &D) {
+      for (ParsedAttr &AL : Attrs) {
+        LentAttrs.push_back(&AL);
+      }
+      D.takeAttributes(Attrs);
+    }
+
+    void Return(ParsedAttributes &Attrs, Declarator &D) {
+      for (ParsedAttr *AL : LentAttrs) {
+        Attrs.takeOneFrom(D.getAttributes(), AL);
+      }
+      LentAttrs.clear();
+    }
+
+  private:
+    llvm::SmallVector<ParsedAttr *, 1> LentAttrs;
+  };
 } // end namespace clang
 
 #endif
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2316,6 +2316,7 @@
                          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,
@@ -2611,6 +2612,10 @@
   void stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, DeclSpec &DS,
                                       Sema::TagUseKind TUK);
 
+  /// TODO: Add documentation.
+  void ExtractDefiniteDeclAttrs(ParsedAttributes &Attrs,
+                                ParsedAttributes &DeclAttrs);
+
   // FixItLoc = possible correct location for the attributes
   void ProhibitAttributes(ParsedAttributes &Attrs,
                           SourceLocation FixItLoc = SourceLocation()) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to