]> granicus.if.org Git - clang/commitdiff
When laying out bitfields, make sure that the data size is always aligned to a byte...
authorAnders Carlsson <andersca@mac.com>
Sun, 22 Nov 2009 19:13:51 +0000 (19:13 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 22 Nov 2009 19:13:51 +0000 (19:13 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89611 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/RecordLayoutBuilder.cpp
lib/AST/RecordLayoutBuilder.h
test/SemaCXX/class-layout.cpp

index 8e4e160746e0a68b8bef1aae23374b7458c88516..5bc27b9d06f576829091e3d2550404bc89339d2b 100644 (file)
@@ -22,9 +22,9 @@
 using namespace clang;
 
 ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
-  : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
-  DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8),
-  PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
+  : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
+  MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), 
+  NonVirtualAlignment(8), PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
 
 /// LayoutVtable - Lay out the vtable and set PrimaryBase.
 void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
@@ -521,7 +521,7 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
 
 void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
-  uint64_t FieldOffset = IsUnion ? 0 : DataSize;
+  uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
   uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
   
   std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
@@ -549,14 +549,19 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
   // Place this field at the current location.
   FieldOffsets.push_back(FieldOffset);
   
-  // Reserve space for this field.
-  if (IsUnion)
-    Size = std::max(Size, FieldSize);
-  else
-    Size = FieldOffset + FieldSize;
+  // Update DataSize to include the last byte containing (part of) the bitfield.
+  if (IsUnion) {
+    // FIXME: I think FieldSize should be TypeSize here.
+    DataSize = std::max(DataSize, FieldSize);
+  } else {
+    uint64_t NewSizeInBits = FieldOffset + FieldSize;
+    
+    DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+    UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+  }
   
-  // Update the data size.
-  DataSize = Size;
+  // Update the size.
+  Size = std::max(Size, DataSize);
   
   // Remember max struct/class alignment.
   UpdateAlignment(FieldAlign);
@@ -568,6 +573,9 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
     return;
   }
 
+  // Reset the unfilled bits.
+  UnfilledBitsInLastByte = 0;
+
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
   uint64_t FieldOffset = IsUnion ? 0 : DataSize;
   uint64_t FieldSize;
index c738e31beb4c0ae99cdb17cb3a347262374bb6df..fe02d882cec8d372deae9b4cbf41366e86c514cf 100644 (file)
@@ -27,12 +27,21 @@ namespace clang {
 class ASTRecordLayoutBuilder {
   ASTContext &Ctx;
 
+  /// Size - The current size of the record layout.
   uint64_t Size;
+  
+  /// Alignment - The current alignment of the record layout.
   unsigned Alignment;
+  
   llvm::SmallVector<uint64_t, 16> FieldOffsets;
 
   /// Packed - Whether the record is packed or not.
   bool Packed;
+
+  /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
+  /// this contains the number of bits in the last byte that can be used for
+  /// an adjacent bitfield if necessary.
+  unsigned char UnfilledBitsInLastByte;
   
   /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
   /// #pragma pack. 
index 56f41bfbdb936a042186b84597cbe4bc36e05820..b5971723a70d78fbc43cdfc8a13fa73f9d201db7 100644 (file)
@@ -47,3 +47,20 @@ struct G { G(); };
 struct H : G { };
 
 SA(6, sizeof(H) == 1);
+
+// PR5580
+namespace PR5580 {
+
+class A { bool iv0 : 1; };
+SA(7, sizeof(A) == 1);  
+
+class B : A { bool iv0 : 1; };
+SA(8, sizeof(B) == 2);
+
+struct C { bool iv0 : 1; };
+SA(9, sizeof(C) == 1);  
+
+struct D : C { bool iv0 : 1; };
+SA(10, sizeof(D) == 2);
+
+}