bool operator <(const MemberInfo& a) const { return Offset < a.Offset; }
};
// The constructor.
- CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D);
+ CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed);
// Short helper routines.
/// \brief Constructs a MemberInfo instance from an offset and llvm::Type *.
MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
/// padding that is or can potentially be used.
void clipTailPadding();
/// \brief Determines if we need a packed llvm struct.
- void determinePacked();
+ void determinePacked(bool NVBaseType);
/// \brief Inserts padding everwhere it's needed.
void insertPadding();
/// \brief Fills out the structures that are ultimately consumed.
};
} // namespace {
-CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D)
+CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed)
: Types(Types), Context(Types.getContext()), D(D),
RD(dyn_cast<CXXRecordDecl>(D)),
Layout(Types.getContext().getASTRecordLayout(D)),
DataLayout(Types.getDataLayout()), IsZeroInitializable(true),
- IsZeroInitializableAsBase(true), Packed(false) {}
+ IsZeroInitializableAsBase(true), Packed(Packed) {}
void CGRecordLowering::setBitFieldInfo(
const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) {
std::stable_sort(Members.begin(), Members.end());
Members.push_back(StorageInfo(Size, getIntNType(8)));
clipTailPadding();
- determinePacked();
+ determinePacked(NVBaseType);
insertPadding();
Members.pop_back();
calculateZeroInit();
}
}
-void CGRecordLowering::determinePacked() {
+void CGRecordLowering::determinePacked(bool NVBaseType) {
+ if (Packed)
+ return;
CharUnits Alignment = CharUnits::One();
+ CharUnits NVAlignment = CharUnits::One();
+ CharUnits NVSize =
+ !NVBaseType && RD ? Layout.getNonVirtualSize() : CharUnits::Zero();
for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
MemberEnd = Members.end();
Member != MemberEnd; ++Member) {
// then the entire record must be packed.
if (Member->Offset % getAlignment(Member->Data))
Packed = true;
+ if (Member->Offset < NVSize)
+ NVAlignment = std::max(NVAlignment, getAlignment(Member->Data));
Alignment = std::max(Alignment, getAlignment(Member->Data));
}
// If the size of the record (the capstone's offset) is not a multiple of the
// record's alignment, it must be packed.
if (Members.back().Offset % Alignment)
Packed = true;
+ // If the non-virtual sub-object is not a multiple of the non-virtual
+ // sub-object's alignment, it must be packed. We cannot have a packed
+ // non-virtual sub-object and an unpacked complete object or vise versa.
+ if (NVSize % NVAlignment)
+ Packed = true;
// Update the alignment of the sentinal.
if (!Packed)
Members.back().Data = getIntNType(Context.toBits(Alignment));
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
llvm::StructType *Ty) {
- CGRecordLowering Builder(*this, D);
+ CGRecordLowering Builder(*this, D, /*Packed=*/false);
- Builder.lower(false);
+ Builder.lower(/*NonVirtualBaseType=*/false);
// If we're in C++, compute the base subobject type.
llvm::StructType *BaseTy = nullptr;
if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) {
BaseTy = Ty;
if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) {
- CGRecordLowering BaseBuilder(*this, D);
- BaseBuilder.lower(true);
+ CGRecordLowering BaseBuilder(*this, D, /*Packed=*/Builder.Packed);
+ BaseBuilder.lower(/*NonVirtualBaseType=*/true);
BaseTy = llvm::StructType::create(
getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed);
addRecordTypeName(D, BaseTy, ".base");
+ // BaseTy and Ty must agree on their packedness for getLLVMFieldNo to work
+ // on both of them with the same index.
+ assert(Builder.Packed == BaseBuilder.Packed &&
+ "Non-virtual and complete types must agree on packedness");
}
}
};
struct C : A, B { int j; };
- // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8
+ // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} <{ %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0, [4 x i8] zeroinitializer }>, align 8
C c;
}
// CHECK: call void @_ZN7PR130971XC1ERKS0_
}
+namespace PR21089 {
+struct A {
+ bool : 1;
+ int A::*x;
+ bool y;
+ A();
+};
+struct B : A {
+};
+B b;
+// CHECK-GLOBAL: @_ZN7PR210891bE = global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
+}
+
// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }