From: Anders Carlsson Date: Mon, 30 Nov 2009 23:41:22 +0000 (+0000) Subject: Have ASTRecordLayout keep track of the key function, in preparation of fixing a synth... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1a5e0d7f18485e4fb958f96dcddff3e4486a4069;p=clang Have ASTRecordLayout keep track of the key function, in preparation of fixing a synthetic ctor/dtor bug. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90168 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index a8334b6940..5d2973ea9d 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -119,6 +119,13 @@ private: /// VBaseOffsets - Contains a map from vbase classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap VBaseOffsets; + + /// KeyFunction - The key function, according to the Itanium C++ ABI, + /// section 5.2.3: + /// + /// ...the first non-pure virtual function that is not inline at the point + /// of class definition. + const CXXMethodDecl *KeyFunction; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -147,7 +154,8 @@ private: const std::pair *bases, unsigned numbases, const std::pair *vbases, - unsigned numvbases) + unsigned numvbases, + const CXXMethodDecl *KeyFunction) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { if (FieldCount > 0) { @@ -163,6 +171,7 @@ private: CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; for (unsigned i = 0; i != numvbases; ++i) CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; + CXXInfo->KeyFunction = KeyFunction; } ~ASTRecordLayout() { @@ -245,6 +254,13 @@ public: return CXXInfo->VBaseOffsets[VBase]; } + /// getKeyFunction - Get the key function. + const CXXMethodDecl *getKeyFunction() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->KeyFunction; + } + primary_base_info_iterator primary_base_begin() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index d104e3a769..326a1dcd27 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -663,6 +663,31 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } +static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) { + if (!RD->isDynamicClass()) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + const FunctionDecl *fn; + if (MD->getBody(fn) && !fn->isOutOfLine()) + continue; + + // We found it. + return MD; + } + + return 0; +} + const ASTRecordLayout * ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, const RecordDecl *D) { @@ -686,6 +711,8 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, uint64_t NonVirtualSize = IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + const CXXMethodDecl *KeyFunction = GetKeyFunction(cast(D)); + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), @@ -695,7 +722,8 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.Bases.data(), Builder.Bases.size(), Builder.VBases.data(), - Builder.VBases.size()); + Builder.VBases.size(), + KeyFunction); } const ASTRecordLayout * diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index edf19f78c8..1a9bc39170 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -330,32 +330,6 @@ void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) { } -static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) { - const CXXRecordDecl *RD = dyn_cast(D); - if (!RD || !RD->isDynamicClass()) - return 0; - - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - if (MD->isPure()) - continue; - - const FunctionDecl *fn; - if (MD->getBody(fn) && !fn->isOutOfLine()) - continue; - - // We found it. - return MD; - } - - return 0; -} - CGRecordLayout * CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, const RecordDecl *D) { @@ -385,7 +359,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); } - const CXXMethodDecl *KeyFunction = GetKeyFunction(D); - - return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction); + return new CGRecordLayout(Ty, Builder.ContainsMemberPointer); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 224c829a5b..715aa4c03c 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -1060,10 +1060,10 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, if (LayoutClass != RD) CreateDefinition = true; else { - // We have to convert it to have a record layout. - Types.ConvertTagDeclType(LayoutClass); - const CGRecordLayout &CGLayout = Types.getCGRecordLayout(LayoutClass); - if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + const ASTRecordLayout &Layout = + getContext().getASTRecordLayout(LayoutClass); + + if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { if (!KeyFunction->getBody()) { // If there is a KeyFunction, and it isn't defined, just build a // reference to the vtable. @@ -1316,10 +1316,9 @@ llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { vtbl = CGM.GenerateVtable(RD, RD); bool CreateDefinition = true; - // We have to convert it to have a record layout. - CGM.getTypes().ConvertTagDeclType(RD); - const CGRecordLayout &CGLayout = CGM.getTypes().getCGRecordLayout(RD); - if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { if (!KeyFunction->getBody()) { // If there is a KeyFunction, and it isn't defined, just build a // reference to the vtable. @@ -1339,3 +1338,31 @@ llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, uint64_t Offset) { return CGM.GenerateVtable(LayoutClass, RD, Offset); } + +void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const CXXRecordDecl *RD = MD->getParent(); + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + // Get the key function. + const CXXMethodDecl *KeyFunction = Layout.getKeyFunction(); + + if (!KeyFunction) { + // If there's no key function, we don't want to emit the vtable here. + return; + } + + // Check if we have the key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + + // If the key function is a destructor, we only want to emit the vtable once, + // so do it for the complete destructor. + if (isa(MD) && GD.getDtorType() != Dtor_Complete) + return; + + // Emit the data. + GenerateClassData(RD); +} + diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index ac3cdee63b..5c2b74c9dd 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -91,6 +91,11 @@ class CGVtableInfo { void ComputeMethodVtableIndices(const CXXRecordDecl *RD); + /// GenerateClassData - Generate all the class data requires to be generated + /// upon definition of a KeyFunction. This includes the vtable, the + /// rtti data structure and the VTT. + void GenerateClassData(const CXXRecordDecl *RD); + public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -111,10 +116,9 @@ public: llvm::Constant *getVtable(const CXXRecordDecl *RD); llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset); - /// GenerateClassData - Generate all the class data requires to be generated - /// upon definition of a KeyFunction. This includes the vtable, the - /// rtti data structure and the VTT. - void GenerateClassData(const CXXRecordDecl *RD); + + + void MaybeEmitVtable(GlobalDecl GD); }; } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a14733aba0..4b3b122b71 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" @@ -614,18 +615,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (const CXXMethodDecl *MD = dyn_cast(D)) { - const CXXRecordDecl *RD = MD->getParent(); - // We have to convert it to have a record layout. - Types.ConvertTagDeclType(RD); - const CGRecordLayout &CGLayout = Types.getCGRecordLayout(RD); - // A definition of a KeyFunction, generates all the class data, such - // as vtable, rtti and the VTT. - if (CGLayout.getKeyFunction() - && (CGLayout.getKeyFunction()->getCanonicalDecl() - == MD->getCanonicalDecl())) - getVtableInfo().GenerateClassData(RD); - } + if (isa(D)) + getVtableInfo().MaybeEmitVtable(GD); + if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast(D)) diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 55827aac49..2ff602f900 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -64,17 +64,9 @@ namespace CodeGen { /// is a member pointer, or a struct that contains a member pointer. bool ContainsMemberPointer; - /// KeyFunction - The key function of the record layout (if one exists), - /// which is the first non-pure virtual function that is not inline at the - /// point of class definition. - /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable. - const CXXMethodDecl *KeyFunction; - public: - CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer, - const CXXMethodDecl *KeyFunction) - : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer), - KeyFunction(KeyFunction) { } + CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer) + : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { } /// getLLVMType - Return llvm type associated with this record. const llvm::Type *getLLVMType() const { @@ -84,10 +76,6 @@ namespace CodeGen { bool containsMemberPointer() const { return ContainsMemberPointer; } - - const CXXMethodDecl *getKeyFunction() const { - return KeyFunction; - } }; /// CodeGenTypes - This class organizes the cross-module state that is used