diff options
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 2 | ||||
-rw-r--r-- | clang/test/Parser/MicrosoftExtensions.c | 7 | ||||
-rw-r--r-- | clang/test/Parser/MicrosoftExtensions.cpp | 9 |
5 files changed, 63 insertions, 0 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f4487c1d9d4..b0c116cfceb 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1979,6 +1979,9 @@ private: void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, SourceLocation CorrectLocation); + void handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, Sema::TagUseKind TUK); + void ProhibitAttributes(ParsedAttributesWithRange &attrs) { if (!attrs.Range.isValid()) return; DiagnoseProhibitedAttributes(attrs); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 8f4afdf9034..c64421793c6 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1360,6 +1360,46 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) { } } +// As an exception to the rule, __declspec(align(...)) before the +// class-key affects the type instead of the variable. +void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, + Sema::TagUseKind TUK) { + if (TUK == Sema::TUK_Reference) + return; + + ParsedAttributes &PA = DS.getAttributes(); + AttributeList *AL = PA.getList(); + AttributeList *Prev = nullptr; + while (AL) { + AttributeList *Next = AL->getNext(); + + // We only consider attributes using the appropriate '__declspec' spelling, + // this behavior doesn't extend to any other spellings. + if (AL->getKind() == AttributeList::AT_Aligned && + AL->isDeclspecAttribute()) { + // Stitch the attribute into the tag's attribute list. + AL->setNext(nullptr); + Attrs.add(AL); + + // Remove the attribute from the variable's attribute list. + if (Prev) { + // Set the last variable attribute's next attribute to be the attribute + // after the current one. + Prev->setNext(Next); + } else { + // Removing the head of the list requires us to reset the head to the + // next attribute. + PA.set(Next); + } + } else { + Prev = AL; + } + + AL = Next; + } +} + /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the @@ -3851,6 +3891,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } + handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + bool Owned = false; bool IsDependent = false; const char *PrevSpec = nullptr; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index c74b02877c9..11934c4df68 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1692,6 +1692,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TParams = MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); + handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, diff --git a/clang/test/Parser/MicrosoftExtensions.c b/clang/test/Parser/MicrosoftExtensions.c index 83e0921f8b5..40a9510d6e2 100644 --- a/clang/test/Parser/MicrosoftExtensions.c +++ b/clang/test/Parser/MicrosoftExtensions.c @@ -93,3 +93,10 @@ typedef void(*ignored_quals_dummy3)(), __stdcall ignored_quals3; // expected-war typedef void(*ignored_quals_dummy4)(), __thiscall ignored_quals4; // expected-warning {{qualifiers after comma in declarator list are ignored}} typedef void(*ignored_quals_dummy5)(), __cdecl ignored_quals5; // expected-warning {{qualifiers after comma in declarator list are ignored}} typedef void(*ignored_quals_dummy6)(), __vectorcall ignored_quals6; // expected-warning {{qualifiers after comma in declarator list are ignored}} + +__declspec(align(16)) struct align_before_key1 {}; +__declspec(align(16)) struct align_before_key2 {} align_before_key2_var; +__declspec(align(16)) struct align_before_key3 {} *align_before_key3_var; +_Static_assert(__alignof(struct align_before_key1) == 16, ""); +_Static_assert(__alignof(struct align_before_key2) == 16, ""); +_Static_assert(__alignof(struct align_before_key3) == 16, ""); diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp index 736e69a9654..1686515d688 100644 --- a/clang/test/Parser/MicrosoftExtensions.cpp +++ b/clang/test/Parser/MicrosoftExtensions.cpp @@ -391,3 +391,12 @@ constexpr A<int> h() { } static_assert(h().g() == false, ""); } + +namespace { +__declspec(align(16)) struct align_before_key1 {}; +__declspec(align(16)) struct align_before_key2 {} align_before_key2_var; +__declspec(align(16)) struct align_before_key3 {} *align_before_key3_var; +static_assert(__alignof(struct align_before_key1) == 16, ""); +static_assert(__alignof(struct align_before_key2) == 16, ""); +static_assert(__alignof(struct align_before_key3) == 16, ""); +} |