Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -411,6 +411,9 @@ 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 + behaviour exhibited by GCC. Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ Index: clang/lib/Parse/ParseTemplate.cpp =================================================================== --- clang/lib/Parse/ParseTemplate.cpp +++ clang/lib/Parse/ParseTemplate.cpp @@ -210,7 +210,15 @@ } 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 @@ // 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)); Index: clang/test/Parser/attr-order.cpp =================================================================== --- clang/test/Parser/attr-order.cpp +++ clang/test/Parser/attr-order.cpp @@ -13,12 +13,21 @@ [[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