Skip to content

Commit b3a6d43

Browse files
authored
[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.
1 parent 52b18b4 commit b3a6d43

File tree

9 files changed

+106
-11
lines changed

9 files changed

+106
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ Bug Fixes to C++ Support
680680
- Improved parser recovery of invalid requirement expressions. In turn, this
681681
fixes crashes from follow-on processing of the invalid requirement. (#GH138820)
682682
- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255)
683+
- Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107)
683684
- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852)
684685

685686
Bug Fixes to AST Handling

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3081,13 +3081,16 @@ class Parser : public CodeCompletionHandler {
30813081
bool CouldBeBitField = false);
30823082
Decl *ParseHLSLBuffer(SourceLocation &DeclEnd);
30833083

3084-
void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
3084+
bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
3085+
bool AttrsParsed = false;
30853086
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
30863087
Tok.is(tok::l_square)) {
30873088
ParsedAttributes AttrsWithRange(AttrFactory);
30883089
ParseMicrosoftAttributes(AttrsWithRange);
3090+
AttrsParsed = !AttrsWithRange.empty();
30893091
Attrs.takeAllFrom(AttrsWithRange);
30903092
}
3093+
return AttrsParsed;
30913094
}
30923095
void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs);
30933096
void ParseMicrosoftAttributes(ParsedAttributes &Attrs);

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3096,11 +3096,24 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
30963096
}
30973097

30983098
ParsedAttributes DeclSpecAttrs(AttrFactory);
3099-
MaybeParseMicrosoftAttributes(DeclSpecAttrs);
3100-
31013099
// Hold late-parsed attributes so we can attach a Decl to them later.
31023100
LateParsedAttrList CommonLateParsedAttrs;
31033101

3102+
while (MaybeParseCXX11Attributes(DeclAttrs) ||
3103+
MaybeParseGNUAttributes(DeclSpecAttrs, &CommonLateParsedAttrs) ||
3104+
MaybeParseMicrosoftAttributes(DeclSpecAttrs))
3105+
;
3106+
3107+
SourceLocation DeclStart;
3108+
if (DeclAttrs.Range.isValid()) {
3109+
DeclStart = DeclSpecAttrs.Range.isInvalid()
3110+
? DeclAttrs.Range.getBegin()
3111+
: std::min(DeclAttrs.Range.getBegin(),
3112+
DeclSpecAttrs.Range.getBegin());
3113+
} else {
3114+
DeclStart = DeclSpecAttrs.Range.getBegin();
3115+
}
3116+
31043117
// decl-specifier-seq:
31053118
// Parse the common declaration-specifiers piece.
31063119
ParsingDeclSpec DS(*this, TemplateDiags);
@@ -3128,6 +3141,9 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
31283141
// Turn off colon protection that was set for declspec.
31293142
X.restore();
31303143

3144+
if (DeclStart.isValid())
3145+
DS.SetRangeStart(DeclStart);
3146+
31313147
// If we had a free-standing type definition with a missing semicolon, we
31323148
// may get this far before the problem becomes obvious.
31333149
if (DS.hasTagDefinition() &&

clang/lib/Parse/ParseStmt.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
235235
}
236236

237237
default: {
238+
if (getLangOpts().CPlusPlus && MaybeParseCXX11Attributes(CXX11Attrs, true))
239+
goto Retry;
240+
238241
bool HaveAttrs = !CXX11Attrs.empty() || !GNUAttrs.empty();
239242
auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
240243
bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) &&
@@ -260,11 +263,11 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
260263
GNUAttrs);
261264
}
262265
if (CXX11Attrs.Range.getBegin().isValid()) {
263-
// The caller must guarantee that the CXX11Attrs appear before the
264-
// GNUAttrs, and we rely on that here.
265-
assert(GNUAttrs.Range.getBegin().isInvalid() ||
266-
GNUAttrs.Range.getBegin() > CXX11Attrs.Range.getBegin());
267-
DeclStart = CXX11Attrs.Range.getBegin();
266+
// Order of C++11 and GNU attributes is may be arbitrary.
267+
DeclStart = GNUAttrs.Range.getBegin().isInvalid()
268+
? CXX11Attrs.Range.getBegin()
269+
: std::min(CXX11Attrs.Range.getBegin(),
270+
GNUAttrs.Range.getBegin());
268271
} else if (GNUAttrs.Range.getBegin().isValid())
269272
DeclStart = GNUAttrs.Range.getBegin();
270273
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);

clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,18 @@ int main()
670670
// CHECK-NEXT: },
671671
// CHECK-NEXT: "range": {
672672
// CHECK-NEXT: "begin": {
673-
// CHECK-NEXT: "offset": 404,
674-
// CHECK-NEXT: "col": 16,
675-
// CHECK-NEXT: "tokLen": 9
673+
// CHECK-NEXT: "spellingLoc": {
674+
// CHECK-NEXT: "offset": 123,
675+
// CHECK-NEXT: "line": 4,
676+
// CHECK-NEXT: "col": 20,
677+
// CHECK-NEXT: "tokLen": 1
678+
// CHECK-NEXT: },
679+
// CHECK-NEXT: "expansionLoc": {
680+
// CHECK-NEXT: "offset": 393,
681+
// CHECK-NEXT: "line": 17,
682+
// CHECK-NEXT: "col": 5,
683+
// CHECK-NEXT: "tokLen": 10
684+
// CHECK-NEXT: }
676685
// CHECK-NEXT: },
677686
// CHECK-NEXT: "end": {
678687
// CHECK-NEXT: "offset": 481,

clang/test/Parser/c2x-alignas.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,26 @@
22

33
_Alignas(int) struct c1; // expected-warning {{'_Alignas' attribute ignored}}
44
alignas(int) struct c1; // expected-warning {{'alignas' attribute ignored}}
5+
6+
7+
__attribute__(()) [[]] alignas(int) int a; // expected-none TODO: actually this line should be an error
8+
__attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}}
9+
__attribute__(()) alignas(int) int c; // expected-none
10+
[[]] __attribute__(()) alignas(int) int d; // expected-none
11+
alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}}
12+
13+
struct C1 {
14+
__attribute__(()) [[]] alignas(int) int a; // expected-error {{an attribute list cannot appear here}}
15+
__attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}}
16+
__attribute__(()) alignas(int) int c; // expected-none
17+
[[]] __attribute__(()) alignas(int) int d; // expected-none
18+
alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}}
19+
};
20+
21+
void fn_with_decl() {
22+
__attribute__(()) [[]] alignas(int) int a; // expected-error {{an attribute list cannot appear here}}
23+
__attribute__(()) alignas(int) [[]] int b; // expected-error {{an attribute list cannot appear here}}
24+
__attribute__(()) alignas(int) int c; // expected-none
25+
[[]] __attribute__(()) alignas(int) int d; // expected-none
26+
alignas(int) [[]] __attribute__(()) int e; // expected-error {{an attribute list cannot appear here}}
27+
}

clang/test/Parser/cxx0x-attributes.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,30 @@ namespace test_misplacement {
7272
[[]] enum E2 { }; //expected-error{{misplaced attributes}}
7373
}
7474

75+
__attribute__(()) alignas(int) int xx; // expected-none
76+
__attribute__(()) alignas(int) [[]] int yy; // expected-none
77+
[[]] __attribute__(()) alignas(int) int zz; // expected-none
78+
alignas(int) [[]] __attribute__(()) int aa; // expected-none
79+
[[]] alignas(int) __attribute__(()) int bb; // expected-none
80+
__attribute__(()) [[]] alignas(int) int cc; // expected-none
81+
82+
class C1 {
83+
__attribute__(()) alignas(int) int x; // expected-none
84+
__attribute__(()) alignas(int) [[]] int y; // expected-none
85+
[[]] __attribute__(()) alignas(int) int z; // expected-none
86+
alignas(int) [[]] __attribute__(()) int a; // expected-none
87+
[[]] alignas(int) __attribute__(()) int b; // expected-none
88+
__attribute__(()) [[]] alignas(int) int c; // expected-none
89+
};
90+
91+
void fn_with_decl() {
92+
__attribute__(()) alignas(int) int x; // expected-none
93+
__attribute__(()) alignas(int) [[]] int y; // expected-none
94+
[[]] __attribute__(()) alignas(int) int z; // expected-none
95+
alignas(int) [[]] __attribute__(()) int a; // expected-none
96+
[[]] alignas(int) __attribute__(()) int b; // expected-none
97+
__attribute__(()) [[]] alignas(int) int c; // expected-none
98+
}
7599
// Checks attributes placed at wrong syntactic locations of class specifiers.
76100
class [[]] [[]]
77101
attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Verify that we can parse a simple CUDA file with different attributes order.
2+
// RUN: %clang_cc1 "-triple" "nvptx-nvidia-cuda" -fsyntax-only -verify %s
3+
// expected-no-diagnostics
4+
#include "Inputs/cuda.h"
5+
6+
struct alignas(16) float4 {
7+
float x, y, z, w;
8+
};
9+
10+
__attribute__((device)) float func() {
11+
__shared__ alignas(alignof(float4)) float As[4][4]; // Both combinations
12+
alignas(alignof(float4)) __shared__ float Bs[4][4]; // must be legal
13+
14+
return As[0][0] + Bs[0][0];
15+
}

clang/test/SemaCXX/warn-thread-safety-analysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2464,6 +2464,7 @@ class Foo {
24642464
// expected-warning {{declaration does not declare anything}}
24652465
exclusive_locks_required(a))); // \
24662466
// expected-warning {{attribute exclusive_locks_required ignored}}
2467+
24672468
};
24682469

24692470
} // end namespace WarnNoDecl

0 commit comments

Comments
 (0)