Author: Denis.G Date: 2025-05-09T14:10:18-04:00 New Revision: b3a6d434a7051d879718ef92a4fafd1697759aed
URL: https://github.com/llvm/llvm-project/commit/b3a6d434a7051d879718ef92a4fafd1697759aed DIFF: https://github.com/llvm/llvm-project/commit/b3a6d434a7051d879718ef92a4fafd1697759aed.diff LOG: [Clang] Allow parsing arbitrary order of attributes for declarations (#133107) Enable parsing alignas attribute after GNU attributes, before ParseDeclaration This might be useful for cuda code where __shared__ and other specificators may be mixed with align. I'd be glad to see if there are any better places or other technique to process this attribute without interrupting current flow of parsing. Added: clang/test/SemaCUDA/cuda-attr-order.cu Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Parse/Parser.h clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Parse/ParseStmt.cpp clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp clang/test/Parser/c2x-alignas.c clang/test/Parser/cxx0x-attributes.cpp clang/test/SemaCXX/warn-thread-safety-analysis.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cd452179a6555..9ca1c1c79b20a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -680,6 +680,7 @@ Bug Fixes to C++ Support - Improved parser recovery of invalid requirement expressions. In turn, this fixes crashes from follow-on processing of the invalid requirement. (#GH138820) - Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255) +- Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107) - Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852) Bug Fixes to AST Handling diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e0b8850493b49..d2fec2b7a6462 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3081,13 +3081,16 @@ class Parser : public CodeCompletionHandler { bool CouldBeBitField = false); Decl *ParseHLSLBuffer(SourceLocation &DeclEnd); - void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) { + bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) { + bool AttrsParsed = false; if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) && Tok.is(tok::l_square)) { ParsedAttributes AttrsWithRange(AttrFactory); ParseMicrosoftAttributes(AttrsWithRange); + AttrsParsed = !AttrsWithRange.empty(); Attrs.takeAllFrom(AttrsWithRange); } + return AttrsParsed; } void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs); void ParseMicrosoftAttributes(ParsedAttributes &Attrs); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index ec080bf9dc97d..2aa7a5b1a0cb1 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3096,11 +3096,24 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( } ParsedAttributes DeclSpecAttrs(AttrFactory); - MaybeParseMicrosoftAttributes(DeclSpecAttrs); - // Hold late-parsed attributes so we can attach a Decl to them later. LateParsedAttrList CommonLateParsedAttrs; + while (MaybeParseCXX11Attributes(DeclAttrs) || + MaybeParseGNUAttributes(DeclSpecAttrs, &CommonLateParsedAttrs) || + MaybeParseMicrosoftAttributes(DeclSpecAttrs)) + ; + + SourceLocation DeclStart; + if (DeclAttrs.Range.isValid()) { + DeclStart = DeclSpecAttrs.Range.isInvalid() + ? DeclAttrs.Range.getBegin() + : std::min(DeclAttrs.Range.getBegin(), + DeclSpecAttrs.Range.getBegin()); + } else { + DeclStart = DeclSpecAttrs.Range.getBegin(); + } + // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); @@ -3128,6 +3141,9 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( // Turn off colon protection that was set for declspec. X.restore(); + if (DeclStart.isValid()) + DS.SetRangeStart(DeclStart); + // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. if (DS.hasTagDefinition() && diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 546e524932f5e..2794a5834dce9 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -235,6 +235,9 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( } default: { + if (getLangOpts().CPlusPlus && MaybeParseCXX11Attributes(CXX11Attrs, true)) + goto Retry; + bool HaveAttrs = !CXX11Attrs.empty() || !GNUAttrs.empty(); auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) && @@ -260,11 +263,11 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( GNUAttrs); } if (CXX11Attrs.Range.getBegin().isValid()) { - // The caller must guarantee that the CXX11Attrs appear before the - // GNUAttrs, and we rely on that here. - assert(GNUAttrs.Range.getBegin().isInvalid() || - GNUAttrs.Range.getBegin() > CXX11Attrs.Range.getBegin()); - DeclStart = CXX11Attrs.Range.getBegin(); + // Order of C++11 and GNU attributes is may be arbitrary. + DeclStart = GNUAttrs.Range.getBegin().isInvalid() + ? CXX11Attrs.Range.getBegin() + : std::min(CXX11Attrs.Range.getBegin(), + GNUAttrs.Range.getBegin()); } else if (GNUAttrs.Range.getBegin().isValid()) DeclStart = GNUAttrs.Range.getBegin(); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); diff --git a/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp b/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp index b80c1e1d77140..cc9a82cb7bfff 100644 --- a/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp +++ b/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp @@ -670,9 +670,18 @@ int main() // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": 404, -// CHECK-NEXT: "col": 16, -// CHECK-NEXT: "tokLen": 9 +// CHECK-NEXT: "spellingLoc": { +// CHECK-NEXT: "offset": 123, +// CHECK-NEXT: "line": 4, +// CHECK-NEXT: "col": 20, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "expansionLoc": { +// CHECK-NEXT: "offset": 393, +// CHECK-NEXT: "line": 17, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 10 +// CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "end": { // CHECK-NEXT: "offset": 481, diff --git a/clang/test/Parser/c2x-alignas.c b/clang/test/Parser/c2x-alignas.c index 1658cb1c74496..d1b0726098652 100644 --- a/clang/test/Parser/c2x-alignas.c +++ b/clang/test/Parser/c2x-alignas.c @@ -2,3 +2,26 @@ _Alignas(int) struct c1; // expected-warning {{'_Alignas' attribute ignored}} alignas(int) struct c1; // expected-warning {{'alignas' attribute ignored}} + + +__attribute__(()) [[]] alignas(int) int a; // expected-none TODO: actually this line should be an error +__attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}} +__attribute__(()) alignas(int) int c; // expected-none +[[]] __attribute__(()) alignas(int) int d; // expected-none +alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}} + +struct C1 { + __attribute__(()) [[]] alignas(int) int a; // expected-error {{an attribute list cannot appear here}} + __attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}} + __attribute__(()) alignas(int) int c; // expected-none + [[]] __attribute__(()) alignas(int) int d; // expected-none + alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}} +}; + +void fn_with_decl() { + __attribute__(()) [[]] alignas(int) int a; // expected-error {{an attribute list cannot appear here}} + __attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}} + __attribute__(()) alignas(int) int c; // expected-none + [[]] __attribute__(()) alignas(int) int d; // expected-none + alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}} +} diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index 6f2db3a655a95..6e0904e94fecc 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -72,6 +72,30 @@ namespace test_misplacement { [[]] enum E2 { }; //expected-error{{misplaced attributes}} } +__attribute__(()) alignas(int) int xx; // expected-none +__attribute__(()) alignas(int) [[]] int yy; // expected-none +[[]] __attribute__(()) alignas(int) int zz; // expected-none +alignas(int) [[]] __attribute__(()) int aa; // expected-none +[[]] alignas(int) __attribute__(()) int bb; // expected-none +__attribute__(()) [[]] alignas(int) int cc; // expected-none + +class C1 { + __attribute__(()) alignas(int) int x; // expected-none + __attribute__(()) alignas(int) [[]] int y; // expected-none + [[]] __attribute__(()) alignas(int) int z; // expected-none + alignas(int) [[]] __attribute__(()) int a; // expected-none + [[]] alignas(int) __attribute__(()) int b; // expected-none + __attribute__(()) [[]] alignas(int) int c; // expected-none +}; + +void fn_with_decl() { + __attribute__(()) alignas(int) int x; // expected-none + __attribute__(()) alignas(int) [[]] int y; // expected-none + [[]] __attribute__(()) alignas(int) int z; // expected-none + alignas(int) [[]] __attribute__(()) int a; // expected-none + [[]] alignas(int) __attribute__(()) int b; // expected-none + __attribute__(()) [[]] alignas(int) int c; // expected-none +} // Checks attributes placed at wrong syntactic locations of class specifiers. class [[]] [[]] attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}} diff --git a/clang/test/SemaCUDA/cuda-attr-order.cu b/clang/test/SemaCUDA/cuda-attr-order.cu new file mode 100644 index 0000000000000..d3bf5b014d1c6 --- /dev/null +++ b/clang/test/SemaCUDA/cuda-attr-order.cu @@ -0,0 +1,15 @@ +// Verify that we can parse a simple CUDA file with diff erent attributes order. +// RUN: %clang_cc1 "-triple" "nvptx-nvidia-cuda" -fsyntax-only -verify %s +// expected-no-diagnostics +#include "Inputs/cuda.h" + +struct alignas(16) float4 { + float x, y, z, w; +}; + +__attribute__((device)) float func() { + __shared__ alignas(alignof(float4)) float As[4][4]; // Both combinations + alignas(alignof(float4)) __shared__ float Bs[4][4]; // must be legal + + return As[0][0] + Bs[0][0]; +} diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 4c17294d11e79..5382023318f28 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -2464,6 +2464,7 @@ class Foo { // expected-warning {{declaration does not declare anything}} exclusive_locks_required(a))); // \ // expected-warning {{attribute exclusive_locks_required ignored}} + }; } // end namespace WarnNoDecl _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits