summaryrefslogtreecommitdiffstats
path: root/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp141
1 files changed, 86 insertions, 55 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4ed031f..0770e1f 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -19,7 +19,7 @@
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
-#include <map>
+#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
@@ -564,6 +564,8 @@ protected:
unsigned IsUnion : 1;
unsigned IsMac68kAlign : 1;
+
+ unsigned IsMsStruct : 1;
/// 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
@@ -580,6 +582,8 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
+ CharUnits ZeroLengthBitfieldAlignment;
+
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -612,10 +616,12 @@ protected:
*EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
- Packed(false), IsUnion(false), IsMac68kAlign(false),
+ Packed(false), IsUnion(false),
+ IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
- NonVirtualAlignment(CharUnits::One()), PrimaryBase(0),
+ NonVirtualAlignment(CharUnits::One()),
+ ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -657,7 +663,7 @@ protected:
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -757,9 +763,9 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
}
-uint64_t
+CharUnits
RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- return Context.Target.getPointerWidth(0);
+ return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -815,8 +821,8 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
// Update the size.
- setSize(getSizeInBits() + GetVirtualPointersSize(RD));
- setDataSize(getSizeInBits());
+ setSize(getSize() + GetVirtualPointersSize(RD));
+ setDataSize(getSize());
CharUnits UnpackedBaseAlign =
Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
@@ -1108,8 +1114,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
- uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
- setSize(std::max(getSizeInBits(), RecordSizeInBits));
+ setSize(std::max(getSize(), Layout.getSize()));
return CharUnits::Zero();
}
@@ -1124,27 +1129,24 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
// Round up the current record size to the base's alignment boundary.
- uint64_t Offset =
- llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(BaseAlign));
+ CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign);
// Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
- Context.toCharUnitsFromBits(Offset)))
- Offset += Context.toBits(BaseAlign);
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
+ Offset += BaseAlign;
if (!Base->Class->isEmpty()) {
// Update the data size.
- setDataSize(Offset + Context.toBits(Layout.getNonVirtualSize()));
+ setDataSize(Offset + Layout.getNonVirtualSize());
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ setSize(std::max(getSize(), getDataSize()));
} else
- setSize(std::max(getSizeInBits(),
- Offset + Context.toBits(Layout.getSize())));
+ setSize(std::max(getSize(), Offset + Layout.getSize()));
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
- return Context.toCharUnitsFromBits(Offset);
+ return Offset;
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
@@ -1152,6 +1154,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
+
+ IsMsStruct = D->hasAttr<MsStructAttr>();
// mac68k alignment supersedes maximum field alignment and attribute aligned,
// and forces all structures to have 2-byte alignment. The IBM docs on it
@@ -1187,8 +1191,9 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- // FIXME: Size isn't always an exact multiple of the char width. Round up?
- NonVirtualSize = Context.toCharUnitsFromBits(getSizeInBits());
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.Target.getCharAlign()));
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1233,7 +1238,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
setSize(SL.getDataSize());
- setDataSize(getSizeInBits());
+ setDataSize(getSize());
}
InitializeLayout(D);
@@ -1252,9 +1257,28 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
+ const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
+ if (IsMsStruct) {
+ const FieldDecl *FD = (*Field);
+ if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ // FIXME. Multiple zero bitfields may follow a bitfield.
+ // set ZeroLengthBitfieldAlignment to max. of its
+ // currrent and alignment of 'FD'.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+ ZeroLengthBitfieldAlignment = FieldInfo.second;
+ continue;
+ }
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
+ continue;
+ LastFD = FD;
+ }
LayoutField(*Field);
+ }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1285,7 +1309,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
}
assert(!Type.isNull() && "Did not find a type!");
- unsigned TypeAlign = Context.getTypeAlign(Type);
+ CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
UnfilledBitsInLastByte = 0;
@@ -1299,11 +1323,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
// for T', with length n bits.
- FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), TypeAlign);
+ FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
+ Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1311,13 +1337,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
FieldOffsets.push_back(FieldOffset);
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
- TypeAlign, FieldPacked, D);
+ Context.toBits(TypeAlign), FieldPacked, D);
// Update the size.
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
- UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
+ UpdateAlignment(TypeAlign);
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
@@ -1380,7 +1406,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1428,6 +1455,9 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ ZeroLengthBitfieldAlignment = CharUnits::Zero();
if (Context.getLangOptions().MSBitfields) {
// If MS bitfield layout is required, figure out what type is being
@@ -1487,7 +1517,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (IsUnion)
setSize(std::max(getSizeInBits(), FieldSizeInBits));
else
- setSize(Context.toBits(FieldOffset) + FieldSizeInBits);
+ setSize(FieldOffset + FieldSize);
// Update the data size.
setDataSize(getSizeInBits());
@@ -1504,17 +1534,18 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// which is not empty but of size 0; such as having fields of
// array of zero-length, remains of Size 0
if (RD->isEmpty())
- setSize(8);
+ setSize(CharUnits::One());
}
else
- setSize(8);
+ setSize(CharUnits::One());
}
// Finally, round the size of the record up to the alignment of the
// record itself.
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
- uint64_t UnpackedSize =
+ uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
+ CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
unsigned CharBitNum = Context.Target.getCharWidth();
@@ -1536,7 +1567,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Warn if we packed it unnecessarily. If the alignment is 1 byte don't
// bother since there won't be alignment issues.
if (Packed && UnpackedAlignment > CharUnits::One() &&
- getSizeInBits() == UnpackedSize)
+ getSize() == UnpackedSize)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
@@ -1664,17 +1695,19 @@ namespace {
EmptySubobjectMap *EmptySubobjects) :
RecordLayoutBuilder(Ctx, EmptySubobjects) {}
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
};
}
-uint64_t
+CharUnits
MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
// We should reserve space for two pointers if the class has both
// virtual functions and virtual bases.
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
if (RD->isPolymorphic() && RD->getNumVBases() > 0)
- return 2 * Context.Target.getPointerWidth(0);
- return Context.Target.getPointerWidth(0);
+ return 2 * PointerWidth;
+ return PointerWidth;
}
/// getASTRecordLayout - Get or compute information about the layout of the
@@ -1705,6 +1738,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
case CXXABI_Microsoft:
Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects));
}
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
+ RecordBuilderCleanup(Builder.get());
+
Builder->Layout(RD);
// FIXME: This is not always correct. See the part about bitfields at
@@ -1713,17 +1750,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
// FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize;
- CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ?
- toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize;
+ CharUnits DataSize =
+ IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize();
+ CharUnits NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
- CharUnits RecordSize = toCharUnitsFromBits(Builder->Size);
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder->getSize(),
Builder->Alignment,
- toCharUnitsFromBits(DataSize),
+ DataSize,
Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
NonVirtualSize,
@@ -1736,12 +1771,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.Size),
+ Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
@@ -1797,12 +1830,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.DataSize),
+ Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
OpenPOWER on IntegriCloud