]> granicus.if.org Git - clang/commitdiff
Use external layout information to layout bit-fields for MS ABI.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 13 Jul 2018 21:07:42 +0000 (21:07 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 13 Jul 2018 21:07:42 +0000 (21:07 +0000)
Patch by Aleksandr Urakov!

Differential Revision: https://reviews.llvm.org/D49227

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

lib/AST/RecordLayoutBuilder.cpp
test/CodeGenCXX/Inputs/override-bit-field-layout.layout [new file with mode: 0644]
test/CodeGenCXX/override-bit-field-layout.cpp [new file with mode: 0644]

index 988b88b39b4a8a15f672c8a8b90fd67be6d2a544..b4b09c7cecd75a2827c6abaaba7e8ef6f41f4aca 100644 (file)
@@ -2677,7 +2677,7 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
   // Check to see if this bitfield fits into an existing allocation.  Note:
   // MSVC refuses to pack bitfields of formal types with different sizes
   // into the same allocation.
-  if (!IsUnion && LastFieldIsNonZeroWidthBitfield &&
+  if (!UseExternalLayout && !IsUnion && LastFieldIsNonZeroWidthBitfield &&
       CurrentBitfieldSize == Info.Size && Width <= RemainingBitsInField) {
     placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
     RemainingBitsInField -= Width;
@@ -2689,6 +2689,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
     placeFieldAtOffset(CharUnits::Zero());
     Size = std::max(Size, Info.Size);
     // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
+  } else if (UseExternalLayout) {
+    auto FieldBitOffset = External.getExternalFieldOffset(FD);
+    placeFieldAtBitOffset(FieldBitOffset);
+    auto NewSize = Context.toCharUnitsFromBits(
+        llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth()));
+    assert(NewSize >= Size && "bit field offset already allocated");
+    Size = NewSize;
+    Alignment = std::max(Alignment, Info.Alignment);
   } else {
     // Allocate a new block of memory and place the bitfield in it.
     CharUnits FieldOffset = Size.alignTo(Info.Alignment);
diff --git a/test/CodeGenCXX/Inputs/override-bit-field-layout.layout b/test/CodeGenCXX/Inputs/override-bit-field-layout.layout
new file mode 100644 (file)
index 0000000..8e67dce
--- /dev/null
@@ -0,0 +1,16 @@
+
+*** Dumping AST Record Layout
+Type: struct S1
+
+Layout: <ASTRecordLayout
+  Size:16
+  Alignment:16
+  FieldOffsets: [0, 11]>
+
+*** Dumping AST Record Layout
+Type: struct S2
+
+Layout: <ASTRecordLayout
+  Size:128
+  Alignment:64
+  FieldOffsets: [64]>
diff --git a/test/CodeGenCXX/override-bit-field-layout.cpp b/test/CodeGenCXX/override-bit-field-layout.cpp
new file mode 100644 (file)
index 0000000..e84fcb0
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -w -fdump-record-layouts-simple -foverride-record-layout=%S/Inputs/override-bit-field-layout.layout %s | FileCheck %s
+
+// CHECK: Type: struct S1
+// CHECK:   FieldOffsets: [0, 11]
+struct S1 {
+  short a : 3;
+  short b : 5;
+};
+
+// CHECK: Type: struct S2
+// CHECK:   FieldOffsets: [64]
+struct S2 {
+  virtual ~S2() = default;
+  short a : 3;
+};
+
+void use_structs() {
+  S1 s1s[sizeof(S1)];
+  S2 s2s[sizeof(S2)];
+}