[MS-ABI] Update to zero-sized padding algorithm

Slight change to the way zero-sized sub-objects are tracked in the 
presence of virtual bases.
In addition we correctly distinguish between dsize and nvsize.
addresses http://llvm.org/bugs/show_bug.cgi?id=18826
Unit tests are included.

llvm-svn: 201832
This commit is contained in:
Warren Hunt 2014-02-21 01:40:35 +00:00
parent 90331d5cf4
commit f6ec74826e
2 changed files with 59 additions and 21 deletions

View File

@ -2165,7 +2165,8 @@ public:
void finalizeLayout(const RecordDecl *RD);
/// \brief Gets the size and alignment of a base taking pragma pack and
/// __declspec(align) into account.
ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout);
ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout,
bool AsBase = true);
/// \brief Gets the size and alignment of a field taking pragma pack and
/// __declspec(align) into account. It also updates RequiredAlignment as a
/// side effect because it is most convenient to do so here.
@ -2184,7 +2185,9 @@ public:
const ASTContext &Context;
/// \brief The size of the record being laid out.
CharUnits Size;
/// \brief The data alignment of the record layout.
/// \brief The non-virtual size of the record layout.
CharUnits NonVirtualSize;
/// \brief The data size of the record layout.
CharUnits DataSize;
/// \brief The current alignment of the record layout.
CharUnits Alignment;
@ -2236,7 +2239,7 @@ public:
MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
const ASTRecordLayout &Layout) {
const ASTRecordLayout &Layout, bool AsBase) {
ElementInfo Info;
Info.Alignment = Layout.getAlignment();
// Respect pragma pack.
@ -2250,7 +2253,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
// doesn't actually apply to the struct alignment at this point.
Alignment = std::max(Alignment, Info.Alignment);
Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
Info.Size = Layout.getDataSize();
Info.Size = AsBase ? Layout.getNonVirtualSize() : Layout.getSize();
return Info;
}
@ -2266,10 +2269,11 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl());
// Get the element info for a layout, respecting pack.
Info = getAdjustedElementInfo(Layout);
// Nomally getAdjustedElementInfo returns the non-virtual size, which is
// correct for bases but not for fields.
Info.Size = Context.getTypeInfoInChars(FD->getType()).first;
Info = getAdjustedElementInfo(Layout, false);
// If the field is an array type, scale it's size properly.
if (const ConstantArrayType *CAT =
dyn_cast<ConstantArrayType>(FD->getType()))
Info.Size = Info.Size * (int64_t)CAT->getSize().getZExtValue();
// Capture required alignment as a side-effect.
RequiredAlignment = std::max(RequiredAlignment,
Layout.getRequiredAlignment());
@ -2317,7 +2321,7 @@ void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
layoutNonVirtualBases(RD);
layoutFields(RD);
injectVPtrs(RD);
DataSize = Size = Size.RoundUpToAlignment(Alignment);
NonVirtualSize = Size = Size.RoundUpToAlignment(Alignment);
RequiredAlignment = std::max(
RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
layoutVirtualBases(RD);
@ -2458,7 +2462,7 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
Bases.insert(std::make_pair(BaseDecl, BaseOffset));
Size = BaseOffset + BaseLayout.getDataSize();
Size = BaseOffset + BaseLayout.getNonVirtualSize();
PreviousBaseLayout = &BaseLayout;
VBPtrOffset = Size;
}
@ -2569,9 +2573,6 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
i != e; ++i)
if (i->second >= InjectionSite)
i->second += Offset;
// The presence of a vbptr suppresses zero sized objects that are not in
// virtual bases.
HasZeroSizedSubObject = false;
}
void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
@ -2645,17 +2646,17 @@ void MicrosoftRecordLayoutBuilder::injectVPtrs(const CXXRecordDecl *RD) {
// different from the general case layout but it may have to do with lazy
// placement of zero sized bases.
VBPtrOffset = Size;
if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
VBPtrOffset = Bases[LastBaseDecl];
if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
VBPtrOffset = Bases[PenultBaseDecl];
}
// Once we've located a spot for the vbptr, place it.
VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
Size = VBPtrOffset + PointerInfo.Size;
if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
// Add the padding between zero sized bases after the vbptr.
if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
Size += CharUnits::One();
Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment());
Bases[LastBaseDecl] = Size;
@ -2715,11 +2716,12 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
if (HasVtordisp)
Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
// Insert the virtual base.
HasZeroSizedSubObject = false;
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
VBases.insert(std::make_pair(BaseDecl,
ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
Size = BaseOffset + BaseLayout.getDataSize();
Size = BaseOffset + BaseLayout.getNonVirtualSize();
PreviousBaseLayout = &BaseLayout;
}
}
@ -2727,6 +2729,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
// Respect required alignment. Note that in 32-bit mode Required alignment
// may be 0 nad cause size not to be updated.
DataSize = Size;
if (!RequiredAlignment.isZero()) {
Alignment = std::max(Alignment, RequiredAlignment);
Size = Size.RoundUpToAlignment(Alignment);
@ -2852,8 +2855,8 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
*this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
Builder.HasOwnVFPtr,
Builder.HasOwnVFPtr || Builder.PrimaryBase,
Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(), Builder.DataSize,
Builder.VBPtrOffset, Builder.NonVirtualSize, Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(), Builder.NonVirtualSize,
Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase,
false, Builder.SharedVBPtrBase,
Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase,

View File

@ -730,6 +730,40 @@ struct T3 : virtual T1, virtual T0 { long long a; };
// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
struct Q0A {};
struct Q0B { char Q0BField; };
struct Q0C : virtual Q0A, virtual Q0B { char Q0CField; };
struct Q0D : Q0C, Q0A {};
// CHECK: *** Dumping AST Record Layout
// CHECK: *** Dumping AST Record Layout
// CHECK: *** Dumping AST Record Layout
// CHECK: *** Dumping AST Record Layout
// CHECK-NEXT: 0 | struct Q0D
// CHECK-NEXT: 0 | struct Q0C (base)
// CHECK-NEXT: 0 | (Q0C vbtable pointer)
// CHECK-NEXT: 4 | char Q0CField
// CHECK-NEXT: 8 | struct Q0A (base) (empty)
// CHECK-NEXT: 8 | struct Q0A (virtual base) (empty)
// CHECK-NEXT: 8 | struct Q0B (virtual base)
// CHECK-NEXT: 8 | char Q0BField
// CHECK-NEXT: | [sizeof=9, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct Q0D
// CHECK-X64-NEXT: 0 | struct Q0C (base)
// CHECK-X64-NEXT: 0 | (Q0C vbtable pointer)
// CHECK-X64-NEXT: 8 | char Q0CField
// CHECK-X64-NEXT: 16 | struct Q0A (base) (empty)
// CHECK-X64-NEXT: 16 | struct Q0A (virtual base) (empty)
// CHECK-X64-NEXT: 16 | struct Q0B (virtual base)
// CHECK-X64-NEXT: 16 | char Q0BField
// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
int a[
sizeof(A)+
sizeof(B)+
@ -753,4 +787,5 @@ sizeof(S)+
sizeof(T)+
sizeof(U)+
sizeof(V)+
sizeof(T3)];
sizeof(T3)+
sizeof(Q0D)];