diff options
-rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.cpp | 12 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 76 | ||||
-rwxr-xr-x | clang/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp | 10 |
3 files changed, 91 insertions, 7 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 515088e67bb..ceb49ff0bf2 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2157,7 +2157,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Respect required alignment, this is necessary because we may have adjusted // the alignment in the case of pragam pack. Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment()); - Info.Size = Layout.getNonVirtualSize(); + Info.Size = Layout.getDataSize(); return Info; } @@ -2538,17 +2538,17 @@ void MicrosoftRecordLayoutBuilder::injectVPtrs(const CXXRecordDecl *RD) { // different from the general case layout but it may have to do with lazy // placement of zero sized bases. VBPtrOffset = Size; - if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) { + if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) { VBPtrOffset = Bases[LastBaseDecl]; - if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero()) + if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero()) VBPtrOffset = Bases[PenultBaseDecl]; } // Once we've located a spot for the vbptr, place it. VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment); Size = VBPtrOffset + PointerInfo.Size; - if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) { + if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) { // Add the padding between zero sized bases after the vbptr. - if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero()) + if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero()) Size += CharUnits::One(); Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment()); Bases[LastBaseDecl] = Size; @@ -2601,7 +2601,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
VBases.insert(std::make_pair(BaseDecl, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); - Size = BaseOffset + BaseLayout.getNonVirtualSize(); + Size = BaseOffset + BaseLayout.getDataSize(); updateAlignment(Info.Alignment); PreviousBaseLayout = &BaseLayout; } diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index c3338a17b36..3aa1f81c737 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -144,6 +144,11 @@ private: bool LayoutNonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + /// MSLayoutNonVirtualBases - layout the virtual bases of a record decl, + /// like MSVC. + bool MSLayoutNonVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout); + /// ComputeNonVirtualBaseType - Compute the non-virtual base field types. bool ComputeNonVirtualBaseType(const CXXRecordDecl *RD); @@ -708,6 +713,72 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, } bool +CGRecordLayoutBuilder::MSLayoutNonVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout) { + // Add a vfptr if the layout says to do so. + if (Layout.hasOwnVFPtr()) { + llvm::Type *FunctionType = + llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()), + /*isVarArg=*/true); + llvm::Type *VTableTy = FunctionType->getPointerTo(); + + if (getTypeAlignment(VTableTy) > Alignment) { + // FIXME: Should we allow this to happen in Sema? + assert(!Packed && "Alignment is wrong even with packed struct!"); + return false; + } + + assert(NextFieldOffset.isZero() && + "VTable pointer must come first!"); + AppendField(CharUnits::Zero(), VTableTy->getPointerTo()); + } + + // Layout the non-virtual bases that have leading vfptrs. + 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()); + const ASTRecordLayout &BaseLayout + = Types.getContext().getASTRecordLayout(BaseDecl); + + if (!BaseLayout.hasExtendableVFPtr()) + continue; + + if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl))) + return false; + } + + // Layout the non-virtual bases that don't have leading vfptrs. + 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()); + const ASTRecordLayout &BaseLayout + = Types.getContext().getASTRecordLayout(BaseDecl); + + if (BaseLayout.hasExtendableVFPtr()) + continue; + + if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl))) + return false; + } + + // Add a vb-table pointer if the layout insists. + if (Layout.hasOwnVBPtr()) { + CharUnits VBPtrOffset = Layout.getVBPtrOffset(); + llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext()); + AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr)); + AppendField(VBPtrOffset, Vbptr); + } + + return true; +} + +bool CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); @@ -755,7 +826,10 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); if (RD) - if (!LayoutNonVirtualBases(RD, Layout)) + if (Types.getTarget().getCXXABI().isMicrosoft()) { + if (!MSLayoutNonVirtualBases(RD, Layout)) + return false; + } else if (!LayoutNonVirtualBases(RD, Layout)) return false; unsigned FieldNo = 0; diff --git a/clang/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp b/clang/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp new file mode 100755 index 00000000000..f09c47e0fdc --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i686-pc-win32 -o - %s 2>/dev/null | FileCheck %s +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 -o - %s 2>/dev/null | FileCheck %s + +struct C0 { int a; }; +struct C1 { int a; virtual void C1M() {} }; +struct C2 { int a; virtual void C2M() {} }; +struct C3 : C0, C1, C2 {} a; + +// Check to see that both C1 and C2 get laid out before C0 does. +// CHECK: %struct.C3 = type { %struct.C1, %struct.C2, %struct.C0 } |