From: John McCall Date: Wed, 2 Jun 2010 21:22:02 +0000 (+0000) Subject: Don't try to emit the vtable for a class just because we're emitting a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e21323588b32caf674213c9897dd12e2f0ea3cc5;p=clang Don't try to emit the vtable for a class just because we're emitting a virtual function from it. Fixes PR7241. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105345 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 81e80cc26e..1aa9a11fc1 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -2745,7 +2745,7 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) const CXXRecordDecl *RD = MD->getParent(); // Compute VTable related info for this class. - ComputeVTableRelatedInformation(RD); + ComputeVTableRelatedInformation(RD, false); ThunksMapTy::const_iterator I = Thunks.find(MD); if (I == Thunks.end()) { @@ -2758,24 +2758,30 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) EmitThunk(GD, ThunkInfoVector[I]); } -void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { - uint64_t *&LayoutData = VTableLayoutMap[RD]; +void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD, + bool RequireVTable) { + VTableLayoutData &Entry = VTableLayoutMap[RD]; + + // We may need to generate a definition for this vtable. + if (RequireVTable && !Entry.getInt()) { + if (!isKeyFunctionInAnotherTU(CGM.getContext(), RD) && + RD->getTemplateSpecializationKind() + != TSK_ExplicitInstantiationDeclaration) + CGM.DeferredVTables.push_back(RD); + + Entry.setInt(true); + } // Check if we've computed this information before. - if (LayoutData) + if (Entry.getPointer()) return; - // We may need to generate a definition for this vtable. - if (!isKeyFunctionInAnotherTU(CGM.getContext(), RD) && - RD->getTemplateSpecializationKind() - != TSK_ExplicitInstantiationDeclaration) - CGM.DeferredVTables.push_back(RD); - VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); // Add the VTable layout. uint64_t NumVTableComponents = Builder.getNumVTableComponents(); - LayoutData = new uint64_t[NumVTableComponents + 1]; + uint64_t *LayoutData = new uint64_t[NumVTableComponents + 1]; + Entry.setPointer(LayoutData); // Store the number of components. LayoutData[0] = NumVTableComponents; @@ -2990,7 +2996,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { CGM.getMangleContext().mangleCXXVTable(RD, OutName); llvm::StringRef Name = OutName.str(); - ComputeVTableRelatedInformation(RD); + ComputeVTableRelatedInformation(RD, true); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); llvm::ArrayType *ArrayType = diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index e55377f2fa..4c790f92ab 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -207,8 +207,12 @@ class CodeGenVTables { /// Thunks - Contains all thunks that a given method decl will need. ThunksMapTy Thunks; - - typedef llvm::DenseMap VTableLayoutMapTy; + + // The layout entry and a bool indicating whether we've actually emitted + // the vtable. + typedef llvm::PointerIntPair VTableLayoutData; + typedef llvm::DenseMap + VTableLayoutMapTy; /// VTableLayoutMap - Stores the vtable layout for all record decls. /// The layout is stored as an array of 64-bit integers, where the first @@ -237,13 +241,13 @@ class CodeGenVTables { uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const { assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - return VTableLayoutMap.lookup(RD)[0]; + return VTableLayoutMap.lookup(RD).getPointer()[0]; } const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const { assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - uint64_t *Components = VTableLayoutMap.lookup(RD); + uint64_t *Components = VTableLayoutMap.lookup(RD).getPointer(); return &Components[1]; } @@ -275,7 +279,8 @@ class CodeGenVTables { /// ComputeVTableRelatedInformation - Compute and store all vtable related /// information (vtable layout, vbase offset offsets, thunks etc) for the /// given record decl. - void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); + void ComputeVTableRelatedInformation(const CXXRecordDecl *RD, + bool VTableRequired); /// CreateVTableInitializer - Create a vtable initializer for the given record /// decl. diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp index 79ca709f47..1de576128a 100644 --- a/test/CodeGenCXX/thunks.cpp +++ b/test/CodeGenCXX/thunks.cpp @@ -234,6 +234,18 @@ namespace Test8 { void C::bar(NonPOD var) {} } +// PR7241: Emitting thunks for a method shouldn't require the vtable for +// that class to be emitted. +namespace Test9 { + struct A { virtual ~A() { } }; + struct B : A { virtual void test() const {} }; + struct C : B { C(); ~C(); }; + struct D : C { D() {} }; + void test() { + D d; + } +} + /**** The following has to go at the end of the file ****/ // This is from Test5: diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index 22c49a089d..4618a03b9d 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -27,6 +27,11 @@ int main() { // 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 +// CHECK: } + // basic_iostream's deleting dtor calls its complete dtor, then // operator delete(). // CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev @@ -44,9 +49,3 @@ int main() { // CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev // CHECK: call void @_ZN13basic_istreamIcED1Ev // CHECK: call void @_ZdlPv - -// basic_istream's base dtor is a no-op. -// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev -// CHECK-NOT: call -// CHECK: } -