From: Anders Carlsson Date: Sun, 19 Jul 2009 00:18:47 +0000 (+0000) Subject: Handle layout of non-virtual base classes. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=74cbe226207fd101623638dadfa7fbada04ff2a6;p=clang Handle layout of non-virtual base classes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76348 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 41272fdbfe..1dcc4f8465 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -11,6 +11,7 @@ #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" @@ -20,9 +21,48 @@ using namespace clang; ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) - : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0), + : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0), IsUnion(false) {} +void +ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { + assert(!RD->isPolymorphic() && + "FIXME: We don't support polymorphic classes yet!"); + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast(i->getType()->getAsRecordType()->getDecl()); + LayoutNonVirtualBase(Base); + } + } +} + +void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(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(); + + // Round up the current record size to the base's alignment boundary. + Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1); + + // 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) { IsUnion = D->isUnion(); @@ -31,7 +71,11 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (const AlignedAttr *AA = D->getAttr()) UpdateAlignment(AA->getAlignment()); - + + // If this is a C++ class, lay out the nonvirtual bases. + if (Ctx.getLangOptions().CPlusPlus) + LayoutNonVirtualBases(cast(D)); + LayoutFields(D); // Finally, round the size of the total struct up to the alignment of the @@ -191,8 +235,20 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.Layout(D); - return new ASTRecordLayout(Builder.Size, Builder.Alignment, - Builder.NextOffset, + 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(); + } + + uint64_t DataSize = + IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset; + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); } diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 4a71b2b0eb..1545c37901 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -15,6 +15,7 @@ namespace clang { class ASTContext; class ASTRecordLayout; + class CXXRecordDecl; class FieldDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; @@ -34,12 +35,16 @@ class ASTRecordLayoutBuilder { ASTRecordLayoutBuilder(ASTContext &Ctx); void Layout(const RecordDecl *D); + void Layout(const CXXRecordDecl *D); void Layout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutNonVirtualBases(const CXXRecordDecl *RD); + void LayoutNonVirtualBase(const CXXRecordDecl *RD); + /// FinishLayout - Finalize record layout. Adjust record size based on the /// alignment. void FinishLayout(); diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp new file mode 100644 index 0000000000..0cb5a6d8ff --- /dev/null +++ b/test/SemaCXX/class-layout.cpp @@ -0,0 +1,31 @@ +// RUN: clang-cc -triple x86_64-unknown-unknown %s -fsyntax-only -verify + +#define SA(n, p) int a##n[(p) ? 1 : -1] + +struct A { + int a; + char b; +}; + +SA(0, sizeof(A) == 8); + +struct B : A { + char c; +}; + +SA(1, sizeof(B) == 12); + +struct C { +// Make fields private so C won't be a POD type. +private: + int a; + char b; +}; + +SA(2, sizeof(C) == 8); + +struct D : C { + char c; +}; + +SA(3, sizeof(D) == 8);