The following program:

union A {
  int f1: 3;
  A();
};

A::A() {}

causes the failure of the assertion "DataSize % Context.getCharWidth() == 0" at 
clang/lib/AST/RecordLayoutBuilder.cpp:754.

It happens because '2.4 Non-POD Class Types/II. Allocation of Members Other 
Than Virtual Bases/1. bit-fileds' of C++ ABI 
(http://mentorembedded.github.io/cxx-abi/abi.html#class-types) is implemented 
incorrectly: dsize(C) is not updated to include the last byte containing (part 
of) the bitfield.

http://reviews.llvm.org/D5775

Files:
  lib/AST/RecordLayoutBuilder.cpp
  test/Layout/union_regular_bit_field.cpp
  test/Layout/union_wide_bit_field.cpp
Index: lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- lib/AST/RecordLayoutBuilder.cpp
+++ lib/AST/RecordLayoutBuilder.cpp
@@ -1345,6 +1345,14 @@
     LayoutField(Field);
 }
 
+// Rounds the specified field up to have it multiple of the char size.
+static uint64_t
+RoundUpFieldSizeToCharAlignment(const uint64_t FieldSize,
+                                const ASTContext &Context) {
+  uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
+  return llvm::RoundUpToAlignment(FieldSize, CharAlignment);
+}
+
 void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
                                              uint64_t TypeSize,
                                              bool FieldPacked,
@@ -1382,7 +1390,9 @@
   uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
 
   if (IsUnion) {
-    setDataSize(std::max(getDataSizeInBits(), FieldSize));
+    uint64_t RoundedFieldSize = RoundUpFieldSizeToCharAlignment(FieldSize,
+                                                                Context);
+    setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize));
     FieldOffset = 0;
   } else {
     // The bitfield is allocated starting at the next offset aligned 
@@ -1607,9 +1617,9 @@
 
   // For unions, this is just a max operation, as usual.
   if (IsUnion) {
-    // FIXME: I think FieldSize should be TypeSize here.
-    setDataSize(std::max(getDataSizeInBits(), FieldSize));
-
+    uint64_t RoundedFieldSize = RoundUpFieldSizeToCharAlignment(FieldSize,
+                                                                Context);
+    setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize));
   // For non-zero-width bitfields in ms_struct structs, allocate a new
   // storage unit if necessary.
   } else if (IsMsStruct && FieldSize) {
Index: test/Layout/union_regular_bit_field.cpp
===================================================================
--- /dev/null
+++ test/Layout/union_regular_bit_field.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple aarch64 -fdump-record-layouts %s 2>/dev/null \
+// RUN:            | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64 -fdump-record-layouts %s 2>/dev/null \
+// RUN:            | FileCheck %s
+
+union A {
+  int f1: 3;
+  A();
+};
+
+A::A() {}
+
+// CHECK:      | [sizeof=4, dsize=1, align=4
+// CHECK-NEXT:     |  nvsize=1, nvalign=4]
+
Index: test/Layout/union_wide_bit_field.cpp
===================================================================
--- /dev/null
+++ test/Layout/union_wide_bit_field.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple aarch64 -fdump-record-layouts %s 2>/dev/null \
+// RUN:            | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64 -fdump-record-layouts %s 2>/dev/null \
+// RUN:            | FileCheck %s
+
+union A {
+  int f1: 69;
+  A();
+};
+
+A::A() {}
+
+// CHECK:      | [sizeof=16, dsize=9, align=8
+// CHECK-NEXT:     |  nvsize=9, nvalign=8]
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to