From 1faa89f9c619e4b2411fab4af7e22ee7a2bd9009 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 5 Feb 2011 04:35:53 +0000 Subject: [PATCH] Re-land r124768, with a fix for PR9130. We now emit everything except unused implicit virtual member functions when building the vtable. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124935 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 6 +- lib/CodeGen/CGVTables.cpp | 4 +- lib/CodeGen/CodeGenModule.cpp | 22 ++++--- lib/CodeGen/CodeGenModule.h | 6 +- lib/Sema/SemaDeclCXX.cpp | 7 -- .../vtable-available-externally.cpp | 65 +++++++++++++++++++ 6 files changed, 89 insertions(+), 21 deletions(-) diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 9cb85954df..b217729e6e 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -227,7 +227,8 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), FPT->isVariadic()); - return cast(GetOrCreateLLVMFunction(Name, FTy, GD)); + return cast(GetOrCreateLLVMFunction(Name, FTy, GD, + /*ForVTable=*/false)); } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { @@ -284,7 +285,8 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false); - return cast(GetOrCreateLLVMFunction(Name, FTy, GD)); + return cast(GetOrCreateLLVMFunction(Name, FTy, GD, + /*ForVTable=*/false)); } static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index de6cbf52f3..eadfe9f146 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -2463,7 +2463,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Name); const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); - return GetOrCreateLLVMFunction(Name, Ty, GD); + return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/false); } static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, @@ -2918,7 +2918,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, } else { const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); - Init = CGM.GetAddrOfFunction(GD, Ty); + Init = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); } Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a086badfa8..82365aab42 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -654,7 +654,8 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { llvm::Constant *Aliasee; if (isa(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl()); + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), + /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); @@ -786,7 +787,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { llvm::Constant * CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, const llvm::Type *Ty, - GlobalDecl D) { + GlobalDecl D, bool ForVTable) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { @@ -844,12 +845,15 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, // - special member functions with implicit definitions // If we ever change our AST traversal to walk into class methods, // this will be unnecessary. + // + // We also don't emit a definition for a function if it's going to be an entry + // in a vtable, unless it's already marked as used. } else if (getLangOptions().CPlusPlus && D.getDecl()) { // Look for a declaration that's lexically in a record. const FunctionDecl *FD = cast(D.getDecl()); do { if (isa(FD->getLexicalDeclContext())) { - if (FD->isImplicit()) { + if (FD->isImplicit() && !ForVTable) { assert(FD->isUsed() && "Sema didn't mark implicit function as used!"); DeferredDeclsToEmit.push_back(D); break; @@ -876,13 +880,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, - const llvm::Type *Ty) { + const llvm::Type *Ty, + bool ForVTable) { // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast(GD.getDecl())->getType()); llvm::StringRef MangledName = getMangledName(GD); - return GetOrCreateLLVMFunction(MangledName, Ty, GD); + return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable); } /// CreateRuntimeFunction - Create a new runtime function with the specified @@ -890,7 +895,7 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, llvm::Constant * CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, llvm::StringRef Name) { - return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); + return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false); } static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { @@ -1458,7 +1463,8 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { // if a deferred decl. llvm::Constant *Aliasee; if (isa(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl()); + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), + /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); @@ -1524,7 +1530,7 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, const llvm::FunctionType *Ty = cast(getTypes().ConvertType(FD->getType())); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD)); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD), /*ForVTable=*/false); } llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 39117c2da7..1ed56d5b92 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -317,7 +317,8 @@ public: /// non-null, then this function will use the specified type if it has to /// create it. llvm::Constant *GetAddrOfFunction(GlobalDecl GD, - const llvm::Type *Ty = 0); + const llvm::Type *Ty = 0, + bool ForVTable = false); /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor /// for the given type. @@ -543,7 +544,8 @@ private: llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName, const llvm::Type *Ty, - GlobalDecl D); + GlobalDecl D, + bool ForVTable); llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName, const llvm::PointerType *PTy, const VarDecl *D, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5fbc0f6f26..49be40c5e4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7220,13 +7220,6 @@ bool Sema::DefineUsedVTables() { switch (KeyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - // The key function is in another translation unit. Mark all of the - // virtual members of this class as referenced so that we can build a - // vtable anyway (in order to do devirtualization when optimizations - // are turned on for example. - MarkVirtualMembersReferenced(Loc, Class); - continue; - case TSK_ExplicitInstantiationDeclaration: // The key function is in another translation unit. continue; diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp index b6e48c8f8c..594709d589 100644 --- a/test/CodeGenCXX/vtable-available-externally.cpp +++ b/test/CodeGenCXX/vtable-available-externally.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t // RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t #include @@ -53,3 +54,67 @@ namespace Test2 { void A::f() { } } + +// Test that we don't assert on this test. +namespace Test3 { + +struct A { + virtual void f(); + virtual ~A() { } +}; + +struct B : A { + B(); + virtual void f(); +}; + +B::B() { } + +void g(A* a) { + a->f(); +}; + +} + +// PR9114, test that we don't try to instantiate RefPtr. +namespace Test4 { + +template struct RefPtr { + T* p; + ~RefPtr() { + p->deref(); + } +}; + +struct A { + virtual ~A(); +}; + +struct Node; + +struct B : A { + virtual void deref(); + RefPtr m; +}; + +void f() { + RefPtr b; +} + +} + +// PR9130, test that we emit a definition of A::f. +// CHECK-TEST5: define linkonce_odr void @_ZN5Test51A1fEv +namespace Test5 { + +struct A { + virtual void f() { } +}; + +struct B : A { + virtual ~B(); +}; + +B::~B() { } + +} -- 2.40.0