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