aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-11-22 19:13:51 +0000
committerAnders Carlsson <andersca@mac.com>2009-11-22 19:13:51 +0000
commite4fc0d97420e13d13c9664a3c27c17aa7c1e47b9 (patch)
tree60beeb21c2402d1e0ccab1db42b00b4df82ba6df
parenta7601999342df118f9b9f1acdcf96c0478239638 (diff)
When laying out bitfields, make sure that the data size is always aligned to a byte. This fixes PR5580.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89611 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp30
-rw-r--r--lib/AST/RecordLayoutBuilder.h9
-rw-r--r--test/SemaCXX/class-layout.cpp17
3 files changed, 45 insertions, 11 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 8e4e160746..5bc27b9d06 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -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;
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index c738e31beb..fe02d882ce 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -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.
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
index 56f41bfbdb..b5971723a7 100644
--- a/test/SemaCXX/class-layout.cpp
+++ b/test/SemaCXX/class-layout.cpp
@@ -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);
+
+}