From bbf58bb1b8dd8c5e0f07547a6c20ffd55385fcf6 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 10 Mar 2010 02:19:29 +0000 Subject: [PATCH] Delay codegen of vtables when handling implicit instantiations. This fixes PR6474. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98123 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGVtable.cpp | 38 +++++++++++-------- lib/CodeGen/CGVtable.h | 18 ++++----- lib/CodeGen/CodeGenModule.cpp | 10 ++++- lib/CodeGen/CodeGenModule.h | 4 +- lib/Sema/SemaDeclCXX.cpp | 11 ++++-- .../virtual-base-destructor-call.cpp | 10 ++--- .../SemaTemplate/virtual-member-functions.cpp | 4 +- 7 files changed, 58 insertions(+), 37 deletions(-) diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 932bd079e9..a77a28ccdd 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -3405,7 +3405,22 @@ void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0, /*IsVirtual=*/false, AddressPoints); - GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if (!(*i)->isVirtual()) + continue; + if(!(*i)->hasInlineBody() && !(*i)->isImplicit()) + continue; + + if (const CXXDestructorDecl *DD = dyn_cast(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } } llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { @@ -3438,19 +3453,12 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { return; } - // Emit the data. - GenerateClassData(CGM.getVtableLinkage(RD), RD); + if (Vtables.count(RD)) + return; - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - if ((*i)->isVirtual() && ((*i)->hasInlineBody() || (*i)->isImplicit())) { - if (const CXXDestructorDecl *DD = dyn_cast(*i)) { - CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); - CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); - } else { - CGM.BuildThunksForVirtual(GlobalDecl(*i)); - } - } - } + TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); + if (kind == TSK_ImplicitInstantiation) + CGM.DeferredVtables.push_back(RD); + else + GenerateClassData(CGM.getVtableLinkage(RD), RD); } - diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 6ccb011985..57220d9d5a 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -173,15 +173,7 @@ private: uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); 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. - /// - /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. - void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); - + llvm::GlobalVariable * GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *LayoutClass, @@ -245,6 +237,14 @@ public: llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); void MaybeEmitVtable(GlobalDecl GD); + + /// 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. + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); }; } // end namespace CodeGen diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d6a56dad0b..c67948d27f 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -488,7 +488,15 @@ void CodeGenModule::EmitDeferred() { // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. - while (!DeferredDeclsToEmit.empty()) { + + while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) { + if (!DeferredVtables.empty()) { + const CXXRecordDecl *RD = DeferredVtables.back(); + DeferredVtables.pop_back(); + getVtableInfo().GenerateClassData(getVtableLinkage(RD), RD); + continue; + } + GlobalDecl D = DeferredDeclsToEmit.back(); DeferredDeclsToEmit.pop_back(); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c86f8b45bc..40dc563889 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -451,7 +451,9 @@ public: /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; - + + std::vector DeferredVtables; + private: /// UniqueMangledName - Unique a name by (if necessary) inserting it into the /// MangledNames string map. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a89f355147..79cab15e69 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5902,10 +5902,13 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, // We will need to mark all of the virtual members as referenced to build the // vtable. - // We actually call MarkVirtualMembersReferenced instead of adding to - // ClassesWithUnmarkedVirtualMembers because this marking is needed by - // codegen that will happend before we finish parsing the file. - if (needsVtable(MD, Context)) + if (!needsVtable(MD, Context)) + return; + + TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); + if (kind == TSK_ImplicitInstantiation) + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); + else MarkVirtualMembersReferenced(Loc, RD); } diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index b6e85e208b..7de9dd2a60 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -22,6 +22,11 @@ int main() { // CHECK: call void @_ZN14basic_iostreamIcED2Ev // CHECK: call void @_ZN9basic_iosD2Ev +// basic_iostream's base dtor calls its non-virtual base dtor. +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev +// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: } + // basic_iostream's deleting dtor calls its complete dtor, then // operator delete(). // CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev @@ -40,11 +45,6 @@ int main() { // CHECK: call void @_ZN13basic_istreamIcED1Ev // CHECK: call void @_ZdlPv -// basic_iostream's base dtor calls its non-virtual base dtor. -// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev -// CHECK: call void @_ZN13basic_istreamIcED2Ev -// CHECK: } - // basic_istream's base dtor is a no-op. // CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev // CHECK-NOT: call diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp index 58ac08c0b2..8df808d256 100644 --- a/test/SemaTemplate/virtual-member-functions.cpp +++ b/test/SemaTemplate/virtual-member-functions.cpp @@ -14,7 +14,7 @@ template int A::a(T x) { } void f(A x) { - x.anchor(); // expected-note{{in instantiation of member function 'PR5557::A::anchor' requested here}} + x.anchor(); } template @@ -52,4 +52,4 @@ T *HasOutOfLineKey::f(float *fp) { return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}} } -HasOutOfLineKey out_of_line; // expected-note{{in instantiation of member function 'HasOutOfLineKey::HasOutOfLineKey' requested here}} +HasOutOfLineKey out_of_line;