Index: include/clang/AST/VTableBuilder.h =================================================================== --- include/clang/AST/VTableBuilder.h +++ include/clang/AST/VTableBuilder.h @@ -154,6 +154,18 @@ bool isRTTIKind() const { return isRTTIKind(getKind()); } + GlobalDecl getGlobalDecl() const { + assert(isUsedFunctionPointerKind() && + "GlobalDecl can be created only from virtual function"); + if (getKind() == CK_FunctionPointer) + return GlobalDecl(getFunctionDecl()); + + auto *DtorDecl = cast(getFunctionDecl()); + if (getKind() == CK_CompleteDtorPointer) + return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete); + return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting); + } + private: static bool isFunctionPointerKind(Kind ComponentKind) { return isUsedFunctionPointerKind(ComponentKind) || Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -34,7 +34,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Value.h" - +#include using namespace clang; using namespace CodeGen; @@ -366,17 +366,39 @@ void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override; private: - bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const { + + SmallVector getVirtualFunctions(const CXXRecordDecl *RD) const { + SmallVector VFunctions; const auto &VtableLayout = CGM.getItaniumVTableContext().getVTableLayout(RD); for (const auto &VtableComponent : VtableLayout.vtable_components()) { - // Skip empty slot. + // Skip slots without virtual functions. if (!VtableComponent.isUsedFunctionPointerKind()) continue; + VFunctions.push_back(VtableComponent.getGlobalDecl()); + } + return VFunctions; + } + + bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const { + std::cerr << "entering\n"; + for (GlobalDecl VFunction : getVirtualFunctions(RD)) { + const auto * VFunctionDecl = cast(VFunction.getDecl()); + //VFunctionDecl->dumpColor(); + if (!VFunctionDecl->getCanonicalDecl()->isInlined()) + continue; + + StringRef Name = CGM.getMangledName(VFunction); + std::cerr << std::string(Name) << std::endl; + auto *Entry = CGM.GetGlobalValue(Name); + /*if (!Entry) + std::cerr << "no entry\n"; + else + std::cerr<< "entry with decl=" << Entry->isDeclaration() << std::endl;*/ - const CXXMethodDecl *Method = VtableComponent.getFunctionDecl(); - if (Method->getCanonicalDecl()->isInlined()) + // If function doesn't exist or doesn't have a definition. + if (!Entry || Entry->isDeclaration()) return true; } return false; @@ -1684,11 +1706,11 @@ if (CGM.getLangOpts().AppleKext) return false; - // If we don't have any inline virtual functions, and if vtable is not hidden, - // then we are safe to emit available_externally copy of vtable. + // If we don't have any not emitted inline virtual functions and if vtable is + // not hidden, then we are safe to emit available_externally copy of vtable. // FIXME we can still emit a copy of the vtable if we // can emit definition of the inline functions. - return !hasAnyVirtualInlineFunction(RD) && !isVTableHidden(RD); + return !hasAnyUnusedVirtualInlineFunction(RD) && !isVTableHidden(RD); } static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, Address InitialPtr, Index: test/CodeGenCXX/vtable-available-externally.cpp =================================================================== --- test/CodeGenCXX/vtable-available-externally.cpp +++ test/CodeGenCXX/vtable-available-externally.cpp @@ -391,3 +391,20 @@ } } +namespace Test17 { + +struct A { + virtual void foo(); + virtual ~A() {}; +}; + +struct B : A { + virtual void foo(); + virtual ~B() {}; +}; + +void B::foo() {} +void test() { + A a; // This will force emit of A's destructor. +} +}