diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 02736f2ee67fc..69ab645d49c23 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -473,6 +473,10 @@ Bug Fixes to Attribute Support structs, unions, and scoped enums) were not properly ignored, resulting in misleading warning messages. Now, such attribute annotations are correctly ignored. (`#61660 `_) +- GNU attributes preceding C++ style attributes on templates were not properly + handled, resulting in compilation error. This has been corrected to match the + behavior exhibited by GCC, which permits mixed ordering of GNU and C++ + attributes. Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 79f4ab683281e..d2e8a81ad521a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -210,7 +210,15 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( } ParsedAttributes prefixAttrs(AttrFactory); - MaybeParseCXX11Attributes(prefixAttrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + + // GNU attributes are applied to the declaration specification while the + // standard attributes are applied to the declaration. We parse the two + // attribute sets into different containters so we can apply them during + // the regular parsing process. + while (MaybeParseCXX11Attributes(prefixAttrs) || + MaybeParseGNUAttributes(DeclSpecAttrs)) + ; if (Tok.is(tok::kw_using)) { auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, @@ -223,6 +231,9 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( // Parse the declaration specifiers, stealing any diagnostics from // the template parameters. ParsingDeclSpec DS(*this, &DiagsFromTParams); + DS.SetRangeStart(DeclSpecAttrs.Range.getBegin()); + DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd()); + DS.takeAttributesFrom(DeclSpecAttrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, getDeclSpecContextFromDeclaratorContext(Context)); diff --git a/clang/test/Parser/attr-order.cpp b/clang/test/Parser/attr-order.cpp index 9a8490d819ee3..10bad38cac644 100644 --- a/clang/test/Parser/attr-order.cpp +++ b/clang/test/Parser/attr-order.cpp @@ -13,12 +13,21 @@ struct [[]] __attribute__((lockable)) [[]] __declspec(dllexport) H {}; // ok [[noreturn]] __declspec(dllexport) __attribute__((cdecl)) void b(); // ok [[]] [[noreturn]] __attribute__((cdecl)) __declspec(dllexport) void c(); // ok -// [[]] attributes before a declaration must be at the start of the line. __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(); + +__attribute__((cdecl)) [[noreturn]] __declspec(dllexport) void g(); // ok [[noreturn]] __attribute__((cdecl)) [[]] __declspec(dllexport) void h(); + +template +__attribute__((cdecl)) [[noreturn]] __declspec(dllexport) void i(); // ok + +template +[[]] [[noreturn]] __attribute__((cdecl)) __declspec(dllexport) void j(); // ok + +template +[[noreturn]] __declspec(dllexport) __attribute__((cdecl)) void k(); // ok