diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 8a3e08965f4d..78598b795626 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -219,8 +219,18 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, } } -void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, - bool IsVirtualBase) { +bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, + uint64_t Offset) const { + // FIXME: Implement. + return true; +} + +void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, + uint64_t Offset) { + // FIXME: Implement. +} + +uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); if (!Bases.empty()) { assert(BaseInfo.getDataSize() > 0 && @@ -229,15 +239,32 @@ void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, 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); + uint64_t Offset = llvm::RoundUpToAlignment(Size, BaseAlign); + + // Reserve space for this base. + Size = Offset + BaseSize; + + // Remember the next available offset. + NextOffset = Size; + + // Remember max struct/class alignment. + UpdateAlignment(BaseAlign); + + return Offset; +} + +void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, + bool IsVirtualBase) { + // Layout the base. + unsigned Offset = LayoutBase(RD); // Add base class offsets. if (IsVirtualBase) - VBases.push_back(std::make_pair(RD, Size)); + VBases.push_back(std::make_pair(RD, Offset)); else - Bases.push_back(std::make_pair(RD, Size)); + Bases.push_back(std::make_pair(RD, Offset)); #if 0 // And now add offsets for all our primary virtual bases as well, so @@ -254,15 +281,6 @@ void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, L = &Ctx.getASTRecordLayout(PB); } #endif - - // Reserve space for this base. - Size += BaseSize; - - // Remember the next available offset. - NextOffset = Size; - - // Remember max struct/class alignment. - UpdateAlignment(BaseAlign); } void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { @@ -408,7 +426,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { FieldAlign = std::min(FieldAlign, MaxFieldAlignment); // Round up the current record size to the field's alignment boundary. - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); } // Place this field at the current location. diff --git a/clang/lib/AST/RecordLayoutBuilder.h b/clang/lib/AST/RecordLayoutBuilder.h index efc309155f0c..43563c6729b9 100644 --- a/clang/lib/AST/RecordLayoutBuilder.h +++ b/clang/lib/AST/RecordLayoutBuilder.h @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/DataTypes.h" +#include namespace clang { class ASTContext; @@ -53,6 +54,10 @@ class ASTRecordLayoutBuilder { /// primary base classes for some other direct or indirect base class. llvm::SmallSet IndirectPrimaryBases; + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef std::multimap EmptyClassOffsetsTy; + EmptyClassOffsetsTy EmptyClassOffsets; + ASTRecordLayoutBuilder(ASTContext &Ctx); void Layout(const RecordDecl *D); @@ -79,6 +84,10 @@ class ASTRecordLayoutBuilder { bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + /// LayoutBase - Will lay out a base and return the offset where it was + /// placed, in bits. + uint64_t LayoutBase(const CXXRecordDecl *RD); + void LayoutVtable(const CXXRecordDecl *RD); void LayoutNonVirtualBases(const CXXRecordDecl *RD); void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); @@ -88,6 +97,18 @@ class ASTRecordLayoutBuilder { llvm::SmallSet &mark, llvm::SmallSet &IndirectPrimary); + /// 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) 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); + /// FinishLayout - Finalize record layout. Adjust record size based on the /// alignment. void FinishLayout();