Skip to content

Commit

Permalink
[Clang][Parser] Accept GNU attributes preceding C++ attributes on tem…
Browse files Browse the repository at this point in the history
…plates

Clang was rejecting valid code where GNU style attributes preceded C++ style
attributes in template declarations as follows:

template<int a>
__attribute__((deprecated("oh no!"))) [[deprecated("oh no!")]] void foo();

This PR fixes the bug.

Differential Revision: https://reviews.llvm.org/D151837
  • Loading branch information
elizabethandrews committed Jun 2, 2023
1 parent 6d8f889 commit cecd847
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://github.com/llvm/llvm-project/issues/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
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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));
Expand Down
13 changes: 11 additions & 2 deletions clang/test/Parser/attr-order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <int a>
__attribute__((cdecl)) [[noreturn]] __declspec(dllexport) void i(); // ok

template <int a>
[[]] [[noreturn]] __attribute__((cdecl)) __declspec(dllexport) void j(); // ok

template <int a>
[[noreturn]] __declspec(dllexport) __attribute__((cdecl)) void k(); // ok

0 comments on commit cecd847

Please sign in to comment.