RecordLayoutBuilder.cpp [plain text]
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
namespace {
struct BaseSubobjectInfo {
const CXXRecordDecl *Class;
bool IsVirtual;
SmallVector<BaseSubobjectInfo*, 4> Bases;
BaseSubobjectInfo *PrimaryVirtualBaseInfo;
const BaseSubobjectInfo *Derived;
};
class EmptySubobjectMap {
const ASTContext &Context;
uint64_t CharWidth;
const CXXRecordDecl *Class;
typedef SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
CharUnits MaxEmptyClassOffset;
void ComputeEmptySubobjectSizes();
void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset);
void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
CharUnits Offset, bool PlacingEmptyBase);
void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset);
void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const {
return Offset <= MaxEmptyClassOffset;
}
CharUnits
getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const {
uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
assert(FieldOffset % CharWidth == 0 &&
"Field offset not at char boundary!");
return Context.toCharUnitsFromBits(FieldOffset);
}
protected:
bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
CharUnits Offset) const;
bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset);
bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset) const;
bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
CharUnits Offset) const;
public:
CharUnits SizeOfLargestEmptySubobject;
EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class)
: Context(Context), CharWidth(Context.getCharWidth()), Class(Class) {
ComputeEmptySubobjectSizes();
}
bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset);
bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset);
};
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
E = Class->bases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
if (BaseDecl->isEmpty()) {
EmptySize = Layout.getSize();
} else {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
if (EmptySize > SizeOfLargestEmptySubobject)
SizeOfLargestEmptySubobject = EmptySize;
}
for (CXXRecordDecl::field_iterator I = Class->field_begin(),
E = Class->field_end(); I != E; ++I) {
const RecordType *RT =
Context.getBaseElementType(I->getType())->getAs<RecordType>();
if (!RT)
continue;
CharUnits EmptySize;
const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
EmptySize = Layout.getSize();
} else {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
if (EmptySize > SizeOfLargestEmptySubobject)
SizeOfLargestEmptySubobject = EmptySize;
}
}
bool
EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
CharUnits Offset) const {
if (!RD->isEmpty())
return true;
EmptyClassOffsetsMapTy::const_iterator I = EmptyClassOffsets.find(Offset);
if (I == EmptyClassOffsets.end())
return true;
const ClassVectorTy& Classes = I->second;
if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end())
return true;
return false;
}
void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
CharUnits Offset) {
if (!RD->isEmpty())
return;
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
return;
Classes.push_back(RD);
if (Offset > MaxEmptyClassOffset)
MaxEmptyClassOffset = Offset;
}
bool
EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset) {
if (!AnyEmptySubobjectsBeyondOffset(Offset))
return true;
if (!CanPlaceSubobjectAtOffset(Info->Class, Offset))
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
BaseSubobjectInfo* Base = Info->Bases[I];
if (Base->IsVirtual)
continue;
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset))
return false;
}
if (Info->PrimaryVirtualBaseInfo) {
BaseSubobjectInfo *PrimaryVirtualBaseInfo = Info->PrimaryVirtualBaseInfo;
if (Info == PrimaryVirtualBaseInfo->Derived) {
if (!CanPlaceBaseSubobjectAtOffset(PrimaryVirtualBaseInfo, Offset))
return false;
}
}
unsigned FieldNo = 0;
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
if (I->isBitField())
continue;
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(*I, FieldOffset))
return false;
}
return true;
}
void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
CharUnits Offset,
bool PlacingEmptyBase) {
if (!PlacingEmptyBase && Offset >= SizeOfLargestEmptySubobject) {
return;
}
AddSubobjectAtOffset(Info->Class, Offset);
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
BaseSubobjectInfo* Base = Info->Bases[I];
if (Base->IsVirtual)
continue;
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
UpdateEmptyBaseSubobjects(Base, BaseOffset, PlacingEmptyBase);
}
if (Info->PrimaryVirtualBaseInfo) {
BaseSubobjectInfo *PrimaryVirtualBaseInfo = Info->PrimaryVirtualBaseInfo;
if (Info == PrimaryVirtualBaseInfo->Derived)
UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset,
PlacingEmptyBase);
}
unsigned FieldNo = 0;
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
if (I->isBitField())
continue;
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(*I, FieldOffset);
}
}
bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset) {
if (SizeOfLargestEmptySubobject.isZero())
return true;
if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))
return false;
UpdateEmptyBaseSubobjects(Info, Offset, Info->Class->isEmpty());
return true;
}
bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset) const {
if (!AnyEmptySubobjectsBeyondOffset(Offset))
return true;
if (!CanPlaceSubobjectAtOffset(RD, Offset))
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual())
continue;
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset))
return false;
}
if (RD == Class) {
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
return false;
}
}
unsigned FieldNo = 0;
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
if (I->isBitField())
continue;
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(*I, FieldOffset))
return false;
}
return true;
}
bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
CharUnits Offset) const {
if (!AnyEmptySubobjectsBeyondOffset(Offset))
return true;
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
return CanPlaceFieldSubobjectAtOffset(RD, RD, Offset);
}
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return true;
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
if (!AnyEmptySubobjectsBeyondOffset(ElementOffset))
return true;
if (!CanPlaceFieldSubobjectAtOffset(RD, RD, ElementOffset))
return false;
ElementOffset += Layout.getSize();
}
}
return true;
}
bool
EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD,
CharUnits Offset) {
if (!CanPlaceFieldSubobjectAtOffset(FD, Offset))
return false;
UpdateEmptyFieldSubobjects(FD, Offset);
return true;
}
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset) {
if (Offset >= SizeOfLargestEmptySubobject)
return;
AddSubobjectAtOffset(RD, Offset);
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual())
continue;
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
}
if (RD == Class) {
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
}
}
unsigned FieldNo = 0;
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
if (I->isBitField())
continue;
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(*I, FieldOffset);
}
}
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
CharUnits Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
UpdateEmptyFieldSubobjects(RD, RD, Offset);
return;
}
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
if (ElementOffset >= SizeOfLargestEmptySubobject)
return;
UpdateEmptyFieldSubobjects(RD, RD, ElementOffset);
ElementOffset += Layout.getSize();
}
}
}
typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> ClassSetTy;
class RecordLayoutBuilder {
protected:
friend class clang::ASTContext;
const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
uint64_t Size;
CharUnits Alignment;
CharUnits UnpackedAlignment;
SmallVector<uint64_t, 16> FieldOffsets;
unsigned ExternalLayout : 1;
unsigned InferAlignment : 1;
unsigned Packed : 1;
unsigned IsUnion : 1;
unsigned IsMac68kAlign : 1;
unsigned IsMsStruct : 1;
unsigned char UnfilledBitsInLastByte;
CharUnits MaxFieldAlignment;
uint64_t DataSize;
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
FieldDecl *ZeroLengthBitfield;
const CXXRecordDecl *PrimaryBase;
bool PrimaryBaseIsVirtual;
bool HasOwnVFPtr;
CharUnits VBPtrOffset;
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
BaseOffsetsMapTy Bases;
ASTRecordLayout::VBaseOffsetsMapTy VBases;
CXXIndirectPrimaryBaseSet IndirectPrimaryBases;
const CXXRecordDecl *FirstNearlyEmptyVBase;
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
uint64_t ExternalSize;
uint64_t ExternalAlign;
llvm::DenseMap<const FieldDecl *, uint64_t> ExternalFieldOffsets;
llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalBaseOffsets;
llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalVirtualBaseOffsets;
RecordLayoutBuilder(const ASTContext &Context,
EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
ExternalLayout(false), InferAlignment(false),
Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
ZeroLengthBitfield(0), PrimaryBase(0),
PrimaryBaseIsVirtual(false),
HasOwnVFPtr(false),
VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
void resetWithTargetAlignment(CharUnits TargetAlignment) {
const ASTContext &Context = this->Context;
EmptySubobjectMap *EmptySubobjects = this->EmptySubobjects;
this->~RecordLayoutBuilder();
new (this) RecordLayoutBuilder(Context, EmptySubobjects);
Alignment = UnpackedAlignment = TargetAlignment;
}
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
void Layout(const ObjCInterfaceDecl *D);
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
bool isMicrosoftCXXABI() const {
return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
}
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
typedef llvm::DenseMap<const CXXRecordDecl *, BaseSubobjectInfo *>
BaseSubobjectInfoMapTy;
BaseSubobjectInfoMapTy VirtualBaseInfo;
BaseSubobjectInfoMapTy NonVirtualBaseInfo;
void ComputeBaseSubobjectInfo(const CXXRecordDecl *RD);
BaseSubobjectInfo *ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
bool IsVirtual,
BaseSubobjectInfo *Derived);
void DeterminePrimaryBase(const CXXRecordDecl *RD);
void SelectPrimaryVBase(const CXXRecordDecl *RD);
void EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign);
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
void LayoutNonVirtualBase(const BaseSubobjectInfo *Base);
void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset);
bool needsVFTable(const CXXRecordDecl *RD) const;
bool hasNewVirtualFunction(const CXXRecordDecl *RD,
bool IgnoreDestructor = false) const;
bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const;
void computeVtordisps(const CXXRecordDecl *RD,
ClassSetTy &VtordispVBases);
void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
void LayoutVirtualBase(const BaseSubobjectInfo *Base,
bool IsVtordispNeed = false);
CharUnits LayoutBase(const BaseSubobjectInfo *Base);
void InitializeLayout(const Decl *D);
void FinishLayout(const NamedDecl *D);
void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment);
void UpdateAlignment(CharUnits NewAlignment) {
UpdateAlignment(NewAlignment, NewAlignment);
}
uint64_t updateExternalFieldOffset(const FieldDecl *Field,
uint64_t ComputedOffset);
void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
uint64_t UnpackedOffset, unsigned UnpackedAlign,
bool isPacked, const FieldDecl *D);
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
CharUnits getSize() const {
assert(Size % Context.getCharWidth() == 0);
return Context.toCharUnitsFromBits(Size);
}
uint64_t getSizeInBits() const { return Size; }
void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); }
void setSize(uint64_t NewSize) { Size = NewSize; }
CharUnits getAligment() const { return Alignment; }
CharUnits getDataSize() const {
assert(DataSize % Context.getCharWidth() == 0);
return Context.toCharUnitsFromBits(DataSize);
}
uint64_t getDataSizeInBits() const { return DataSize; }
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
}
void
RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
if (I->isVirtual() && Context.isNearlyEmpty(Base)) {
if (!IndirectPrimaryBases.count(Base)) {
PrimaryBase = Base;
PrimaryBaseIsVirtual = true;
return;
}
if (!FirstNearlyEmptyVBase)
FirstNearlyEmptyVBase = Base;
}
SelectPrimaryVBase(Base);
if (PrimaryBase)
return;
}
}
void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
if (!RD->isDynamicClass())
return;
RD->getIndirectPrimaryBases(IndirectPrimaryBases);
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
if (i->isVirtual())
continue;
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (isPossiblePrimaryBase(Base)) {
PrimaryBase = Base;
PrimaryBaseIsVirtual = false;
return;
}
}
if (isMicrosoftCXXABI()) {
assert(!PrimaryBase && "Should not get here with a primary base!");
return;
}
if (RD->getNumVBases() != 0) {
SelectPrimaryVBase(RD);
if (PrimaryBase)
return;
}
if (FirstNearlyEmptyVBase) {
PrimaryBase = FirstNearlyEmptyVBase;
PrimaryBaseIsVirtual = true;
return;
}
assert(!PrimaryBase && "Should not get here with a primary base!");
}
BaseSubobjectInfo *
RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
bool IsVirtual,
BaseSubobjectInfo *Derived) {
BaseSubobjectInfo *Info;
if (IsVirtual) {
BaseSubobjectInfo *&InfoSlot = VirtualBaseInfo[RD];
if (InfoSlot) {
assert(InfoSlot->Class == RD && "Wrong class for virtual base info!");
return InfoSlot;
}
InfoSlot = new (BaseSubobjectInfoAllocator.Allocate()) BaseSubobjectInfo;
Info = InfoSlot;
} else {
Info = new (BaseSubobjectInfoAllocator.Allocate()) BaseSubobjectInfo;
}
Info->Class = RD;
Info->IsVirtual = IsVirtual;
Info->Derived = 0;
Info->PrimaryVirtualBaseInfo = 0;
const CXXRecordDecl *PrimaryVirtualBase = 0;
BaseSubobjectInfo *PrimaryVirtualBaseInfo = 0;
if (RD->getNumVBases()) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
if (Layout.isPrimaryBaseVirtual()) {
PrimaryVirtualBase = Layout.getPrimaryBase();
assert(PrimaryVirtualBase && "Didn't have a primary virtual base!");
PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase);
if (PrimaryVirtualBaseInfo) {
if (PrimaryVirtualBaseInfo->Derived) {
PrimaryVirtualBase = 0;
} else {
Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo;
PrimaryVirtualBaseInfo->Derived = Info;
}
}
}
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
bool IsVirtual = I->isVirtual();
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
Info->Bases.push_back(ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, Info));
}
if (PrimaryVirtualBase && !PrimaryVirtualBaseInfo) {
PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase);
assert(PrimaryVirtualBaseInfo &&
"Did not create a primary virtual base!");
Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo;
PrimaryVirtualBaseInfo->Derived = Info;
}
return Info;
}
void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
bool IsVirtual = I->isVirtual();
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, 0);
if (IsVirtual) {
assert(VirtualBaseInfo.count(BaseDecl) &&
"Did not add virtual base!");
} else {
assert(!NonVirtualBaseInfo.count(BaseDecl) &&
"Non-virtual base already exists!");
NonVirtualBaseInfo.insert(std::make_pair(BaseDecl, Info));
}
}
}
void
RecordLayoutBuilder::EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign) {
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
if (!MaxFieldAlignment.isZero()) {
BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
}
setSize(getSize().RoundUpToAlignment(BaseAlign));
setDataSize(getSize());
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
}
void
RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
DeterminePrimaryBase(RD);
ComputeBaseSubobjectInfo(RD);
if (PrimaryBase) {
if (PrimaryBaseIsVirtual) {
BaseSubobjectInfo *PrimaryBaseInfo = VirtualBaseInfo.lookup(PrimaryBase);
PrimaryBaseInfo->Derived = 0;
IndirectPrimaryBases.insert(PrimaryBase);
assert(!VisitedVirtualBases.count(PrimaryBase) &&
"vbase already visited!");
VisitedVirtualBases.insert(PrimaryBase);
LayoutVirtualBase(PrimaryBaseInfo);
} else {
BaseSubobjectInfo *PrimaryBaseInfo =
NonVirtualBaseInfo.lookup(PrimaryBase);
assert(PrimaryBaseInfo &&
"Did not find base info for non-virtual primary base!");
LayoutNonVirtualBase(PrimaryBaseInfo);
}
} else if (needsVFTable(RD)) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
CharUnits PtrAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
EnsureVTablePointerAlignment(PtrAlign);
HasOwnVFPtr = true;
setSize(getSize() + PtrWidth);
setDataSize(getSize());
}
bool HasDirectVirtualBases = false;
bool HasNonVirtualBaseWithVBTable = false;
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual()) {
HasDirectVirtualBases = true;
continue;
}
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
if (BaseDecl->getNumVBases())
HasNonVirtualBaseWithVBTable = true;
if (BaseDecl == PrimaryBase && !PrimaryBaseIsVirtual)
continue;
BaseSubobjectInfo *BaseInfo = NonVirtualBaseInfo.lookup(BaseDecl);
assert(BaseInfo && "Did not find base info for non-virtual base!");
LayoutNonVirtualBase(BaseInfo);
}
if (isMicrosoftCXXABI() &&
HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) {
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
CharUnits PtrAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
PtrAlign = std::max(PtrAlign, Alignment);
EnsureVTablePointerAlignment(PtrAlign);
VBPtrOffset = getSize();
setSize(getSize() + PtrWidth);
setDataSize(getSize());
}
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
CharUnits Offset = LayoutBase(Base);
assert(!Bases.count(Base->Class) && "base offset already exists!");
Bases.insert(std::make_pair(Base->Class, Offset));
AddPrimaryVirtualBaseOffsets(Base, Offset);
}
void
RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset) {
if (!Info->Class->getNumVBases())
return;
if (Info->PrimaryVirtualBaseInfo) {
assert(Info->PrimaryVirtualBaseInfo->IsVirtual &&
"Primary virtual base is not virtual!");
if (Info->PrimaryVirtualBaseInfo->Derived == Info) {
assert(!VBases.count(Info->PrimaryVirtualBaseInfo->Class) &&
"primary vbase offset already exists!");
VBases.insert(std::make_pair(Info->PrimaryVirtualBaseInfo->Class,
ASTRecordLayout::VBaseInfo(Offset, false)));
AddPrimaryVirtualBaseOffsets(Info->PrimaryVirtualBaseInfo, Offset);
}
}
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
const BaseSubobjectInfo *Base = Info->Bases[I];
if (Base->IsVirtual)
continue;
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
AddPrimaryVirtualBaseOffsets(Base, BaseOffset);
}
}
bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const {
assert(!PrimaryBase);
if (!isMicrosoftCXXABI())
return RD->isDynamicClass();
if (!RD->isPolymorphic()) return false;
if (RD->getNumVBases() == 0) return true;
return hasNewVirtualFunction(RD);
}
static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD,
const ClassSetTy &set) {
for (CXXRecordDecl::base_class_const_iterator
I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual()) continue;
const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
if (set.count(base))
return true;
if (hasNonVirtualBaseInSet(base, set))
return true;
}
return false;
}
static bool overridesMethodRequiringVtorDisp(const ASTContext &Context,
const CXXMethodDecl *M) {
CXXMethodDecl::method_iterator
I = M->begin_overridden_methods(), E = M->end_overridden_methods();
if (I == E) return false;
const ASTRecordLayout::VBaseOffsetsMapTy &offsets =
Context.getASTRecordLayout(M->getParent()).getVBaseOffsetsMap();
do {
const CXXMethodDecl *overridden = *I;
ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
it = offsets.find(overridden->getParent());
if (it == offsets.end()) continue;
if (it->second.hasVtorDisp()) return true;
} while (++I != E);
return false;
}
void RecordLayoutBuilder::computeVtordisps(const CXXRecordDecl *RD,
ClassSetTy &vtordispVBases) {
assert(RD->getNumVBases());
ClassSetTy undecidedVBases;
for (CXXRecordDecl::base_class_const_iterator
I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *vbase = I->getType()->getAsCXXRecordDecl();
undecidedVBases.insert(vbase);
}
assert(!undecidedVBases.empty());
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
const ASTRecordLayout &baseLayout = Context.getASTRecordLayout(base);
for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
VI = baseLayout.getVBaseOffsetsMap().begin(),
VE = baseLayout.getVBaseOffsetsMap().end(); VI != VE; ++VI) {
if (!VI->second.hasVtorDisp()) continue;
if (!undecidedVBases.erase(VI->first))
continue;
vtordispVBases.insert(VI->first);
if (undecidedVBases.empty())
return;
}
}
ClassSetTy overriddenBases;
for (CXXRecordDecl::method_iterator
M = RD->method_begin(), E = RD->method_end(); M != E; ++M) {
if (isa<CXXDestructorDecl>(*M) || !M->isVirtual())
continue;
for (CXXMethodDecl::method_iterator I = M->begin_overridden_methods(),
E = M->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *overriddenMethod = (*I);
if (overridesMethodRequiringVtorDisp(Context, overriddenMethod))
continue;
const CXXRecordDecl *overriddenBase = overriddenMethod->getParent();
if (undecidedVBases.erase(overriddenBase)) {
vtordispVBases.insert(overriddenBase);
if (undecidedVBases.empty()) return;
}
overriddenBases.insert(overriddenBase);
}
}
for (ClassSetTy::const_iterator
I = undecidedVBases.begin(), E = undecidedVBases.end(); I != E; ++I) {
if (hasNonVirtualBaseInSet(*I, overriddenBases))
vtordispVBases.insert(*I);
}
}
bool
RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD,
bool IgnoreDestructor) const {
if (!RD->getNumBases())
return true;
for (CXXRecordDecl::method_iterator method = RD->method_begin();
method != RD->method_end();
++method) {
if (method->isVirtual() && !method->size_overridden_methods() &&
!(IgnoreDestructor && method->getKind() == Decl::CXXDestructor)) {
return true;
}
}
return false;
}
bool
RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *base) const {
if (!isMicrosoftCXXABI())
return base->isDynamicClass();
if (!base->isPolymorphic()) return false;
if (!base->getNumVBases()) return true;
const ASTRecordLayout &layout = Context.getASTRecordLayout(base);
if (layout.hasOwnVFPtr()) return true;
if (layout.getPrimaryBase()) return true;
return false;
}
void
RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase;
bool PrimaryBaseIsVirtual;
if (MostDerivedClass == RD) {
PrimaryBase = this->PrimaryBase;
PrimaryBaseIsVirtual = this->PrimaryBaseIsVirtual;
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
if (I->isVirtual()) {
if (PrimaryBase != BaseDecl || !PrimaryBaseIsVirtual) {
bool IndirectPrimaryBase = IndirectPrimaryBases.count(BaseDecl);
if (!IndirectPrimaryBase) {
if (!VisitedVirtualBases.insert(BaseDecl))
continue;
const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
assert(BaseInfo && "Did not find virtual base info!");
LayoutVirtualBase(BaseInfo);
}
}
}
if (!BaseDecl->getNumVBases()) {
continue;
}
LayoutVirtualBases(BaseDecl, MostDerivedClass);
}
}
void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
if (!RD->getNumVBases())
return;
ClassSetTy VtordispVBases;
computeVtordisps(RD, VtordispVBases);
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
assert(BaseInfo && "Did not find virtual base info!");
bool vtordispNeeded = false;
if (VtordispVBases.count(BaseDecl)) {
CharUnits IntSize =
CharUnits::fromQuantity(Context.getTargetInfo().getIntWidth() / 8);
setSize(getSize() + IntSize);
setDataSize(getSize());
vtordispNeeded = true;
}
LayoutVirtualBase(BaseInfo, vtordispNeeded);
}
}
void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
bool IsVtordispNeed) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
CharUnits Offset = LayoutBase(Base);
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
VBases.insert(std::make_pair(Base->Class,
ASTRecordLayout::VBaseInfo(Offset, IsVtordispNeed)));
if (!isMicrosoftCXXABI())
AddPrimaryVirtualBaseOffsets(Base, Offset);
}
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
CharUnits Offset;
bool HasExternalLayout = false;
if (ExternalLayout) {
llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known;
if (Base->IsVirtual) {
Known = ExternalVirtualBaseOffsets.find(Base->Class);
if (Known != ExternalVirtualBaseOffsets.end()) {
Offset = Known->second;
HasExternalLayout = true;
}
} else {
Known = ExternalBaseOffsets.find(Base->Class);
if (Known != ExternalBaseOffsets.end()) {
Offset = Known->second;
HasExternalLayout = true;
}
}
}
if (Base->Class->isEmpty() &&
(!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
return CharUnits::Zero();
}
CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
if (!MaxFieldAlignment.isZero()) {
BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
}
if (!HasExternalLayout) {
Offset = getDataSize().RoundUpToAlignment(BaseAlign);
while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
Offset += BaseAlign;
} else {
bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
(void)Allowed;
assert(Allowed && "Base subobject externally placed at overlapping offset");
if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){
Alignment = CharUnits::One();
InferAlignment = false;
}
}
if (!Base->Class->isEmpty()) {
setDataSize(Offset + Layout.getNonVirtualSize());
setSize(std::max(getSize(), getDataSize()));
} else
setSize(std::max(getSize(), Offset + Layout.getSize()));
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
return Offset;
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
IsMsStruct = D->hasAttr<MsStructAttr>();
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
}
if (D->hasAttr<AlignMac68kAttr>()) {
IsMac68kAlign = true;
MaxFieldAlignment = CharUnits::fromQuantity(2);
Alignment = CharUnits::fromQuantity(2);
} else {
if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
if (unsigned MaxAlign = D->getMaxAlignment())
UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
}
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
if (ExternalASTSource *External = Context.getExternalSource()) {
ExternalLayout = External->layoutRecordType(RD,
ExternalSize,
ExternalAlign,
ExternalFieldOffsets,
ExternalBaseOffsets,
ExternalVirtualBaseOffsets);
if (ExternalLayout) {
if (ExternalAlign > 0) {
Alignment = Context.toCharUnitsFromBits(ExternalAlign);
} else {
InferAlignment = true;
}
}
}
}
void RecordLayoutBuilder::Layout(const RecordDecl *D) {
InitializeLayout(D);
LayoutFields(D);
FinishLayout(D);
}
void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
InitializeLayout(RD);
LayoutNonVirtualBases(RD);
LayoutFields(RD);
NonVirtualSize = Context.toCharUnitsFromBits(
llvm::RoundUpToAlignment(getSizeInBits(),
Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
if (isMicrosoftCXXABI()) {
if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
CharUnits AlignMember =
NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
setSize(getSize() + AlignMember);
setDataSize(getSize());
NonVirtualSize = Context.toCharUnitsFromBits(
llvm::RoundUpToAlignment(getSizeInBits(),
Context.getTargetInfo().getCharAlign()));
}
MSLayoutVirtualBases(RD);
} else {
LayoutVirtualBases(RD, RD);
}
FinishLayout(RD);
#ifndef NDEBUG
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual())
continue;
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
assert(Bases.count(BaseDecl) && "Did not find base offset!");
}
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
assert(VBases.count(BaseDecl) && "Did not find base offset!");
}
#endif
}
void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD);
UpdateAlignment(SL.getAlignment());
setSize(SL.getDataSize());
setDataSize(getSize());
}
InitializeLayout(D);
for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD;
IVD = IVD->getNextIvar())
LayoutField(IVD);
FinishLayout(D);
}
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
const FieldDecl *LastFD = 0;
ZeroLengthBitfield = 0;
unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
if (IsMsStruct) {
FieldDecl *FD = *Field;
if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
ZeroLengthBitfield = FD;
else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
continue;
else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
Context.BitfieldFollowsNonBitfield(FD, LastFD) ||
Context.NonBitfieldFollowsBitfield(FD, LastFD)) {
std::pair<uint64_t, unsigned> FieldInfo =
Context.getTypeInfo(FD->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
if (TypeSize > FieldAlign &&
(Context.hasSameType(FD->getType(),
Context.UnsignedLongLongTy)
||Context.hasSameType(FD->getType(),
Context.LongLongTy)))
FieldAlign = TypeSize;
FieldInfo = Context.getTypeInfo(LastFD->getType());
uint64_t TypeSizeLastFD = FieldInfo.first;
unsigned FieldAlignLastFD = FieldInfo.second;
if (TypeSizeLastFD > FieldAlignLastFD &&
(Context.hasSameType(LastFD->getType(),
Context.UnsignedLongLongTy)
|| Context.hasSameType(LastFD->getType(),
Context.LongLongTy)))
FieldAlignLastFD = TypeSizeLastFD;
if (TypeSizeLastFD != TypeSize) {
if (RemainingInAlignment &&
LastFD && LastFD->isBitField() &&
LastFD->getBitWidthValue(Context)) {
uint64_t FieldOffset =
getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
RemainingInAlignment = 0;
}
uint64_t UnpaddedFieldOffset =
getDataSizeInBits() - UnfilledBitsInLastByte;
FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
if (!MaxFieldAlignment.isZero()) {
unsigned MaxFieldAlignmentInBits =
Context.toBits(MaxFieldAlignment);
FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
}
uint64_t NewSizeInBits =
llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
}
if (FD->isBitField()) {
uint64_t FieldSize = FD->getBitWidthValue(Context);
assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
if (RemainingInAlignment < FieldSize)
RemainingInAlignment = TypeSize - FieldSize;
else
RemainingInAlignment -= FieldSize;
}
}
else if (FD->isBitField()) {
uint64_t FieldSize = FD->getBitWidthValue(Context);
std::pair<uint64_t, unsigned> FieldInfo =
Context.getTypeInfo(FD->getType());
uint64_t TypeSize = FieldInfo.first;
RemainingInAlignment = TypeSize - FieldSize;
}
LastFD = FD;
}
else if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
ZeroLengthBitfield = *Field;
}
LayoutField(*Field);
}
if (IsMsStruct && RemainingInAlignment &&
LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {
uint64_t FieldOffset =
getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
}
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
uint64_t TypeSize,
bool FieldPacked,
const FieldDecl *D) {
assert(Context.getLangOpts().CPlusPlus &&
"Can only have wide bit-fields in C++!");
QualType IntegralPODTypes[] = {
Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
Context.UnsignedLongTy, Context.UnsignedLongLongTy
};
QualType Type;
for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes);
I != E; ++I) {
uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]);
if (Size > FieldSize)
break;
Type = IntegralPODTypes[I];
}
assert(!Type.isNull() && "Did not find a type!");
CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
if (IsUnion) {
setDataSize(std::max(getDataSizeInBits(), FieldSize));
FieldOffset = 0;
} else {
FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
FieldOffsets.push_back(FieldOffset);
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
Context.toBits(TypeAlign), FieldPacked, D);
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
UpdateAlignment(TypeAlign);
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidthValue(Context);
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
if (IsMsStruct && (TypeSize > FieldAlign) &&
(Context.hasSameType(D->getType(),
Context.UnsignedLongLongTy)
|| Context.hasSameType(D->getType(), Context.LongLongTy)))
FieldAlign = TypeSize;
if (ZeroLengthBitfield) {
std::pair<uint64_t, unsigned> FieldInfo;
unsigned ZeroLengthBitfieldAlignment;
if (IsMsStruct) {
if (ZeroLengthBitfield != D) {
FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType());
ZeroLengthBitfieldAlignment = FieldInfo.second;
if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
FieldAlign = ZeroLengthBitfieldAlignment;
if (FieldSize)
ZeroLengthBitfield = 0;
}
} else {
unsigned ZeroLengthBitfieldBoundary =
Context.getTargetInfo().getZeroLengthBitfieldBoundary();
if (ZeroLengthBitfieldBoundary > FieldAlign)
FieldAlign = ZeroLengthBitfieldBoundary;
}
}
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
}
unsigned UnpackedFieldAlign = FieldAlign;
uint64_t UnpackedFieldOffset = FieldOffset;
if (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield)
UnpackedFieldAlign = 1;
if (FieldPacked ||
(!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield))
FieldAlign = 1;
FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
if (!MaxFieldAlignment.isZero() && FieldSize != 0) {
unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() &&
(FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() &&
(UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
UnpackedFieldAlign);
if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment())
FieldAlign = UnpackedFieldAlign = 1;
if (!IsMsStruct)
ZeroLengthBitfield = 0;
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
FieldOffsets.push_back(FieldOffset);
if (!ExternalLayout)
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
UnpackedFieldAlign, FieldPacked, D);
if (IsUnion) {
setDataSize(std::max(getDataSizeInBits(), FieldSize));
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign),
Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (D->isBitField()) {
LayoutBitField(D);
return;
}
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
UnfilledBitsInLastByte = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
CharUnits FieldOffset =
IsUnion ? CharUnits::Zero() : getDataSize();
CharUnits FieldSize;
CharUnits FieldAlign;
if (D->getType()->isIncompleteArrayType()) {
FieldSize = CharUnits::Zero();
const ArrayType* ATy = Context.getAsArrayType(D->getType());
FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
FieldSize =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
FieldAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
} else {
std::pair<CharUnits, CharUnits> FieldInfo =
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
if (ZeroLengthBitfield) {
CharUnits ZeroLengthBitfieldBoundary =
Context.toCharUnitsFromBits(
Context.getTargetInfo().getZeroLengthBitfieldBoundary());
if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) {
std::pair<CharUnits, CharUnits> FieldInfo =
Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
if (ZeroLengthBitfieldAlignment > FieldAlign)
FieldAlign = ZeroLengthBitfieldAlignment;
} else if (ZeroLengthBitfieldBoundary > FieldAlign) {
assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
"ZeroLengthBitfieldBoundary should only be used in conjunction"
" with useZeroLengthBitfieldAlignment.");
FieldAlign = ZeroLengthBitfieldBoundary;
}
ZeroLengthBitfield = 0;
}
if (Context.getLangOpts().MSBitfields || IsMsStruct) {
QualType T = Context.getBaseElementType(D->getType());
if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
if (TypeSize > FieldAlign)
FieldAlign = TypeSize;
}
}
}
CharUnits UnpackedFieldAlign = FieldAlign;
CharUnits UnpackedFieldOffset = FieldOffset;
if (FieldPacked)
FieldAlign = CharUnits::One();
CharUnits MaxAlignmentInChars =
Context.toCharUnitsFromBits(D->getMaxAlignment());
FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
if (!MaxFieldAlignment.isZero()) {
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
UnpackedFieldOffset =
UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
if (ExternalLayout) {
FieldOffset = Context.toCharUnitsFromBits(
updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
if (!IsUnion && EmptySubobjects) {
bool Allowed = EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset);
(void)Allowed;
assert(Allowed && "Externally-placed field cannot be placed here");
}
} else {
if (!IsUnion && EmptySubobjects) {
while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
FieldOffset += FieldAlign;
}
}
}
FieldOffsets.push_back(Context.toBits(FieldOffset));
if (!ExternalLayout)
CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
Context.toBits(UnpackedFieldOffset),
Context.toBits(UnpackedFieldAlign), FieldPacked, D);
uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
setDataSize(std::max(getDataSizeInBits(), FieldSizeInBits));
else
setDataSize(FieldOffset + FieldSize);
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
UpdateAlignment(FieldAlign, UnpackedFieldAlign);
}
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (RD->isEmpty())
setSize(CharUnits::One());
}
else
setSize(CharUnits::One());
}
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
uint64_t RoundedSize
= llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment));
if (ExternalLayout) {
if (InferAlignment && ExternalSize < RoundedSize) {
Alignment = CharUnits::One();
InferAlignment = false;
}
setSize(ExternalSize);
return;
}
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (isMicrosoftCXXABI() && RD->getNumVBases())
return;
}
setSize(RoundedSize);
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
if (getSizeInBits() > UnpaddedSize) {
unsigned PadSize = getSizeInBits() - UnpaddedSize;
bool InBits = true;
if (PadSize % CharBitNum == 0) {
PadSize = PadSize / CharBitNum;
InBits = false;
}
Diag(RD->getLocation(), diag::warn_padded_struct_size)
<< Context.getTypeDeclType(RD)
<< PadSize
<< (InBits ? 1 : 0) << (PadSize > 1); }
if (Packed && UnpackedAlignment > CharUnits::One() &&
getSize() == UnpackedSize)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
}
void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
CharUnits UnpackedNewAlignment) {
if (IsMac68kAlign || (ExternalLayout && !InferAlignment))
return;
if (NewAlignment > Alignment) {
assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() &&
"Alignment not a power of 2"));
Alignment = NewAlignment;
}
if (UnpackedNewAlignment > UnpackedAlignment) {
assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() &&
"Alignment not a power of 2"));
UnpackedAlignment = UnpackedNewAlignment;
}
}
uint64_t
RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
uint64_t ComputedOffset) {
assert(ExternalFieldOffsets.find(Field) != ExternalFieldOffsets.end() &&
"Field does not have an external offset");
uint64_t ExternalFieldOffset = ExternalFieldOffsets[Field];
if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
Alignment = CharUnits::One();
InferAlignment = false;
}
return ExternalFieldOffset;
}
static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) {
switch (Tag) {
case TTK_Struct: return 0;
case TTK_Interface: return 1;
case TTK_Class: return 2;
default: llvm_unreachable("Invalid tag kind for field padding diagnostic!");
}
}
void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
uint64_t UnpaddedOffset,
uint64_t UnpackedOffset,
unsigned UnpackedAlign,
bool isPacked,
const FieldDecl *D) {
if (isa<ObjCIvarDecl>(D))
return;
if (D->getLocation().isInvalid())
return;
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
if (!IsUnion && Offset > UnpaddedOffset) {
unsigned PadSize = Offset - UnpaddedOffset;
bool InBits = true;
if (PadSize % CharBitNum == 0) {
PadSize = PadSize / CharBitNum;
InBits = false;
}
if (D->getIdentifier())
Diag(D->getLocation(), diag::warn_padded_struct_field)
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) << (PadSize > 1) << D->getIdentifier();
else
Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) << (PadSize > 1); }
if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< D->getIdentifier();
}
const CXXMethodDecl *
RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!RD->isPolymorphic())
return 0;
if (RD->getLinkage() != ExternalLinkage)
return 0;
TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
if (TSK == TSK_ImplicitInstantiation ||
TSK == TSK_ExplicitInstantiationDefinition)
return 0;
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
if (!MD->isVirtual())
continue;
if (MD->isPure())
continue;
if (MD->isImplicit())
continue;
if (MD->isInlineSpecified())
continue;
if (MD->hasInlineBody())
continue;
if (!MD->isUserProvided())
continue;
return MD;
}
return 0;
}
DiagnosticBuilder
RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
return Context.getDiagnostics().Report(Loc, DiagID);
}
const ASTRecordLayout &
ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (D->hasExternalLexicalStorage() && !D->getDefinition())
getExternalSource()->CompleteType(const_cast<RecordDecl*>(D));
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
const ASTRecordLayout *Entry = ASTRecordLayouts[D];
if (Entry) return *Entry;
const ASTRecordLayout *NewEntry;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
RecordLayoutBuilder Builder(*this, &EmptySubobjects);
Builder.Layout(RD);
if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) &&
(Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) {
Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment);
Builder.Layout(RD);
}
bool IsPODForThePurposeOfLayout =
(!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD());
CharUnits DataSize =
IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
Builder.HasOwnVFPtr,
Builder.VBPtrOffset,
DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
Builder.Bases, Builder.VBases);
} else {
RecordLayoutBuilder Builder(*this, 0);
Builder.Layout(D);
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
ASTRecordLayouts[D] = NewEntry;
if (getLangOpts().DumpRecordLayouts) {
llvm::errs() << "\n*** Dumping AST Record Layout\n";
DumpRecordLayout(D, llvm::errs(), getLangOpts().DumpRecordLayoutsSimple);
}
return *NewEntry;
}
const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
RD = cast<CXXRecordDecl>(RD->getDefinition());
assert(RD && "Cannot get key function for forward declarations!");
const CXXMethodDecl *&Entry = KeyFunctions[RD];
if (!Entry)
Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
return Entry;
}
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
const ASTRecordLayout &Layout = C.getASTRecordLayout(FD->getParent());
return Layout.getFieldOffset(FD->getFieldIndex());
}
uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {
uint64_t OffsetInBits;
if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
OffsetInBits = ::getFieldOffset(*this, FD);
} else {
const IndirectFieldDecl *IFD = cast<IndirectFieldDecl>(VD);
OffsetInBits = 0;
for (IndirectFieldDecl::chain_iterator CI = IFD->chain_begin(),
CE = IFD->chain_end();
CI != CE; ++CI)
OffsetInBits += ::getFieldOffset(*this, cast<FieldDecl>(*CI));
}
return OffsetInBits;
}
const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) const {
if (D->hasExternalLexicalStorage() && !D->getDefinition())
getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl*>(D));
D = D->getDefinition();
assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!");
const ObjCContainerDecl *Key =
Impl ? (const ObjCContainerDecl*) Impl : (const ObjCContainerDecl*) D;
if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
return *Entry;
if (Impl) {
unsigned SynthCount = CountNonClassIvars(D);
if (SynthCount == 0)
return getObjCLayout(D, 0);
}
RecordLayoutBuilder Builder(*this, 0);
Builder.Layout(D);
const ASTRecordLayout *NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
ObjCLayouts[Key] = NewEntry;
return *NewEntry;
}
static void PrintOffset(raw_ostream &OS,
CharUnits Offset, unsigned IndentLevel) {
OS << llvm::format("%4" PRId64 " | ", (int64_t)Offset.getQuantity());
OS.indent(IndentLevel * 2);
}
static void DumpCXXRecordLayout(raw_ostream &OS,
const CXXRecordDecl *RD, const ASTContext &C,
CharUnits Offset,
unsigned IndentLevel,
const char* Description,
bool IncludeVirtualBases) {
const ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
PrintOffset(OS, Offset, IndentLevel);
OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString();
if (Description)
OS << ' ' << Description;
if (RD->isEmpty())
OS << " (empty)";
OS << '\n';
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
bool HasVfptr = Layout.hasOwnVFPtr();
bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
if (RD->isDynamicClass() && !PrimaryBase &&
C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (I->isVirtual())
continue;
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
Base == PrimaryBase ? "(primary base)" : "(base)",
false);
}
if (HasVfptr) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vftable pointer)\n";
}
if (HasVbptr) {
PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
OS << '(' << *RD << " vbtable pointer)\n";
}
uint64_t FieldNo = 0;
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl &Field = **I;
CharUnits FieldOffset = Offset +
C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
if (const RecordType *RT = Field.getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
Field.getName().data(),
true);
continue;
}
}
PrintOffset(OS, FieldOffset, IndentLevel);
OS << Field.getType().getAsString() << ' ' << Field << '\n';
}
if (!IncludeVirtualBases)
return;
const ASTRecordLayout::VBaseOffsetsMapTy &vtordisps =
Layout.getVBaseOffsetsMap();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
assert(I->isVirtual() && "Found non-virtual class!");
const CXXRecordDecl *VBase =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
if (vtordisps.find(VBase)->second.hasVtorDisp()) {
PrintOffset(OS, VBaseOffset - CharUnits::fromQuantity(4), IndentLevel);
OS << "(vtordisp for vbase " << *VBase << ")\n";
}
DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel,
VBase == PrimaryBase ?
"(primary virtual base)" : "(virtual base)",
false);
}
OS << " sizeof=" << Layout.getSize().getQuantity();
OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n';
OS << '\n';
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
raw_ostream &OS,
bool Simple) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
if (!Simple)
return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
if (!Simple) {
OS << "Record: ";
RD->dump();
}
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
if (i) OS << ", ";
OS << Info.getFieldOffset(i);
}
OS << "]>\n";
}