diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2553,7 +2553,7 @@ let Documentation = [SwiftAsyncErrorDocs]; } -def Suppress : StmtAttr { +def Suppress : DeclOrStmtAttr { let Spellings = [CXX11<"gsl", "suppress">]; let Args = [VariadicStringArgument<"DiagnosticIdentifiers">]; let Documentation = [SuppressDocs]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3357,9 +3357,9 @@ InGroup; 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< +def err_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 err_type_attribute_invalid_on_decl : Error< "%0 attribute cannot be applied to a declaration">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2686,30 +2686,34 @@ /// Such situations should use the specific attribute parsing functionality. void ParseAttributes(unsigned WhichAttrKinds, ParsedAttributesWithRange &Attrs, + AttributeAppertainsTo appertainsTo, LateParsedAttrList *LateAttrs = nullptr); void ParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, + AttributeAppertainsTo appertainsTo, LateParsedAttrList *LateAttrs = nullptr) { ParsedAttributesWithRange AttrsWithRange(AttrFactory); - ParseAttributes(WhichAttrKinds, AttrsWithRange, LateAttrs); + ParseAttributes(WhichAttrKinds, AttrsWithRange, appertainsTo, LateAttrs); Attrs.takeAllFrom(AttrsWithRange); } /// \brief Possibly parse attributes based on what syntaxes are desired, /// allowing for the order to vary. bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributesWithRange &Attrs, + AttributeAppertainsTo appertainsTo, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) || (standardAttributesAllowed() && isCXX11AttributeSpecifier())) { - ParseAttributes(WhichAttrKinds, Attrs, LateAttrs); + ParseAttributes(WhichAttrKinds, Attrs, appertainsTo, LateAttrs); return true; } return false; } bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, + AttributeAppertainsTo appertainsTo, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) || (standardAttributesAllowed() && isCXX11AttributeSpecifier())) { - ParseAttributes(WhichAttrKinds, Attrs, LateAttrs); + ParseAttributes(WhichAttrKinds, Attrs, appertainsTo, LateAttrs); return true; } return false; @@ -2791,24 +2795,28 @@ void MaybeParseCXX11Attributes(Declarator &D) { if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); - ParseCXX11Attributes(attrs); + // TODO: Is this correct? + ParseCXX11Attributes(attrs, AppertainsToDecl); D.takeAttributes(attrs, attrs.Range.getEnd()); } } - bool MaybeParseCXX11Attributes(ParsedAttributes &attrs) { + bool MaybeParseCXX11Attributes(ParsedAttributes &attrs, + AttributeAppertainsTo appertainsTo) { if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); - ParseCXX11Attributes(attrsWithRange); + ParseCXX11Attributes(attrsWithRange, appertainsTo); attrs.takeAllFrom(attrsWithRange); return true; } return false; } bool MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs, + AttributeAppertainsTo appertainsTo, bool OuterMightBeMessageSend = false) { if (standardAttributesAllowed() && isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) { - ParseCXX11Attributes(attrs); + // TODO: How to pass? + ParseCXX11Attributes(attrs, appertainsTo); return true; } return false; @@ -2817,16 +2825,24 @@ void ParseOpenMPAttributeArgs(IdentifierInfo *AttrName, CachedTokens &OpenMPTokens); + void DiagnoseAppertainsTo(ParsedAttr &PA, AttributeAppertainsTo appertainsTo); + void DiagnoseAppertainsTo(ParsedAttributesView &Attrs, + AttributeAppertainsTo appertainsTo); + void ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, + AttributeAppertainsTo appertainsTo, SourceLocation *EndLoc = nullptr); void ParseCXX11AttributeSpecifier(ParsedAttributes &Attrs, + AttributeAppertainsTo appertainsTo, SourceLocation *EndLoc = nullptr) { CachedTokens OpenMPTokens; - ParseCXX11AttributeSpecifierInternal(Attrs, OpenMPTokens, EndLoc); + ParseCXX11AttributeSpecifierInternal(Attrs, OpenMPTokens, appertainsTo, + EndLoc); ReplayOpenMPAttributeTokens(OpenMPTokens); } - void ParseCXX11Attributes(ParsedAttributesWithRange &attrs); + void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, + AttributeAppertainsTo appertainsTo); /// Parses a C++11 (or C2x)-style attribute argument list. Returns true /// if this results in adding an attribute to the ParsedAttributes list. bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -61,6 +61,8 @@ unsigned IsType : 1; /// True if this attribute applies to statements. unsigned IsStmt : 1; + /// True if this attribute applies to declarations. + unsigned IsDecl : 1; /// True if this attribute has any spellings that are known to gcc. unsigned IsKnownToGCC : 1; /// True if this attribute is supported by #pragma clang attribute. @@ -79,20 +81,23 @@ AttributeCommonInfo::NoSemaHandlerAttribute) : AttrKind(AttrKind), NumArgs(0), OptArgs(0), NumArgMembers(0), HasCustomParsing(0), AcceptsExprPack(0), IsTargetSpecific(0), IsType(0), - IsStmt(0), IsKnownToGCC(0), IsSupportedByPragmaAttribute(0) {} + IsStmt(0), IsDecl(0), IsKnownToGCC(0), IsSupportedByPragmaAttribute(0) { + } constexpr ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind, unsigned NumArgs, unsigned OptArgs, unsigned NumArgMembers, unsigned HasCustomParsing, unsigned AcceptsExprPack, unsigned IsTargetSpecific, unsigned IsType, - unsigned IsStmt, unsigned IsKnownToGCC, + unsigned IsStmt, unsigned IsDecl, + unsigned IsKnownToGCC, unsigned IsSupportedByPragmaAttribute, ArrayRef Spellings, ArrayRef ArgNames) : AttrKind(AttrKind), NumArgs(NumArgs), OptArgs(OptArgs), NumArgMembers(NumArgMembers), HasCustomParsing(HasCustomParsing), AcceptsExprPack(AcceptsExprPack), IsTargetSpecific(IsTargetSpecific), - IsType(IsType), IsStmt(IsStmt), IsKnownToGCC(IsKnownToGCC), + IsType(IsType), IsStmt(IsStmt), IsDecl(IsDecl), + IsKnownToGCC(IsKnownToGCC), IsSupportedByPragmaAttribute(IsSupportedByPragmaAttribute), Spellings(Spellings), ArgNames(ArgNames) {} @@ -1147,6 +1152,14 @@ ExpectedFunctionWithProtoType, }; +// TODO: Document +enum AttributeAppertainsTo { + AppertainsToDecl, + AppertainsToStmt, + AppertainsToType, + AppertainsToUnknown, +}; + inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const ParsedAttr &At) { DB.AddTaggedVal(reinterpret_cast(At.getAttrName()), diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -105,6 +105,7 @@ void Parser::ParseAttributes(unsigned WhichAttrKinds, ParsedAttributesWithRange &Attrs, + AttributeAppertainsTo appertainsTo, LateParsedAttrList *LateAttrs) { bool MoreToParse; do { @@ -112,7 +113,8 @@ // parsed, loop to ensure all specified attribute combinations are parsed. MoreToParse = false; if (WhichAttrKinds & PAKM_CXX11) - MoreToParse |= MaybeParseCXX11Attributes(Attrs); + // TODO: Need to plumb the right value in here + MoreToParse |= MaybeParseCXX11Attributes(Attrs, appertainsTo); if (WhichAttrKinds & PAKM_GNU) MoreToParse |= MaybeParseGNUAttributes(Attrs, LateAttrs); if (WhichAttrKinds & PAKM_Declspec) @@ -1652,7 +1654,7 @@ // Consume the attributes. SourceLocation Loc = Tok.getLocation(); - ParseCXX11Attributes(Attrs); + ParseCXX11Attributes(Attrs, AppertainsToUnknown); CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true); // FIXME: use err_attributes_misplaced Diag(Loc, diag::err_attributes_not_allowed) @@ -3216,7 +3218,7 @@ attrs.clear(); attrs.Range = SourceRange(); - ParseCXX11Attributes(attrs); + ParseCXX11Attributes(attrs, AppertainsToType); AttrsLastTime = true; continue; @@ -3675,7 +3677,8 @@ // Attributes support. case tok::kw___attribute: case tok::kw___declspec: - ParseAttributes(PAKM_GNU | PAKM_Declspec, DS.getAttributes(), LateAttrs); + ParseAttributes(PAKM_GNU | PAKM_Declspec, DS.getAttributes(), + AppertainsToType, LateAttrs); continue; // Microsoft single token adornments. @@ -4313,7 +4316,7 @@ // Parse leading attributes. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); DS.takeAttributesFrom(Attrs); // Parse the common specifier-qualifiers-list piece. @@ -4552,7 +4555,8 @@ // If attributes exist after tag, parse them. ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs, + AppertainsToDecl); SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; @@ -4569,7 +4573,8 @@ ProhibitAttributes(attrs); // They are allowed afterwards, though. - MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs, + AppertainsToDecl); } // C++11 [temp.explicit]p12: @@ -4962,7 +4967,7 @@ ? diag::warn_cxx14_compat_ns_enum_attribute : diag::ext_ns_enum_attribute) << 1 /*enumerator*/; - ParseCXX11Attributes(attrs); + ParseCXX11Attributes(attrs, AppertainsToDecl); } SourceLocation EqualLoc; @@ -5636,7 +5641,7 @@ if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); - ParseCXX11Attributes(attrs); + ParseCXX11Attributes(attrs, AppertainsToType); DS.takeAttributesFrom(attrs); } @@ -6679,7 +6684,7 @@ // If there are attributes following the identifier list, parse them and // prohibit them. - MaybeParseCXX11Attributes(FnAttrs); + MaybeParseCXX11Attributes(FnAttrs, AppertainsToDecl); ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) @@ -6755,7 +6760,7 @@ // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes // after the exception-specification. - MaybeParseCXX11Attributes(FnAttrs); + MaybeParseCXX11Attributes(FnAttrs, AppertainsToType); // Parse trailing-return-type[opt]. LocalEndLoc = EndLoc; @@ -6771,7 +6776,7 @@ EndLoc = Range.getEnd(); } } else if (standardAttributesAllowed()) { - MaybeParseCXX11Attributes(FnAttrs); + MaybeParseCXX11Attributes(FnAttrs, AppertainsToType); } } @@ -6963,7 +6968,7 @@ DeclSpec DS(AttrFactory); // Parse any C++11 attributes. - MaybeParseCXX11Attributes(DS.getAttributes()); + MaybeParseCXX11Attributes(DS.getAttributes(), AppertainsToDecl); // Skip any Microsoft attributes before a param. MaybeParseMicrosoftAttributes(DS.getAttributes()); @@ -7169,7 +7174,7 @@ if (Tok.getKind() == tok::r_square) { T.consumeClose(); ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToType); // Remember that we parsed the empty array type. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, nullptr, @@ -7185,7 +7190,7 @@ T.consumeClose(); ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToType); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, ExprRes.get(), @@ -7262,7 +7267,7 @@ T.consumeClose(); - MaybeParseCXX11Attributes(DS.getAttributes()); + MaybeParseCXX11Attributes(DS.getAttributes(), AppertainsToType); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo( diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyDeclStackTrace.h" @@ -19,10 +18,12 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/TimeProfiler.h" @@ -88,7 +89,7 @@ ? diag::warn_cxx14_compat_ns_enum_attribute : diag::ext_ns_enum_attribute) << 0 /*namespace*/; - ParseCXX11Attributes(attrs); + ParseCXX11Attributes(attrs, AppertainsToDecl); MoreToParse = true; } } while (MoreToParse); @@ -252,7 +253,7 @@ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); ParseExternalDeclaration(attrs); } @@ -355,7 +356,7 @@ Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" @@ -405,7 +406,7 @@ LLVM_FALLTHROUGH; default: ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); ParseExternalDeclaration(attrs); continue; } @@ -437,7 +438,7 @@ if (Tok.isNot(tok::l_brace)) { // FIXME: Factor out a ParseExternalDeclarationWithAttrs. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); MaybeParseMicrosoftAttributes(Attrs); ParseExternalDeclaration(Attrs); return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl, @@ -457,7 +458,7 @@ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); MaybeParseMicrosoftAttributes(Attrs); ParseExternalDeclaration(Attrs); } @@ -725,7 +726,7 @@ // Check for misplaced attributes before the identifier in an // alias-declaration. ParsedAttributesWithRange MisplacedAttrs(AttrFactory); - MaybeParseCXX11Attributes(MisplacedAttrs); + MaybeParseCXX11Attributes(MisplacedAttrs, AppertainsToDecl); if (InInitStatement && Tok.isNot(tok::identifier)) return nullptr; @@ -734,7 +735,7 @@ bool InvalidDeclarator = ParseUsingDeclarator(Context, D); ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs, AppertainsToDecl); // If we had any misplaced attributes from earlier, this is where they // should have been written. @@ -781,7 +782,7 @@ SmallVector DeclsInGroup; while (true) { // Parse (optional) attributes. - MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs, AppertainsToDecl); DiagnoseCXX11AttributeExtension(Attrs); Attrs.addAll(PrefixAttrs.begin(), PrefixAttrs.end()); @@ -1506,7 +1507,9 @@ ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + // TODO: I think this doesn't really work -- could be a type too. + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs, + AppertainsToDecl); // Parse inheritance specifiers. if (Tok.isOneOf(tok::kw___single_inheritance, @@ -1515,7 +1518,9 @@ ParseMicrosoftInheritanceClassAttributes(attrs); // Allow attributes to precede or succeed the inheritance specifiers. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + // TODO: I think this doesn't really work -- could be a type too. + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs, + AppertainsToDecl); // Source location used by FIXIT to insert misplaced // C++11 attributes @@ -1752,7 +1757,7 @@ // DeclSpecContext::DSC_alias_declaration. // If there are attributes after class name, parse them. - MaybeParseCXX11Attributes(Attributes); + MaybeParseCXX11Attributes(Attributes, AppertainsToDecl); const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); Sema::TagUseKind TUK; @@ -2164,7 +2169,7 @@ SourceLocation StartLoc = Tok.getLocation(); ParsedAttributesWithRange Attributes(AttrFactory); - MaybeParseCXX11Attributes(Attributes); + MaybeParseCXX11Attributes(Attributes, AppertainsToDecl); // Parse the 'virtual' keyword. if (TryConsumeToken(tok::kw_virtual)) @@ -2683,7 +2688,7 @@ ParsedAttributesWithRange attrs(AttrFactory); ParsedAttributesViewWithRange FnAttrs; // Optional C++11 attribute-specifier - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); // The next token may be an OpenMP pragma annotation token. That would // normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in @@ -4370,6 +4375,68 @@ return true; } +void Parser::DiagnoseAppertainsTo(ParsedAttr &PA, + AttributeAppertainsTo appertainsTo) { + AttributeCommonInfo::Kind kind = PA.getKind(); + + if (kind == ParsedAttr::UnknownAttribute) + return; + + switch (appertainsTo) { + case AppertainsToDecl: + if (!PA.getInfo().IsDecl && kind != ParsedAttr::AT_AddressSpace && + kind != ParsedAttr::AT_CmseNSCall && + kind != ParsedAttr::AT_OpenCLPrivateAddressSpace && + kind != ParsedAttr::AT_OpenCLGlobalAddressSpace && + kind != ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace && + kind != ParsedAttr::AT_OpenCLGlobalHostAddressSpace && + kind != ParsedAttr::AT_OpenCLLocalAddressSpace && + kind != ParsedAttr::AT_OpenCLConstantAddressSpace && + kind != ParsedAttr::AT_OpenCLGenericAddressSpace && + kind != ParsedAttr::AT_NeonPolyVectorType && + kind != ParsedAttr::AT_NeonVectorType && + kind != ParsedAttr::AT_ArmSveVectorBits && + kind != ParsedAttr::AT_ArmMveStrictPolymorphism && + kind != ParsedAttr::AT_BTFTypeTag && + kind != ParsedAttr::AT_TypeNonNull && + kind != ParsedAttr::AT_TypeNullable && + kind != ParsedAttr::AT_TypeNullableResult && + kind != ParsedAttr::AT_TypeNullUnspecified && + kind != ParsedAttr::AT_ObjCInertUnsafeUnretained && + kind != ParsedAttr::AT_Regparm && kind != ParsedAttr::AT_NoDeref && + kind != ParsedAttr::AT_ObjCGC && kind != ParsedAttr::AT_VectorSize && + kind != ParsedAttr::AT_MatrixType && kind != ParsedAttr::AT_Ptr32 && + kind != ParsedAttr::AT_Ptr64 && kind != ParsedAttr::AT_SPtr && + kind != ParsedAttr::AT_UPtr) { + Diag(PA.getLoc(), diag::err_attribute_invalid_on_decl) << PA; + PA.setInvalid(); + } + break; + case AppertainsToType: + if (!PA.getInfo().IsType) { + Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA; + PA.setInvalid(); + } + break; + case AppertainsToStmt: + if (!PA.getInfo().IsStmt) { + Diag(PA.getLoc(), diag::err_attribute_invalid_on_stmt) << PA; + PA.setInvalid(); + } + break; + case AppertainsToUnknown: + // No checking + break; + } +} + +void Parser::DiagnoseAppertainsTo(ParsedAttributesView &Attrs, + AttributeAppertainsTo appertainsTo) { + for (ParsedAttr &PA : Attrs) { + DiagnoseAppertainsTo(PA, appertainsTo); + } +} + /// ParseCXX11AttributeSpecifier - Parse a C++11 or C2x attribute-specifier. /// /// [C++11] attribute-specifier: @@ -4394,9 +4461,9 @@ /// /// [C++11] attribute-namespace: /// identifier -void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, - CachedTokens &OpenMPTokens, - SourceLocation *EndLoc) { +void Parser::ParseCXX11AttributeSpecifierInternal( + ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, + AttributeAppertainsTo appertainsTo, SourceLocation *EndLoc) { if (Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); ParseAlignmentSpecifier(Attrs, EndLoc); @@ -4433,6 +4500,8 @@ llvm::SmallDenseMap SeenAttrs; + size_t NumAttributesExisting = Attrs.size(); + bool AttrParsed = false; while (!Tok.isOneOf(tok::r_square, tok::semi, tok::eof)) { if (AttrParsed) { @@ -4501,6 +4570,10 @@ << AttrName; } + for (size_t i = NumAttributesExisting; i < Attrs.size(); ++i) { + DiagnoseAppertainsTo(Attrs[i], appertainsTo); + } + // If we hit an error and recovered by parsing up to a semicolon, eat the // semicolon and don't issue further diagnostics about missing brackets. if (Tok.is(tok::semi)) { @@ -4523,14 +4596,15 @@ /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier -void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs) { +void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, + AttributeAppertainsTo appertainsTo) { assert(standardAttributesAllowed()); SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc = StartLoc; do { - ParseCXX11AttributeSpecifier(attrs, &EndLoc); + ParseCXX11AttributeSpecifier(attrs, appertainsTo, &EndLoc); } while (isCXX11AttributeSpecifier()); attrs.Range = SourceRange(StartLoc, EndLoc); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1328,7 +1328,7 @@ // GNU-style attributes must be parsed before the mutable specifier to // be compatible with GCC. MSVC-style attributes must be parsed before // the mutable specifier to be compatible with MSVC. - MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr); + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr, AppertainsToDecl); // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update // the DeclEndLoc. @@ -1355,7 +1355,8 @@ DeclEndLoc = ESpecRange.getEnd(); // Parse attribute-specifier[opt]. - if (MaybeParseCXX11Attributes(Attr)) + // TODO: Correct? + if (MaybeParseCXX11Attributes(Attr, AppertainsToType)) DeclEndLoc = Attr.Range.getEnd(); // Parse OpenCL addr space attribute. @@ -1993,7 +1994,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); const auto WarnOnInit = [this, &CK] { Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 @@ -3244,7 +3245,7 @@ // Attributes here appertain to the array type. C++11 [expr.new]p5. ParsedAttributes Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToType); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*isStatic=*/false, /*isStar=*/false, diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -1358,7 +1358,7 @@ // If attributes exist before the method, parse them. ParsedAttributes methodAttrs(AttrFactory); MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), - methodAttrs); + methodAttrs, AppertainsToDecl); if (Tok.is(tok::code_completion)) { cutOffParsing(); @@ -1384,7 +1384,7 @@ if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), - methodAttrs); + methodAttrs, AppertainsToDecl); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result = Actions.ActOnMethodDeclaration( @@ -1418,7 +1418,7 @@ // If attributes exist before the argument name, parse them. // Regardless, collect all the attributes we've parsed so far. MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), - paramAttrs); + paramAttrs, AppertainsToDecl); ArgInfo.ArgAttrs = paramAttrs; // Code completion for the next piece of the selector. @@ -1501,7 +1501,7 @@ // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), - methodAttrs); + methodAttrs, AppertainsToDecl); if (KeyIdents.size() == 0) return nullptr; @@ -2218,7 +2218,7 @@ ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); while (!ObjCImplParsing.isFinished() && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { DeclGroupRef DG = DGP.get(); DeclsInGroup.append(DG.begin(), DG.end()); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2280,7 +2280,7 @@ // Here we expect to see some function declaration. if (AS == AS_none) { assert(TagType == DeclSpec::TST_unspecified); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); ParsingDeclSpec PDS(*this); Ptr = ParseExternalDeclaration(Attrs, &PDS); } else { diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1651,7 +1651,7 @@ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { // Parse the CXX11 style attribute. - ParseCXX11AttributeSpecifier(Attrs); + ParseCXX11AttributeSpecifier(Attrs, AppertainsToUnknown); } else if (Tok.is(tok::kw___attribute)) { ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -106,7 +106,11 @@ // at the start of the statement. Thus, we're not using MaybeParseAttributes // here because we don't want to allow arbitrary orderings. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs, /*MightBeObjCMessageSend*/ true); + // TODO: Oops -- don't know what to pass here! So we need to be able to do + // either-or and then process this further in + // ParseStatementOrDeclarationAfterAttributes(). Phew, this is complicated. + MaybeParseCXX11Attributes(Attrs, AppertainsToUnknown, + /*MightBeObjCMessageSend*/ true); if (getLangOpts().OpenCL) MaybeParseGNUAttributes(Attrs); @@ -223,6 +227,7 @@ isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; + DiagnoseAppertainsTo(Attrs, AppertainsToDecl); if (GNUAttributeLoc.isValid()) { DeclStart = GNUAttributeLoc; Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs, @@ -1119,7 +1124,8 @@ ConsumeToken(); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs, /*MightBeObjCMessageSend*/ true); + MaybeParseCXX11Attributes(attrs, AppertainsToUnknown, + /*MightBeObjCMessageSend*/ true); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { @@ -1925,7 +1931,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); SourceLocation EmptyInitStmtSemiLoc; @@ -1942,7 +1948,7 @@ ProhibitAttributes(attrs); IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation Loc = ConsumeToken(); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); ForRangeInfo.ColonLoc = ConsumeToken(); if (Tok.is(tok::l_brace)) @@ -2345,7 +2351,7 @@ } // Get the next statement. - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToUnknown); StmtResult S = ParseStatementOrDeclarationAfterAttributes( Stmts, StmtCtx, TrailingElseLoc, Attrs); @@ -2581,7 +2587,7 @@ Decl *ExceptionDecl = nullptr; if (Tok.isNot(tok::ellipsis)) { ParsedAttributesWithRange Attributes(AttrFactory); - MaybeParseCXX11Attributes(Attributes); + MaybeParseCXX11Attributes(Attributes, AppertainsToDecl); DeclSpec DS(AttrFactory); DS.takeAttributesFrom(Attributes); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -205,7 +205,7 @@ } ParsedAttributesWithRange prefixAttrs(AttrFactory); - MaybeParseCXX11Attributes(prefixAttrs); + MaybeParseCXX11Attributes(prefixAttrs, AppertainsToDecl); if (Tok.is(tok::kw_using)) { auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -722,7 +722,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); Result = ParseExternalDeclaration(attrs); // An empty Result might mean a line with ';' or some parsing error, ignore @@ -2293,7 +2293,7 @@ // FIXME: Support module import within __if_exists? while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(attrs, AppertainsToDecl); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); @@ -2381,7 +2381,7 @@ // We don't support any module attributes yet; just parse them and diagnose. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); ExpectAndConsumeSemi(diag::err_module_expected_semi); @@ -2447,7 +2447,7 @@ } ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseCXX11Attributes(Attrs, AppertainsToDecl); // We don't support any module import attributes yet. ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -8209,7 +8209,7 @@ // 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) + S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl) << AL << D->getLocation(); break; case ParsedAttr::AT_Interrupt: diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -489,7 +489,7 @@ // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is // needed for attributes in Attr.td that do not list any subjects. - S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt) + S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) << A << St->getBeginLoc(); return nullptr; } diff --git a/clang/test/Sema/annotate-type.c b/clang/test/Sema/annotate-type.c --- a/clang/test/Sema/annotate-type.c +++ b/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,5 @@ } // 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}} +void g([[clang::annotate_type("bar")]] int); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} diff --git a/clang/test/SemaCXX/annotate-type.cpp b/clang/test/SemaCXX/annotate-type.cpp --- 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 struct is_same { @@ -52,8 +49,8 @@ // 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 {} // 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}} void f4() { - for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} + for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3728,7 +3728,7 @@ 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"; @@ -3772,7 +3772,7 @@ if (!DeclSubjects.empty()) { OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, "; OS << "const Stmt *St) const override {\n"; - OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n"; + OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_stmt)\n"; OS << " << AL << St->getBeginLoc();\n"; OS << " return false;\n"; OS << "}\n\n"; @@ -4220,6 +4220,9 @@ OS << " /*IsStmt=*/"; OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr")) << ",\n"; + OS << " /*IsDecl=*/"; + OS << (!Attr.isSubClassOf("TypeAttr") && !Attr.isSubClassOf("StmtAttr")) + << ",\n"; OS << " /*IsKnownToGCC=*/"; OS << IsKnownToGCC(Attr) << ",\n"; OS << " /*IsSupportedByPragmaAttribute=*/";