diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ccd9f70aa875d..09079506b4679 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -474,6 +474,7 @@ Bug Fixes to C++ Support - Clang no longer crashes when establishing subsumption between some constraint expressions. (#GH122581) - Clang now issues an error when placement new is used to modify a const-qualified variable in a ``constexpr`` function. (#GH131432) +- Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107) - Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806) Bug Fixes to AST Handling diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 53da6269a3b11..d6a7a46133f78 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3062,13 +3062,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 51fe0663a8d1a..8fe149b375d25 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3035,11 +3035,14 @@ 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)) + ; + // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index e8ec140fbe3e5..1fc9d34a8ca27 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-color.cpp b/clang/test/AST/ast-dump-color.cpp index 87797f6bffc5b..2bd9ab7c3c841 100644 --- a/clang/test/AST/ast-dump-color.cpp +++ b/clang/test/AST/ast-dump-color.cpp @@ -91,7 +91,7 @@ struct Invalid { //CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'Mutex'[[RESET]] non_odr_use_unevaluated{{$}} //CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] struct[[CYAN]] Invalid[[RESET]] definition //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit referenced struct[[CYAN]] Invalid[[RESET]] -//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:3[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]] +//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:29[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]] //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:37[[RESET]], [[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]col:42[[RESET]] invalid [[Green]]'int'[[RESET]] //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[BLUE]]NoInlineAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:18[[RESET]]> //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit used constexpr[[CYAN]] Invalid[[RESET]] [[Green]]'void () noexcept'[[RESET]] inline diff --git a/clang/test/Index/annotate-attribute.cpp b/clang/test/Index/annotate-attribute.cpp index bf415fc8fe64d..6b5b0f1eab7d4 100644 --- a/clang/test/Index/annotate-attribute.cpp +++ b/clang/test/Index/annotate-attribute.cpp @@ -24,7 +24,7 @@ int templateFunction(T value) __attribute__((annotate("works"))); // CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2] // CHECK-NEXT: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8] -// CHECK-NEXT: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60] +// CHECK-NEXT: CXXMethod=aMethod:5:51 Extent=[5:46 - 5:60] // CHECK-NEXT: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43] // CHECK-NEXT: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43] // CHECK-NEXT: attribute(annotate)=works Extent=[7:23 - 7:40] 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 fad3010c98b9c..c01adaccbd6b5 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 different 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 ac3ca5e0c12a8..ed7821b2affe4 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -2434,10 +2434,10 @@ class Foo { namespace WarnNoDecl { class Foo { - void foo(int a); __attribute__(( // \ - // expected-warning {{declaration does not declare anything}} - exclusive_locks_required(a))); // \ - // expected-warning {{attribute exclusive_locks_required ignored}} + void foo(int a); __attribute__(( + exclusive_locks_required(a))); // expected-warning {{declaration does not declare anything}} \ + // expected-warning {{attribute exclusive_locks_required ignored}} + }; } // end namespace WarnNoDecl