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.cpp907
1 files changed, 714 insertions, 193 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 3782985..983a287 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1,4 +1,4 @@
-//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==//
+//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==//
//
// The LLVM Compiler Infrastructure
//
@@ -7,28 +7,443 @@
//
//===----------------------------------------------------------------------===//
-#include "RecordLayoutBuilder.h"
-
#include "clang/AST/Attr.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 "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
+#include <map>
using namespace clang;
-ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context)
- : Context(Context), Size(0), Alignment(8), Packed(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false),
- NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
+namespace {
+
+/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
+/// offsets while laying out a C++ class.
+class EmptySubobjectMap {
+ ASTContext &Context;
+
+ /// Class - The class whose empty entries we're keeping track of.
+ const CXXRecordDecl *Class;
+
+ /// EmptyClassOffsets - A map from offsets to empty record decls.
+ typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
+ typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy;
+ EmptyClassOffsetsMapTy EmptyClassOffsets;
+
+ /// ComputeEmptySubobjectSizes - Compute the size of the largest base or
+ /// member subobject that is empty.
+ void ComputeEmptySubobjectSizes();
+
+ struct BaseInfo {
+ const CXXRecordDecl *Class;
+ bool IsVirtual;
+
+ const CXXRecordDecl *PrimaryVirtualBase;
+
+ llvm::SmallVector<BaseInfo*, 4> Bases;
+ const BaseInfo *Derived;
+ };
+
+ llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> VirtualBaseInfo;
+ llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> NonVirtualBaseInfo;
+
+ BaseInfo *ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual,
+ const BaseInfo *Derived);
+ void ComputeBaseInfo();
+
+ bool CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info, uint64_t Offset);
+ void UpdateEmptyBaseSubobjects(const BaseInfo *Info, uint64_t Offset);
+
+public:
+ /// This holds the size of the largest empty subobject (either a base
+ /// or a member). Will be zero if the record being built doesn't contain
+ /// any empty classes.
+ uint64_t SizeOfLargestEmptySubobject;
+
+ EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
+ : Context(Context), Class(Class), SizeOfLargestEmptySubobject(0) {
+ ComputeEmptySubobjectSizes();
+
+ ComputeBaseInfo();
+ }
+
+ /// CanPlaceBaseAtOffset - Return whether the given base class can be placed
+ /// at the given offset.
+ /// Returns false if placing the record will result in two components
+ /// (direct or indirect) of the same type having the same offset.
+ bool CanPlaceBaseAtOffset(const CXXRecordDecl *RD, bool BaseIsVirtual,
+ uint64_t Offset);
+};
+
+void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
+ // Check the bases.
+ 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());
+
+ uint64_t EmptySize = 0;
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ if (BaseDecl->isEmpty()) {
+ // If the class decl is empty, get its size.
+ EmptySize = Layout.getSize();
+ } else {
+ // Otherwise, we get the largest empty subobject for the decl.
+ EmptySize = Layout.getSizeOfLargestEmptySubobject();
+ }
+
+ SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
+ EmptySize);
+ }
+
+ // Check the fields.
+ for (CXXRecordDecl::field_iterator I = Class->field_begin(),
+ E = Class->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ const RecordType *RT =
+ Context.getBaseElementType(FD->getType())->getAs<RecordType>();
+
+ // We only care about record types.
+ if (!RT)
+ continue;
+
+ uint64_t EmptySize = 0;
+ const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
+ if (MemberDecl->isEmpty()) {
+ // If the class decl is empty, get its size.
+ EmptySize = Layout.getSize();
+ } else {
+ // Otherwise, we get the largest empty subobject for the decl.
+ EmptySize = Layout.getSizeOfLargestEmptySubobject();
+ }
+
+ SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
+ EmptySize);
+ }
+}
+
+EmptySubobjectMap::BaseInfo *
+EmptySubobjectMap::ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual,
+ const BaseInfo *Derived) {
+ BaseInfo *Info;
+
+ if (IsVirtual) {
+ BaseInfo *&InfoSlot = VirtualBaseInfo[RD];
+ if (InfoSlot) {
+ assert(InfoSlot->Class == RD && "Wrong class for virtual base info!");
+ return InfoSlot;
+ }
+
+ InfoSlot = new (Context) BaseInfo;
+ Info = InfoSlot;
+ } else {
+ Info = new (Context) BaseInfo;
+ }
+
+ Info->Class = RD;
+ Info->IsVirtual = IsVirtual;
+ Info->Derived = Derived;
+ Info->PrimaryVirtualBase = 0;
+
+ if (RD->getNumVBases()) {
+ // Check if this class has a primary virtual base.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ if (Layout.getPrimaryBaseWasVirtual()) {
+ Info->PrimaryVirtualBase = Layout.getPrimaryBase();
+ assert(Info->PrimaryVirtualBase &&
+ "Didn't have a primary virtual base!");
+ }
+ }
+
+ 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(ComputeBaseInfo(BaseDecl, IsVirtual, Info));
+ }
+
+ return Info;
+}
+
+void EmptySubobjectMap::ComputeBaseInfo() {
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end(); I != E; ++I) {
+ bool IsVirtual = I->isVirtual();
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ BaseInfo *Info = ComputeBaseInfo(BaseDecl, IsVirtual, /*Derived=*/0);
+ if (IsVirtual) {
+ // ComputeBaseInfo has already added this base for us.
+ continue;
+ }
+
+ // Add the base info to the map of non-virtual bases.
+ assert(!NonVirtualBaseInfo.count(BaseDecl) &&
+ "Non-virtual base already exists!");
+ NonVirtualBaseInfo.insert(std::make_pair(BaseDecl, Info));
+ }
+}
+
+bool
+EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info,
+ uint64_t Offset) {
+ // Traverse all non-virtual bases.
+ for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
+ BaseInfo* Base = Info->Bases[I];
+ if (Base->IsVirtual)
+ continue;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+
+ if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset))
+ return false;
+ }
+
+ if (Info->PrimaryVirtualBase) {
+ BaseInfo *PrimaryVirtualBaseInfo =
+ VirtualBaseInfo.lookup(Info->PrimaryVirtualBase);
+ assert(PrimaryVirtualBaseInfo && "Didn't find base info!");
+
+ if (Info == PrimaryVirtualBaseInfo->Derived) {
+ if (!CanPlaceBaseSubobjectAtOffset(PrimaryVirtualBaseInfo, Offset))
+ return false;
+ }
+ }
+
+ // FIXME: Member variables.
+ return true;
+}
+
+void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseInfo *Info,
+ uint64_t Offset) {
+ if (Info->Class->isEmpty()) {
+ // FIXME: Record that there is an empty class at this offset.
+ }
+
+ // Traverse all non-virtual bases.
+ for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
+ BaseInfo* Base = Info->Bases[I];
+ if (Base->IsVirtual)
+ continue;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+
+ UpdateEmptyBaseSubobjects(Base, BaseOffset);
+ }
+
+ if (Info->PrimaryVirtualBase) {
+ BaseInfo *PrimaryVirtualBaseInfo =
+ VirtualBaseInfo.lookup(Info->PrimaryVirtualBase);
+ assert(PrimaryVirtualBaseInfo && "Didn't find base info!");
+
+ if (Info == PrimaryVirtualBaseInfo->Derived)
+ UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset);
+ }
+
+ // FIXME: Member variables.
+}
+
+bool EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD,
+ bool BaseIsVirtual,
+ uint64_t Offset) {
+ // If we know this class doesn't have any empty subobjects we don't need to
+ // bother checking.
+ if (!SizeOfLargestEmptySubobject)
+ return true;
+
+ BaseInfo *Info;
+
+ if (BaseIsVirtual)
+ Info = VirtualBaseInfo.lookup(RD);
+ else
+ Info = NonVirtualBaseInfo.lookup(RD);
+
+ if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))
+ return false;
+
+ UpdateEmptyBaseSubobjects(Info, Offset);
+ return true;
+}
+
+class RecordLayoutBuilder {
+ // FIXME: Remove this and make the appropriate fields public.
+ friend class clang::ASTContext;
+
+ ASTContext &Context;
+
+ EmptySubobjectMap *EmptySubobjects;
+
+ /// 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.
+ unsigned Packed : 1;
+
+ unsigned IsUnion : 1;
+
+ unsigned IsMac68kAlign : 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
+ /// an adjacent bitfield if necessary.
+ unsigned char UnfilledBitsInLastByte;
+
+ /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
+ /// #pragma pack.
+ unsigned MaxFieldAlignment;
+
+ /// DataSize - The data size of the record being laid out.
+ uint64_t DataSize;
+
+ uint64_t NonVirtualSize;
+ unsigned NonVirtualAlignment;
+
+ /// PrimaryBase - the primary base class (if one exists) of the class
+ /// we're laying out.
+ const CXXRecordDecl *PrimaryBase;
+
+ /// PrimaryBaseIsVirtual - Whether the primary base of the class we're laying
+ /// out is virtual.
+ bool PrimaryBaseIsVirtual;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
+
+ /// Bases - base classes and their offsets in the record.
+ BaseOffsetsMapTy Bases;
+
+ // VBases - virtual base classes and their offsets in the record.
+ BaseOffsetsMapTy VBases;
+
+ /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
+ /// primary base classes for some other direct or indirect base class.
+ llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+
+ /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
+ /// inheritance graph order. Used for determining the primary base class.
+ const CXXRecordDecl *FirstNearlyEmptyVBase;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
+ /// EmptyClassOffsets - A map from offsets to empty record decls.
+ typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
+ EmptyClassOffsetsTy EmptyClassOffsets;
+
+ RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
+ : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
+ Packed(false), IsUnion(false), IsMac68kAlign(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
+ NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
+ PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
+
+ 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);
+ void LayoutBitField(const FieldDecl *D);
+
+ /// ComputeEmptySubobjectSizes - Compute the size of the largest base or
+ /// member subobject that is empty.
+ void ComputeEmptySubobjectSizes(const CXXRecordDecl *RD);
+
+ /// DeterminePrimaryBase - Determine the primary base of the given class.
+ void DeterminePrimaryBase(const CXXRecordDecl *RD);
+
+ void SelectPrimaryVBase(const CXXRecordDecl *RD);
+
+ /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
+ /// indirect, that are primary base classes for some other direct or indirect
+ /// base class.
+ void IdentifyPrimaryBases(const CXXRecordDecl *RD);
+
+ bool IsNearlyEmpty(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.
+ void LayoutNonVirtualBases(const CXXRecordDecl *RD);
+
+ /// LayoutNonVirtualBase - Lays out a single non-virtual base.
+ void LayoutNonVirtualBase(const CXXRecordDecl *Base);
+
+ void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBases - Lays out all the virtual bases.
+ void LayoutVirtualBases(const CXXRecordDecl *RD,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBase - Lays out a single virtual base.
+ void LayoutVirtualBase(const CXXRecordDecl *Base);
+
+ /// LayoutBase - Will lay out a base and return the offset where it was
+ /// placed, in bits.
+ uint64_t LayoutBase(const CXXRecordDecl *Base, bool BaseIsVirtual);
+
+ /// canPlaceRecordAtOffset - Return whether a record (either a base class
+ /// or a field) can be placed at the given offset.
+ /// Returns false if placing the record will result in two components
+ /// (direct or indirect) of the same type having the same offset.
+ bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset,
+ bool CheckVBases) const;
+
+ /// canPlaceFieldAtOffset - Return whether a field can be placed at the given
+ /// offset.
+ bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const;
+
+ /// UpdateEmptyClassOffsets - Called after a record (either a base class
+ /// or a field) has been placed at the given offset. Will update the
+ /// EmptyClassOffsets map if the class is empty or has any empty bases or
+ /// fields.
+ void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ bool UpdateVBases);
+
+ /// UpdateEmptyClassOffsets - Called after a field has been placed at the
+ /// given offset.
+ void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
+
+ /// InitializeLayout - Initialize record layout for the given record decl.
+ void InitializeLayout(const Decl *D);
+
+ /// FinishLayout - Finalize record layout. Adjust record size based on the
+ /// alignment.
+ void FinishLayout();
+
+ void UpdateAlignment(unsigned NewAlignment);
+
+ RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+ void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+public:
+ static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
+};
+} // end anonymous namespace
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
-bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
+bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
// FIXME: Audit the corners
if (!RD->isDynamicClass())
return false;
@@ -38,7 +453,7 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
return false;
}
-void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
@@ -63,7 +478,7 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
+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() &&
@@ -77,8 +492,8 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
// If it's not an indirect primary base, then we've found our primary
// base.
if (!IndirectPrimaryBases.count(Base)) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base,
- /*IsVirtual=*/true);
+ PrimaryBase = Base;
+ PrimaryBaseIsVirtual = true;
return;
}
@@ -88,13 +503,13 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
SelectPrimaryVBase(Base);
- if (PrimaryBase.getBase())
+ if (PrimaryBase)
return;
}
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
-void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the class isn't dynamic, it won't have a primary base.
if (!RD->isDynamicClass())
return;
@@ -124,7 +539,8 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
if (Base->isDynamicClass()) {
// We found it.
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false);
+ PrimaryBase = Base;
+ PrimaryBaseIsVirtual = false;
return;
}
}
@@ -133,20 +549,20 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// indirect primary virtual base class, if one exists.
if (RD->getNumVBases() != 0) {
SelectPrimaryVBase(RD);
- if (PrimaryBase.getBase())
+ if (PrimaryBase)
return;
}
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
if (FirstNearlyEmptyVBase) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
- /*IsVirtual=*/true);
+ PrimaryBase = FirstNearlyEmptyVBase;
+ PrimaryBaseIsVirtual = true;
return;
}
// Otherwise there is no primary base class.
- assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
+ assert(!PrimaryBase && "Should not get here with a primary base!");
// Allocate the virtual table pointer at offset zero.
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
@@ -160,22 +576,23 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
+RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// First, determine the primary base class.
DeterminePrimaryBase(RD);
// If we have a primary base class, lay it out.
- if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
- if (PrimaryBase.isVirtual()) {
+ if (PrimaryBase) {
+ if (PrimaryBaseIsVirtual) {
// We have a virtual primary base, insert it as an indirect primary base.
- IndirectPrimaryBases.insert(Base);
+ IndirectPrimaryBases.insert(PrimaryBase);
- assert(!VisitedVirtualBases.count(Base) && "vbase already visited!");
- VisitedVirtualBases.insert(Base);
-
- LayoutVirtualBase(Base);
+ assert(!VisitedVirtualBases.count(PrimaryBase) &&
+ "vbase already visited!");
+ VisitedVirtualBases.insert(PrimaryBase);
+
+ LayoutVirtualBase(PrimaryBase);
} else
- LayoutNonVirtualBase(Base);
+ LayoutNonVirtualBase(PrimaryBase);
}
// Now lay out the non-virtual bases.
@@ -190,7 +607,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
// Skip the primary base.
- if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual())
+ if (Base == PrimaryBase && !PrimaryBaseIsVirtual)
continue;
// Lay out the base.
@@ -198,17 +615,17 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
}
}
-void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(RD);
+ uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/false);
// Add its base class offset.
- if (!Bases.insert(std::make_pair(RD, Offset)).second)
+ if (!Bases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same base offset more than once!");
}
void
-ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
+RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
uint64_t Offset,
const CXXRecordDecl *MostDerivedClass) {
// We already have the offset for the primary base of the most derived class.
@@ -226,7 +643,7 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
@@ -234,17 +651,17 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
// This base isn't interesting since it doesn't have any virtual bases.
continue;
}
-
+
// Compute the offset of this base.
uint64_t BaseOffset;
-
+
if (I->isVirtual()) {
// If we don't know this vbase yet, don't visit it. It will be visited
// later.
if (!VBases.count(BaseDecl)) {
continue;
}
-
+
// Check if we've already visited this base.
if (!VisitedVirtualBases.insert(BaseDecl))
continue;
@@ -265,14 +682,14 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
}
void
-ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase;
bool PrimaryBaseIsVirtual;
if (MostDerivedClass == RD) {
- PrimaryBase = this->PrimaryBase.getBase();
- PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual();
+ PrimaryBase = this->PrimaryBase;
+ PrimaryBaseIsVirtual = this->PrimaryBaseIsVirtual;
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
@@ -296,7 +713,7 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
// Only visit virtual bases once.
if (!VisitedVirtualBases.insert(Base))
continue;
-
+
LayoutVirtualBase(Base);
}
}
@@ -311,58 +728,64 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
-void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(RD);
+ uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/true);
// Add its base class offset.
- if (!VBases.insert(std::make_pair(RD, Offset)).second)
+ if (!VBases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same vbase offset more than once!");
}
-uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
+uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *Base,
+ bool BaseIsVirtual) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base);
// If we have an empty base class, try to place it at offset 0.
- if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
+ if (Base->isEmpty() &&
+ EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, 0) &&
+ canPlaceRecordAtOffset(Base, 0, /*CheckVBases=*/false)) {
// We were able to place the class at offset 0.
- UpdateEmptyClassOffsets(RD, 0);
+ UpdateEmptyClassOffsets(Base, 0, /*UpdateVBases=*/false);
- Size = std::max(Size, BaseInfo.getSize());
+ Size = std::max(Size, Layout.getSize());
return 0;
}
- unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+ unsigned BaseAlign = Layout.getNonVirtualAlign();
// Round up the current record size to the base's alignment boundary.
uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
// Try to place the base.
while (true) {
- if (canPlaceRecordAtOffset(RD, Offset))
+ if (EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, Offset) &&
+ canPlaceRecordAtOffset(Base, Offset, /*CheckVBases=*/false))
break;
Offset += BaseAlign;
}
- if (!RD->isEmpty()) {
+ if (!Base->isEmpty()) {
// Update the data size.
- DataSize = Offset + BaseInfo.getNonVirtualSize();
+ DataSize = Offset + Layout.getNonVirtualSize();
Size = std::max(Size, DataSize);
} else
- Size = std::max(Size, Offset + BaseInfo.getSize());
+ Size = std::max(Size, Offset + Layout.getSize());
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign);
- UpdateEmptyClassOffsets(RD, Offset);
+ UpdateEmptyClassOffsets(Base, Offset, /*UpdateVBases=*/false);
return Offset;
}
-bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const {
+bool
+RecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ bool CheckVBases) const {
// Look for an empty class with the same type at the same offset.
for (EmptyClassOffsetsTy::const_iterator I =
EmptyClassOffsets.lower_bound(Offset),
@@ -372,7 +795,7 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
return false;
}
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Check bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -382,12 +805,13 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
if (I->isVirtual())
continue;
- const CXXRecordDecl *Base =
+ const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+ uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl);
- if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
+ if (!canPlaceRecordAtOffset(BaseDecl, Offset + BaseOffset,
+ /*CheckVBases=*/false))
return false;
}
@@ -397,22 +821,25 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
- uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset))
return false;
}
- // FIXME: virtual bases.
+ if (CheckVBases) {
+ // FIXME: virtual bases.
+ }
+
return true;
}
-bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
+bool RecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
uint64_t Offset) const {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return canPlaceRecordAtOffset(RD, Offset);
+ return canPlaceRecordAtOffset(RD, Offset, /*CheckVBases=*/true);
}
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
@@ -424,27 +851,28 @@ bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
if (!RD)
return true;
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
- if (!canPlaceRecordAtOffset(RD, ElementOffset))
+ if (!canPlaceRecordAtOffset(RD, ElementOffset, /*CheckVBases=*/true))
return false;
- ElementOffset += Info.getSize();
+ ElementOffset += Layout.getSize();
}
}
return true;
}
-void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
- uint64_t Offset) {
+void RecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ bool UpdateVBases) {
if (RD->isEmpty())
EmptyClassOffsets.insert(std::make_pair(Offset, RD));
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Update bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -457,8 +885,9 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
- UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
+ uint64_t BaseClassOffset = Layout.getBaseClassOffset(Base);
+ UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset,
+ /*UpdateVBases=*/false);
}
// Update fields.
@@ -467,21 +896,30 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
- uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
UpdateEmptyClassOffsets(FD, Offset + FieldOffset);
}
- // FIXME: Update virtual bases.
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (UpdateVBases) {
+ // FIXME: Update virtual bases.
+ } else if (PrimaryBase && Layout.getPrimaryBaseWasVirtual()) {
+ // We always want to update the offsets of a primary virtual base.
+ assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
+ "primary base class offset must always be 0!");
+ UpdateEmptyClassOffsets(PrimaryBase, Offset, /*UpdateVBases=*/false);
+ }
}
void
-ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
+RecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- UpdateEmptyClassOffsets(RD, Offset);
+ UpdateEmptyClassOffsets(RD, Offset, /*UpdateVBases=*/true);
return;
}
}
@@ -501,76 +939,90 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
- UpdateEmptyClassOffsets(RD, ElementOffset);
+ UpdateEmptyClassOffsets(RD, ElementOffset, /*UpdateVBases=*/true);
ElementOffset += Info.getSize();
}
}
}
-void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
- IsUnion = D->isUnion();
+void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
- // The #pragma pack attribute specifies the maximum field alignment.
- if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
- MaxFieldAlignment = PPA->getAlignment();
-
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getMaxAlignment());
+ // mac68k alignment supersedes maximum field alignment and attribute aligned,
+ // and forces all structures to have 2-byte alignment. The IBM docs on it
+ // allude to additional (more complicated) semantics, especially with regard
+ // to bit-fields, but gcc appears not to follow that.
+ if (D->hasAttr<AlignMac68kAttr>()) {
+ IsMac68kAlign = true;
+ MaxFieldAlignment = 2 * 8;
+ Alignment = 2 * 8;
+ } else {
+ if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
+ MaxFieldAlignment = MFAA->getAlignment();
- // If this is a C++ class, lay out the vtable and the non-virtual bases.
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (RD)
- LayoutNonVirtualBases(RD);
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ UpdateAlignment(AA->getMaxAlignment());
+ }
+}
+void RecordLayoutBuilder::Layout(const RecordDecl *D) {
+ InitializeLayout(D);
LayoutFields(D);
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ FinishLayout();
+}
+
+void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
+ InitializeLayout(RD);
+
+ // Lay out the vtable and the non-virtual bases.
+ LayoutNonVirtualBases(RD);
+
+ LayoutFields(RD);
+
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- // If this is a C++ class, lay out its virtual bases and add its primary
- // virtual base offsets.
- if (RD) {
- LayoutVirtualBases(RD, RD);
+ // Lay out the virtual bases and add the primary virtual base offsets.
+ LayoutVirtualBases(RD, RD);
- VisitedVirtualBases.clear();
- AddPrimaryVirtualBaseOffsets(RD, 0, RD);
- }
+ VisitedVirtualBases.clear();
+ AddPrimaryVirtualBaseOffsets(RD, 0, RD);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
FinishLayout();
-
+
#ifndef NDEBUG
- if (RD) {
- // Check that we have base offsets for all bases.
- 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!");
- }
-
- // And all virtual bases.
- 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!");
- }
+ // Check that we have base offsets for all bases.
+ 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!");
+ }
+
+ // And all virtual bases.
+ 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
}
-// FIXME. Impl is no longer needed.
-void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
+void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD);
@@ -582,14 +1034,8 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
DataSize = Size;
}
- Packed = D->hasAttr<PackedAttr>();
-
- // The #pragma pack attribute specifies the maximum field alignment.
- if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
- MaxFieldAlignment = PPA->getAlignment();
+ InitializeLayout(D);
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
Context.ShallowCollectObjCIvars(D, Ivars);
@@ -601,7 +1047,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
FinishLayout();
}
-void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *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.
for (RecordDecl::field_iterator Field = D->field_begin(),
@@ -609,17 +1055,17 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
-void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
+void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
uint64_t TypeSize) {
assert(Context.getLangOptions().CPlusPlus &&
"Can only have wide bit-fields in C++!");
-
+
// Itanium C++ ABI 2.4:
- // If sizeof(T)*8 < n, let T' be the largest integral POD type with
+ // If sizeof(T)*8 < n, let T' be the largest integral POD type with
// sizeof(T')*8 <= n.
-
+
QualType IntegralPODTypes[] = {
- Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
+ Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
Context.UnsignedLongTy, Context.UnsignedLongLongTy
};
@@ -634,24 +1080,24 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
Type = IntegralPODTypes[I];
}
assert(!Type.isNull() && "Did not find a type!");
-
+
unsigned TypeAlign = Context.getTypeAlign(Type);
// We're not going to use any of the unfilled bits in the last byte.
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
-
+
if (IsUnion) {
DataSize = std::max(DataSize, FieldSize);
FieldOffset = 0;
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
- // for T', with length n bits.
+ // for T', with length n bits.
FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign);
-
+
uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
+
DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
UnfilledBitsInLastByte = DataSize - NewSizeInBits;
}
@@ -661,12 +1107,12 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
// Update the size.
Size = std::max(Size, DataSize);
-
+
// Remember max struct/class alignment.
UpdateAlignment(TypeAlign);
}
-void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
@@ -718,7 +1164,7 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UpdateAlignment(FieldAlign);
}
-void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (D->isBitField()) {
LayoutBitField(D);
return;
@@ -791,7 +1237,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
UpdateAlignment(FieldAlign);
}
-void ASTRecordLayoutBuilder::FinishLayout() {
+void RecordLayoutBuilder::FinishLayout() {
// In C++, records cannot be of size 0.
if (Context.getLangOptions().CPlusPlus && Size == 0)
Size = 8;
@@ -800,7 +1246,11 @@ void ASTRecordLayoutBuilder::FinishLayout() {
Size = llvm::RoundUpToAlignment(Size, Alignment);
}
-void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+ // The alignment is not modified when using 'mac68k' alignment.
+ if (IsMac68kAlign)
+ return;
+
if (NewAlignment <= Alignment)
return;
@@ -809,55 +1259,8 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
Alignment = NewAlignment;
}
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const RecordDecl *D) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D);
-
- if (!isa<CXXRecordDecl>(D))
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- Builder.Size,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
-
- // FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
- uint64_t NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
-
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- DataSize, Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size(),
- NonVirtualSize,
- Builder.NonVirtualAlignment,
- Builder.PrimaryBase,
- Builder.Bases, Builder.VBases);
-}
-
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D, Impl);
-
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- Builder.DataSize,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-}
-
const CXXMethodDecl *
-ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
assert(RD->isDynamicClass() && "Class does not have any virtual methods!");
// If a class isn't polymorphic it doesn't have a key function.
@@ -898,6 +1301,124 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
return 0;
}
+/// getASTRecordLayout - Get or compute information about the layout of the
+/// specified record (struct/union/class), which indicates its size and field
+/// position information.
+const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
+ D = D->getDefinition();
+ assert(D && "Cannot get layout of forward declarations!");
+
+ // Look up this layout, if already laid out, return what we have.
+ // Note that we can't save a reference to the entry because this function
+ // is recursive.
+ 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);
+
+ // FIXME: This is not always correct. See the part about bitfields at
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
+ // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
+ bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+
+ // FIXME: This should be done in FinalizeLayout.
+ uint64_t DataSize =
+ IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
+ uint64_t NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+
+ NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ DataSize, Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(),
+ NonVirtualSize,
+ Builder.NonVirtualAlignment,
+ EmptySubobjects.SizeOfLargestEmptySubobject,
+ Builder.PrimaryBase,
+ Builder.PrimaryBaseIsVirtual,
+ Builder.Bases, Builder.VBases);
+ } else {
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ Builder.Layout(D);
+
+ NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ Builder.Size,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+ }
+
+ ASTRecordLayouts[D] = NewEntry;
+
+ if (getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::errs());
+ }
+
+ 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);
+ else
+ assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) &&
+ "Key function changed!");
+
+ return Entry;
+}
+
+/// getInterfaceLayoutImpl - Get or compute information about the
+/// layout of the given interface.
+///
+/// \param Impl - If given, also include the layout of the interface's
+/// implementation. This may differ by including synthesized ivars.
+const ASTRecordLayout &
+ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ assert(!D->isForwardDecl() && "Invalid interface decl!");
+
+ // Look up this layout, if already laid out, return what we have.
+ ObjCContainerDecl *Key =
+ Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
+ if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
+ return *Entry;
+
+ // Add in synthesized ivar count if laying out an implementation.
+ if (Impl) {
+ unsigned SynthCount = CountNonClassIvars(D);
+ // If there aren't any sythesized ivars then reuse the interface
+ // entry. Note we can't cache this because we simply free all
+ // entries later; however we shouldn't look up implementations
+ // frequently.
+ if (SynthCount == 0)
+ return getObjCLayout(D, 0);
+ }
+
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ Builder.Layout(D);
+
+ const ASTRecordLayout *NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ Builder.DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+
+ ObjCLayouts[Key] = NewEntry;
+
+ return *NewEntry;
+}
+
static void PrintOffset(llvm::raw_ostream &OS,
uint64_t Offset, unsigned IndentLevel) {
OS << llvm::format("%4d | ", Offset);
OpenPOWER on IntegriCloud