diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h index b7ae9c1cdcf6..4abe810f4025 100644 --- a/clang/include/clang/AST/RecordLayout.h +++ b/clang/include/clang/AST/RecordLayout.h @@ -20,6 +20,7 @@ namespace clang { class ASTContext; class FieldDecl; class RecordDecl; + class CXXRecordDecl; /// ASTRecordLayout - /// This class contains layout information for one RecordDecl, @@ -29,26 +30,78 @@ namespace clang { /// ObjCInterfaceDecl. FIXME - Find appropriate name. /// These objects are managed by ASTContext. class ASTRecordLayout { - uint64_t Size; // Size of record in bits. - uint64_t DataSize; // Size of record in bits without tail padding. + /// Size - Size of record in bits. + uint64_t Size; + + /// DataSize - Size of record in bits without tail padding. + uint64_t DataSize; + + /// FieldOffsets - Array of field offsets in bits. uint64_t *FieldOffsets; - unsigned Alignment; // Alignment of record in bits. - unsigned FieldCount; // Number of fields + + // Alignment - Alignment of record in bits. + unsigned Alignment; + + // FieldCount - Number of fields. + unsigned FieldCount; + + struct CXXRecordLayoutInfo { + /// NonVirtualSize - The non-virtual size (in bits) of an object, which is + /// the size of the object without virtual bases. + uint64_t NonVirtualSize; + + /// NonVirtualAlign - The non-virtual alignment (in bits) of an object, + /// which is the alignment of the object without virtual bases. + uint64_t NonVirtualAlign; + + /// BaseOffsets - Contains a map from base classes to their offset. + /// FIXME: Does it make sense to store offsets for virtual base classes + /// here? + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + llvm::DenseMap BaseOffsets; + }; + + /// CXXInfo - If the record layout is for a C++ record, this will have + /// C++ specific information about the record. + CXXRecordLayoutInfo *CXXInfo; + friend class ASTContext; friend class ASTRecordLayoutBuilder; ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize, const uint64_t *fieldoffsets, unsigned fieldcount) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), - FieldCount(fieldcount) { + FieldCount(fieldcount), CXXInfo(0) { if (FieldCount > 0) { FieldOffsets = new uint64_t[FieldCount]; for (unsigned i = 0; i < FieldCount; ++i) FieldOffsets[i] = fieldoffsets[i]; } } + + // Constructor for C++ records. + ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize, + const uint64_t *fieldoffsets, unsigned fieldcount, + uint64_t nonvirtualsize, unsigned nonvirtualalign, + const CXXRecordDecl **bases, const uint64_t *baseoffsets, + unsigned basecount) + : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), + FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { + if (FieldCount > 0) { + FieldOffsets = new uint64_t[FieldCount]; + for (unsigned i = 0; i < FieldCount; ++i) + FieldOffsets[i] = fieldoffsets[i]; + } + + CXXInfo->NonVirtualSize = nonvirtualsize; + CXXInfo->NonVirtualAlign = nonvirtualalign; + for (unsigned i = 0; i != basecount; ++i) + CXXInfo->BaseOffsets[bases[i]] = baseoffsets[i]; + } + ~ASTRecordLayout() { delete [] FieldOffsets; + delete CXXInfo; } ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT @@ -76,6 +129,30 @@ public: uint64_t getDataSize() const { return DataSize; } + + /// getNonVirtualSize - Get the non-virtual size (in bits) of an object, + /// which is the size of the object without virtual bases. + uint64_t getNonVirtualSize() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualSize; + } + + /// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object, + /// which is the alignment of the object without virtual bases. + unsigned getNonVirtualAlign() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualAlign; + } + + /// getBaseClassOffset - Get the offset, in bits, for the given base class. + uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return CXXInfo->BaseOffsets[Base]; + } }; } // end namespace clang diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index e78b31567547..e6479bf0f534 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -22,7 +22,7 @@ using namespace clang; ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0), - IsUnion(false) {} + IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {} void ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { @@ -44,15 +44,16 @@ void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { assert(BaseInfo.getDataSize() > 0 && "FIXME: Handle empty classes."); - // FIXME: Should get the non-virtual alignment of the base. - unsigned BaseAlign = BaseInfo.getAlignment(); - - // FIXME: Should get the non-virtual size of the base. - uint64_t BaseSize = BaseInfo.getDataSize(); + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + uint64_t BaseSize = BaseInfo.getNonVirtualSize(); // Round up the current record size to the base's alignment boundary. Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1); + // Add base class offsets. + Bases.push_back(RD); + BaseOffsets.push_back(Size); + // Non-virtual base class has offset too. FieldOffsets.push_back(Size); @@ -81,6 +82,9 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutFields(D); + NonVirtualSize = Size; + NonVirtualAlignment = Alignment; + // Finally, round the size of the total struct up to the alignment of the // struct itself. FinishLayout(); @@ -238,22 +242,33 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.Layout(D); - bool IsPODForThePurposeOfLayout; - if (!Ctx.getLangOptions().CPlusPlus) { - // In C, all record types are POD. - IsPODForThePurposeOfLayout = true; - } else { - // 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. - IsPODForThePurposeOfLayout = cast(D)->isPOD(); - } + if (!isa(D)) + return new ASTRecordLayout(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(D)->isPOD(); + + assert(Builder.Bases.size() == Builder.BaseOffsets.size() && + "Base offsets vector must be same size as bases vector!"); + + // FIXME: This should be done in FinalizeLayout. uint64_t DataSize = IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset; + uint64_t NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), - Builder.FieldOffsets.size()); + Builder.FieldOffsets.size(), + NonVirtualSize, + Builder.NonVirtualAlignment, + Builder.Bases.data(), + Builder.BaseOffsets.data(), + Builder.Bases.size()); } const ASTRecordLayout * diff --git a/clang/lib/AST/RecordLayoutBuilder.h b/clang/lib/AST/RecordLayoutBuilder.h index 51ee69be6aba..e7d49b55a8e8 100644 --- a/clang/lib/AST/RecordLayoutBuilder.h +++ b/clang/lib/AST/RecordLayoutBuilder.h @@ -26,13 +26,18 @@ class ASTRecordLayoutBuilder { ASTContext &Ctx; uint64_t Size; - uint64_t Alignment; + unsigned Alignment; llvm::SmallVector FieldOffsets; unsigned StructPacking; unsigned NextOffset; bool IsUnion; + uint64_t NonVirtualSize; + unsigned NonVirtualAlignment; + llvm::SmallVector Bases; + llvm::SmallVector BaseOffsets; + ASTRecordLayoutBuilder(ASTContext &Ctx); void Layout(const RecordDecl *D);