[MS ABI] Correctly associate align attrs before the class-key
authorDavid Majnemer <david.majnemer@gmail.com>
Sun, 19 Apr 2015 07:53:29 +0000 (07:53 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sun, 19 Apr 2015 07:53:29 +0000 (07:53 +0000)
__declspec(align(...)) is unlike all other attributes in that it is not
applied to a variable if it appears before the class-key.  If the
tag in question isn't part of a variable declaration, it is not ignored.

Instead, the alignment attribute is applied to the tag.

This fixes PR18024.

llvm-svn: 235272

clang/include/clang/Parse/Parser.h
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/test/Parser/MicrosoftExtensions.c
clang/test/Parser/MicrosoftExtensions.cpp

index f4487c1..b0c116c 100644 (file)
@@ -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);
index 8f4afdf..c644217 100644 (file)
@@ -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;
index c74b028..11934c4 100644 (file)
@@ -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,
index 83e0921..40a9510 100644 (file)
@@ -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, "");
index 736e69a..1686515 100644 (file)
@@ -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, "");
+}