From: Anders Carlsson Date: Thu, 24 Sep 2009 05:21:31 +0000 (+0000) Subject: More improvements with laying out empty bases. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ffbdefc7a24c01a0f77425423278774796a3aa53;p=clang More improvements with laying out empty bases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82682 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 062ce4f5bc..dec6402d36 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -230,7 +230,25 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return false; } - // FIXME: Bases and fields. + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Check bases. + 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(I->getType()->getAs()->getDecl()); + + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + + if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) + return false; + } + + // FIXME: fields. + // FIXME: virtual bases. return true; } @@ -238,8 +256,23 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset) { if (RD->isEmpty()) EmptyClassOffsets.insert(std::make_pair(Offset, RD)); + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Update bases. + 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(I->getType()->getAs()->getDecl()); - // FIXME: Update bases and fields. + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); + } + + // FIXME: Update fields and virtual bases. } uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { @@ -248,25 +281,35 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { // If we have an empty base class, try to place it at offset 0. if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { // We were able to place the class at offset 0. - // Since the base is empty we don't have to update the size or alignment. UpdateEmptyClassOffsets(RD, 0); - + + Size = std::max(Size, BaseInfo.getNonVirtualSize()); + return 0; } unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + // Round up the current record size to the base's alignment boundary. uint64_t Offset = llvm::RoundUpToAlignment(Size, BaseAlign); - // Reserve space for this base. - Size = Offset + BaseInfo.getNonVirtualSize(); - + // Try to place the base. + while (true) { + if (canPlaceRecordAtOffset(RD, Offset)) + break; + + Offset += BaseAlign; + } + // Remember the next available offset. - NextOffset = Size; + NextOffset = Offset + BaseInfo.getNonVirtualSize(); + + Size = std::max(Size, NextOffset); // Remember max struct/class alignment. UpdateAlignment(BaseAlign); - + + UpdateEmptyClassOffsets(RD, Offset); return Offset; } diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp index 24688fad07..ebbeb38fc9 100644 --- a/test/SemaCXX/empty-class-layout.cpp +++ b/test/SemaCXX/empty-class-layout.cpp @@ -10,3 +10,10 @@ SA(1, sizeof(B) == 1); struct C : A, B { }; SA(2, sizeof(C) == 4); + +struct D { }; +struct E : D { }; +struct F : E { }; + +struct G : E, F { }; +SA(3, sizeof(G) == 2);