]> granicus.if.org Git - clang/commitdiff
MS ABI: Correct layout for empty records
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 30 Sep 2014 06:45:43 +0000 (06:45 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 30 Sep 2014 06:45:43 +0000 (06:45 +0000)
Empty records do not always have size equivalent to their alignment.
They only do so when their alignment is at least as large as the minimum
empty struct size: 1 byte in C++ and 4 bytes in C.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218661 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/RecordLayoutBuilder.cpp
test/Layout/ms-x86-basic-layout.cpp
test/Layout/ms-x86-pack-and-align.cpp

index 6c7f6806116cdda8016d4a556e733d8abd3c6680..798f9f39c3f0fc229333f66c2fef52b5d0948c10 100644 (file)
@@ -2204,6 +2204,8 @@ public:
   CharUnits CurrentBitfieldSize;
   /// \brief Offset to the virtual base table pointer (if one exists).
   CharUnits VBPtrOffset;
+  /// \brief Minimum record size possible.
+  CharUnits MinEmptyStructSize;
   /// \brief The size and alignment info of a pointer.
   ElementInfo PointerInfo;
   /// \brief The primary base class (if one exists).
@@ -2299,6 +2301,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
 }
 
 void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
+  // For C record layout, zero-sized records always have size 4.
+  MinEmptyStructSize = CharUnits::fromQuantity(4);
   initializeLayout(RD);
   layoutFields(RD);
   DataSize = Size = Size.RoundUpToAlignment(Alignment);
@@ -2308,6 +2312,8 @@ void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
 }
 
 void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
+  // The C++ standard says that empty structs have size 1.
+  MinEmptyStructSize = CharUnits::One();
   initializeLayout(RD);
   initializeCXXLayout(RD);
   layoutNonVirtualBases(RD);
@@ -2636,7 +2642,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
 
 void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
   // Respect required alignment.  Note that in 32-bit mode Required alignment
-  // may be 0 nad cause size not to be updated.
+  // may be 0 and cause size not to be updated.
   DataSize = Size;
   if (!RequiredAlignment.isZero()) {
     Alignment = std::max(Alignment, RequiredAlignment);
@@ -2646,11 +2652,15 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
     RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment);
     Size = Size.RoundUpToAlignment(RoundingAlignment);
   }
-  // Zero-sized structures have size equal to their alignment.
   if (Size.isZero()) {
     EndsWithZeroSizedObject = true;
     LeadsWithZeroSizedBase = true;
-    Size = Alignment;
+    // Zero-sized structures have size equal to their alignment if a
+    // __declspec(align) came into play.
+    if (RequiredAlignment >= MinEmptyStructSize)
+      Size = Alignment;
+    else
+      Size = MinEmptyStructSize;
   }
 }
 
index b6ffeee7114a9efe8aa90d0e874ebc88506b6694..aac7aed0601923288f74edd77803315969d468f8 100644 (file)
@@ -816,6 +816,36 @@ struct RecordArrayTypedef {
 // CHECK-X64-NEXT:      | [sizeof=16, align=4
 // CHECK-X64-NEXT:      |  nvsize=16, nvalign=4]
 
+struct EmptyIntMemb {
+  int FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct EmptyIntMemb
+// CHECK-NEXT:    0 |   int [0] FlexArrayMemb
+// CHECK-NEXT:      | [sizeof=1, align=4
+// CHECK-NEXT:      |  nvsize=0, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct EmptyIntMemb
+// CHECK-X64-NEXT:    0 |   int [0] FlexArrayMemb
+// CHECK-X64-NEXT:      | [sizeof=4, align=4
+// CHECK-X64-NEXT:      |  nvsize=0, nvalign=4]
+
+struct EmptyLongLongMemb {
+  long long FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct EmptyLongLongMemb
+// CHECK-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-NEXT:      | [sizeof=1, align=8
+// CHECK-NEXT:      |  nvsize=0, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct EmptyLongLongMemb
+// CHECK-X64-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-X64-NEXT:      | [sizeof=8, align=8
+// CHECK-X64-NEXT:      |  nvsize=0, nvalign=8]
+
 int a[
 sizeof(TestF0)+
 sizeof(TestF1)+
@@ -840,4 +870,6 @@ sizeof(F6)+
 sizeof(ArrayFieldOfRecords)+
 sizeof(ArrayOfArrayFieldOfRecords)+
 sizeof(RecordArrayTypedef)+
+sizeof(EmptyIntMemb)+
+sizeof(EmptyLongLongMemb)+
 0];
index e2f03d782e5d5683f43743f71e22ba784acf2c44..9783233d66acec61bc0496dbf927993c916bd36c 100644 (file)
@@ -769,6 +769,38 @@ struct QD {
 // CHECK-X64-NEXT:      | [sizeof=8, align=4
 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=4]
 
+struct __declspec(align(4)) EmptyAlignedLongLongMemb {
+  long long FlexArrayMemb[0];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct EmptyAlignedLongLongMemb
+// CHECK-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-NEXT:      | [sizeof=8, align=8
+// CHECK-NEXT:      |  nvsize=0, nvalign=8]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct EmptyAlignedLongLongMemb
+// CHECK-X64-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-X64-NEXT:      | [sizeof=8, align=8
+// CHECK-X64-NEXT:      |  nvsize=0, nvalign=8]
+
+#pragma pack(1)
+struct __declspec(align(4)) EmptyPackedAlignedLongLongMemb {
+  long long FlexArrayMemb[0];
+};
+#pragma pack()
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct EmptyPackedAlignedLongLongMemb
+// CHECK-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-NEXT:      | [sizeof=4, align=4
+// CHECK-NEXT:      |  nvsize=0, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct EmptyPackedAlignedLongLongMemb
+// CHECK-X64-NEXT:    0 |   long long [0] FlexArrayMemb
+// CHECK-X64-NEXT:      | [sizeof=4, align=4
+// CHECK-X64-NEXT:      |  nvsize=0, nvalign=4]
+
 int a[
 sizeof(X)+
 sizeof(Y)+
@@ -800,4 +832,6 @@ sizeof(PE)+
 sizeof(QB)+
 sizeof(QC)+
 sizeof(QD)+
+sizeof(EmptyAlignedLongLongMemb)+
+sizeof(EmptyPackedAlignedLongLongMemb)+
 0];