arphaman created this revision.
arphaman added reviewers: ahatanak, rjmccall.
Herald added a subscriber: jkorous-apple.

Clang currently generates wrong record layout for `-mms-bitfield` and `#pragma 
pack`. https://godbolt.org/g/nQ4rVW shows how MSVC and GCC generate different 
layout to Clang.

This patch fixes the issue by ensuring that bitfields are not packed, but the 
record's alignment is still updated. This seems to be in line with logic used 
by GCC and MSVC.

rdar://36343145


Repository:
  rC Clang

https://reviews.llvm.org/D42660

Files:
  lib/AST/RecordLayoutBuilder.cpp
  test/CodeGen/mms-bitfields.c
  test/Sema/mms-bitfields.c

Index: test/Sema/mms-bitfields.c
===================================================================
--- test/Sema/mms-bitfields.c
+++ test/Sema/mms-bitfields.c
@@ -11,3 +11,18 @@
 
 // MS pads out bitfields between different types.
 static int arr[(sizeof(t) == 8) ? 1 : -1];
+
+#pragma pack (push,1)
+
+typedef unsigned int UINT32;
+
+struct Inner {
+  UINT32    A    :  1;
+  UINT32    B    :  1;
+  UINT32    C    :  1;
+  UINT32    D    : 30;
+} Inner;
+
+#pragma pack (pop)
+
+static int arr2[(sizeof(Inner) == 8) ? 1 : -1];
Index: test/CodeGen/mms-bitfields.c
===================================================================
--- test/CodeGen/mms-bitfields.c
+++ test/CodeGen/mms-bitfields.c
@@ -20,3 +20,46 @@
 } s3;
 
 // CHECK: %struct.s3 = type { i32, [4 x i8], %struct.s1 }
+
+// PR32482:
+
+#pragma pack (push,1)
+
+typedef unsigned int UINT32;
+
+struct Inner {
+  UINT32    A    :  1;
+  UINT32    B    :  1;
+  UINT32    C    :  1;
+  UINT32    D    : 30;
+} Inner;
+
+#pragma pack (pop)
+
+// CHECK: %struct.Inner = type { i32, i32 }
+
+// CHECK: %struct.A = type { i32, i32, i32 }
+
+#pragma pack(push, 1)
+
+union HEADER {
+  struct A {
+    int                                         :  3;  // Bits 2:0
+    int a                                       :  9;  // Bits 11:3
+    int                                         :  12;  // Bits 23:12
+    int b                                       :  17;  // Bits 40:24
+    int                                         :  7;  // Bits 47:41
+    int c                                       :  4;  // Bits 51:48
+    int                                         :  4;  // Bits 55:52
+    int d                                       :  3;  // Bits 58:56
+    int                                         :  5;  // Bits 63:59
+  } Bits;
+} HEADER;
+
+#pragma pack(pop)
+
+struct Inner variable = { 1,0,1, 21 };
+union HEADER hdr = {{1,2,3,4}};
+
+// CHECK: @variable = global { i8, [3 x i8], i8, i8, i8, i8 } { i8 5, [3 x i8] undef, i8 21, i8 0, i8 0, i8 0 }, align 1
+// CHECK: @hdr = global { { i8, i8, [2 x i8], i8, i8, i8, i8, i8, [3 x i8] } } { { i8, i8, [2 x i8], i8, i8, i8, i8, i8, [3 x i8] } { i8 8, i8 0, [2 x i8] undef, i8 2, i8 0, i8 0, i8 3, i8 4, [3 x i8] undef } }, align 1
Index: lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- lib/AST/RecordLayoutBuilder.cpp
+++ lib/AST/RecordLayoutBuilder.cpp
@@ -1561,12 +1561,21 @@
   // But, if there's a #pragma pack in play, that takes precedent over
   // even the 'aligned' attribute, for non-zero-width bitfields.
   unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
+  unsigned RecordFieldAlign = FieldAlign;
   if (!MaxFieldAlignment.isZero() && FieldSize) {
-    UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
-    if (FieldPacked)
-      FieldAlign = UnpackedFieldAlign;
-    else
-      FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+    // #pragma pack does not affect bitfield layout in ms_struct, but the
+    // record's alignment is still changed.
+    if (IsMsStruct) {
+      RecordFieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+    } else {
+      UnpackedFieldAlign =
+          std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
+      if (FieldPacked)
+        FieldAlign = UnpackedFieldAlign;
+      else
+        FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+      RecordFieldAlign = FieldAlign;
+    }
   }
 
   // But, ms_struct just ignores all of that in unions, even explicit
@@ -1699,7 +1708,7 @@
   setSize(std::max(getSizeInBits(), getDataSizeInBits()));
 
   // Remember max struct/class alignment.
-  UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign), 
+  UpdateAlignment(Context.toCharUnitsFromBits(RecordFieldAlign),
                   Context.toCharUnitsFromBits(UnpackedFieldAlign));
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to