Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -1603,14 +1603,15 @@ //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributes &Attrs, + ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS = nullptr); bool isDeclarationAfterDeclarator(); bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); - DeclGroupPtrTy - ParseDeclarationOrFunctionDefinition(ParsedAttributes &Attrs, - ParsingDeclSpec *DS = nullptr, - AccessSpecifier AS = AS_none); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, + ParsingDeclSpec *DS = nullptr, AccessSpecifier AS = AS_none); DeclGroupPtrTy ParseDeclOrFunctionDefInternal(ParsedAttributes &Attrs, + ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec &DS, AccessSpecifier AS); @@ -1625,7 +1626,8 @@ // Objective-C External Declarations void MaybeSkipAttributes(tok::ObjCKeywordKind Kind); - DeclGroupPtrTy ParseObjCAtDirectives(ParsedAttributes &Attrs); + DeclGroupPtrTy ParseObjCAtDirectives(ParsedAttributes &Attrs, + ParsedAttributes &DeclSpecAttrs); DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParsedAttributes &prefixAttrs); Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -256,7 +256,8 @@ Tok.isNot(tok::eof)) { ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ParseExternalDeclaration(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); } // The caller is what called check -- we are simply calling @@ -359,6 +360,7 @@ ParsedAttributes DeclAttrs(AttrFactory); MaybeParseCXX11Attributes(DeclAttrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" @@ -367,7 +369,7 @@ DS.SetRangeEnd(SourceLocation()); // ... but anyway remember that such an "extern" was seen. DS.setExternInLinkageSpec(true); - ParseExternalDeclaration(DeclAttrs, &DS); + ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs, &DS); return LinkageSpec ? Actions.ActOnFinishLinkageSpecification( getCurScope(), LinkageSpec, SourceLocation()) : nullptr; @@ -409,7 +411,7 @@ default: ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ParseExternalDeclaration(Attrs); + ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); continue; } @@ -441,7 +443,8 @@ // FIXME: Factor out a ParseExternalDeclarationWithAttrs. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ParseExternalDeclaration(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl, SourceLocation()); } @@ -460,7 +463,8 @@ Tok.isNot(tok::eof)) { ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ParseExternalDeclaration(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); } T.consumeClose(); Index: clang/lib/Parse/ParseHLSL.cpp =================================================================== --- clang/lib/Parse/ParseHLSL.cpp +++ clang/lib/Parse/ParseHLSL.cpp @@ -78,8 +78,9 @@ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // FIXME: support attribute on constants inside cbuffer/tbuffer. ParsedAttributes Attrs(AttrFactory); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); - DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs); + DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer, *this)) { T.skipToEnd(); Index: clang/lib/Parse/ParseObjc.cpp =================================================================== --- clang/lib/Parse/ParseObjc.cpp +++ clang/lib/Parse/ParseObjc.cpp @@ -45,7 +45,11 @@ /// [OBJC] objc-protocol-definition /// [OBJC] objc-method-definition /// [OBJC] '@' 'end' -Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives(ParsedAttributes &Attrs) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtDirectives(ParsedAttributes &Attrs, + ParsedAttributes &DeclSpecAttrs) { + Attrs.takeAllFrom(DeclSpecAttrs); + SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { @@ -54,6 +58,17 @@ return nullptr; } + switch (Tok.getObjCKeywordID()) { + case tok::objc_interface: + case tok::objc_protocol: + case tok::objc_implementation: + break; + default: + for (const auto &PA : Attrs) + if (PA.isGNUAttribute()) + Diag(Tok.getLocation(), diag::err_objc_unexpected_attr); + } + Decl *SingleDecl = nullptr; switch (Tok.getObjCKeywordID()) { case tok::objc_class: @@ -651,6 +666,7 @@ break; ParsedAttributes EmptyAttrs(AttrFactory); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); // Since we call ParseDeclarationOrFunctionDefinition() instead of // ParseExternalDeclaration() below (so that this doesn't parse nested @@ -664,7 +680,7 @@ } allTUVariables.push_back( - ParseDeclarationOrFunctionDefinition(EmptyAttrs)); + ParseDeclarationOrFunctionDefinition(EmptyAttrs, EmptyDeclSpecAttrs)); continue; } @@ -2225,7 +2241,9 @@ while (!ObjCImplParsing.isFinished() && !isEofOrEom()) { ParsedAttributes attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + if (DeclGroupPtrTy DGP = + ParseExternalDeclaration(attrs, EmptyDeclSpecAttrs)) { DeclGroupRef DG = DGP.get(); DeclsInGroup.append(DG.begin(), DG.end()); } Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -1994,6 +1994,8 @@ ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + SourceLocation Loc; OpenMPDirectiveKind DKind; if (Delayed) { @@ -2247,7 +2249,7 @@ assert(TagType == DeclSpec::TST_unspecified); MaybeParseCXX11Attributes(Attrs); ParsingDeclSpec PDS(*this); - Ptr = ParseExternalDeclaration(Attrs, &PDS); + Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS); } else { Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -732,9 +732,12 @@ } ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + while (MaybeParseCXX11Attributes(attrs) || + MaybeParseGNUAttributes(DeclSpecAttrs)) + ; - Result = ParseExternalDeclaration(attrs); + Result = ParseExternalDeclaration(attrs, DeclSpecAttrs); // An empty Result might mean a line with ';' or some parsing error, ignore // it. if (Result) { @@ -777,8 +780,10 @@ /// /// [Modules-TS] module-import-declaration /// -Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, - ParsingDeclSpec *DS) { +Parser::DeclGroupPtrTy +Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, + ParsedAttributes &DeclSpecAttrs, + ParsingDeclSpec *DS) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -866,7 +871,7 @@ // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseExternalDeclaration(Attrs); + return ParseExternalDeclaration(Attrs, DeclSpecAttrs); } case tok::kw_asm: { ProhibitAttributes(Attrs); @@ -894,7 +899,7 @@ break; } case tok::at: - return ParseObjCAtDirectives(Attrs); + return ParseObjCAtDirectives(Attrs, DeclSpecAttrs); case tok::minus: case tok::plus: if (!getLangOpts().ObjC) { @@ -942,18 +947,16 @@ // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; - ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, - EmptyDeclSpecAttrs); + DeclSpecAttrs); } case tok::kw_cbuffer: case tok::kw_tbuffer: if (getLangOpts().HLSL) { SourceLocation DeclEnd; - ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, - EmptyDeclSpecAttrs); + DeclSpecAttrs); } goto dont_know; @@ -964,9 +967,8 @@ Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 0; SourceLocation DeclEnd; - ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, - EmptyDeclSpecAttrs); + DeclSpecAttrs); } goto dont_know; @@ -977,9 +979,8 @@ // Inline namespaces. Allowed as an extension even in C++03. if (NextKind == tok::kw_namespace) { SourceLocation DeclEnd; - ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, - EmptyDeclSpecAttrs); + DeclSpecAttrs); } // Parse (then ignore) 'inline' prior to a template instantiation. This is @@ -988,9 +989,8 @@ Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 1; SourceLocation DeclEnd; - ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, - EmptyDeclSpecAttrs); + DeclSpecAttrs); } } goto dont_know; @@ -1026,7 +1026,7 @@ return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(Attrs, DS); + return ParseDeclarationOrFunctionDefinition(Attrs, DeclSpecAttrs, DS); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -1091,7 +1091,12 @@ /// [OMP] allocate-directive [TODO] /// Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( - ParsedAttributes &Attrs, ParsingDeclSpec &DS, AccessSpecifier AS) { + ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, + ParsingDeclSpec &DS, AccessSpecifier AS) { + DS.SetRangeStart(DeclSpecAttrs.Range.getBegin()); + DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd()); + DS.takeAttributesFrom(DeclSpecAttrs); + MaybeParseMicrosoftAttributes(DS.getAttributes()); // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, @@ -1190,9 +1195,10 @@ } Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( - ParsedAttributes &Attrs, ParsingDeclSpec *DS, AccessSpecifier AS) { + ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, + ParsingDeclSpec *DS, AccessSpecifier AS) { if (DS) { - return ParseDeclOrFunctionDefInternal(Attrs, *DS, AS); + return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, *DS, AS); } else { ParsingDeclSpec PDS(*this); // Must temporarily exit the objective-c container scope for @@ -1200,7 +1206,7 @@ // afterwards. ObjCDeclContextSwitch ObjCDC(*this); - return ParseDeclOrFunctionDefInternal(Attrs, PDS, AS); + return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, PDS, AS); } } @@ -2342,7 +2348,8 @@ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); } Index: clang/test/Parser/attr-order.cpp =================================================================== --- clang/test/Parser/attr-order.cpp +++ clang/test/Parser/attr-order.cpp @@ -17,8 +17,8 @@ __declspec(dllexport) [[noreturn]] __attribute__((cdecl)) void d(); // expected-error {{an attribute list cannot appear here}} __declspec(dllexport) __attribute__((cdecl)) [[noreturn]] void e(); // expected-error {{an attribute list cannot appear here}} __attribute__((cdecl)) __declspec(dllexport) [[noreturn]] void f(); // expected-error {{an attribute list cannot appear here}} -__attribute__((cdecl)) [[noreturn]] __declspec(dllexport) void g(); // expected-error {{an attribute list cannot appear here}} +__attribute__((cdecl)) [[noreturn]] __declspec(dllexport) void g(); [[noreturn]] __attribute__((cdecl)) -[[]] // expected-error {{an attribute list cannot appear here}} +[[]] __declspec(dllexport) void h(); Index: clang/test/Parser/cxx-attributes.cpp =================================================================== --- clang/test/Parser/cxx-attributes.cpp +++ clang/test/Parser/cxx-attributes.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// GH#58229 - rejects-valid +__attribute__((__visibility__("default"))) [[nodiscard]] int f(); +[[nodiscard]] __attribute__((__visibility__("default"))) int f(); + class c { virtual void f1(const char* a, ...) __attribute__ (( __format__(__printf__,2,3) )) = 0; Index: clang/test/SemaCXX/attr-unavailable.cpp =================================================================== --- clang/test/SemaCXX/attr-unavailable.cpp +++ clang/test/SemaCXX/attr-unavailable.cpp @@ -42,18 +42,18 @@ // delayed process for 'deprecated'. // and enum DeprecatedEnum { DE_A, DE_B } __attribute__((deprecated)); // expected-note {{'DeprecatedEnum' has been explicitly marked deprecated here}} -__attribute__((deprecated)) typedef enum DeprecatedEnum DeprecatedEnum; typedef enum DeprecatedEnum AnotherDeprecatedEnum; // expected-warning {{'DeprecatedEnum' is deprecated}} +__attribute__((deprecated)) typedef enum DeprecatedEnum DeprecatedEnum; __attribute__((deprecated)) DeprecatedEnum testDeprecated(DeprecatedEnum X) { return X; } enum UnavailableEnum { UE_A, UE_B } __attribute__((unavailable)); // expected-note {{'UnavailableEnum' has been explicitly marked unavailable here}} -__attribute__((unavailable)) typedef enum UnavailableEnum UnavailableEnum; typedef enum UnavailableEnum AnotherUnavailableEnum; // expected-error {{'UnavailableEnum' is unavailable}} + // - +__attribute__((unavailable)) typedef enum UnavailableEnum UnavailableEnum; __attribute__((unavailable)) UnavailableEnum testUnavailable(UnavailableEnum X) { return X; } Index: clang/unittests/Tooling/SourceCodeTest.cpp =================================================================== --- clang/unittests/Tooling/SourceCodeTest.cpp +++ clang/unittests/Tooling/SourceCodeTest.cpp @@ -247,14 +247,25 @@ // Includes attributes. Visitor.runOverAnnotated(R"cpp( - #define ATTR __attribute__((deprecated("message"))) - $r[[ATTR + $r[[__attribute__((deprecated("message"))) int x;]])cpp"); // Includes attributes and comments together. Visitor.runOverAnnotated(R"cpp( - #define ATTR __attribute__((deprecated("message"))) - $r[[ATTR + $r[[__attribute__((deprecated("message"))) + // Comment. + int x;]])cpp"); + + // Includes attributes through macro expansion. + Visitor.runOverAnnotated(R"cpp( + #define MACRO_EXPANSION __attribute__((deprecated("message"))) + $r[[MACRO_EXPANSION + int x;]])cpp"); + + // Includes attributes through macro expansion with comments. + Visitor.runOverAnnotated(R"cpp( + #define MACRO_EXPANSION __attribute__((deprecated("message"))) + $r[[MACRO_EXPANSION // Comment. int x;]])cpp"); } @@ -402,14 +413,25 @@ // Includes attributes. Visit(R"cpp( - #define ATTR __attribute__((deprecated("message"))) - $r[[ATTR + $r[[__attribute__((deprecated("message"))) int x;]])cpp"); // Includes attributes and comments together. Visit(R"cpp( - #define ATTR __attribute__((deprecated("message"))) - $r[[ATTR + $r[[__attribute__((deprecated("message"))) + // Comment. + int x;]])cpp"); + + // Includes attributes through macro expansion. + Visitor.runOverAnnotated(R"cpp( + #define MACRO_EXPANSION __attribute__((deprecated("message"))) + $r[[MACRO_EXPANSION + int x;]])cpp"); + + // Includes attributes through macro expansion with comments. + Visitor.runOverAnnotated(R"cpp( + #define MACRO_EXPANSION __attribute__((deprecated("message"))) + $r[[MACRO_EXPANSION // Comment. int x;]])cpp"); }