Generating available_externally vtables bugfix
Bugfix revealed in r245264. http://reviews.llvm.org/D12128 llvm-svn: 245489
This commit is contained in:
parent
a431f152df
commit
1d02f681a9
|
@ -123,30 +123,50 @@ public:
|
|||
|
||||
const CXXRecordDecl *getRTTIDecl() const {
|
||||
assert(getKind() == CK_RTTI && "Invalid component kind!");
|
||||
|
||||
return reinterpret_cast<CXXRecordDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXMethodDecl *getFunctionDecl() const {
|
||||
assert(getKind() == CK_FunctionPointer);
|
||||
|
||||
assert(isFunctionPointerKind() && "Invalid component kind!");
|
||||
if (isDestructorKind())
|
||||
return getDestructorDecl();
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXDestructorDecl *getDestructorDecl() const {
|
||||
assert((getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
|
||||
|
||||
assert(isDestructorKind() && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXDestructorDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXMethodDecl *getUnusedFunctionDecl() const {
|
||||
assert(getKind() == CK_UnusedFunctionPointer);
|
||||
|
||||
assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
bool isDestructorKind() const { return isDestructorKind(getKind()); }
|
||||
|
||||
bool isUsedFunctionPointerKind() const {
|
||||
return isUsedFunctionPointerKind(getKind());
|
||||
}
|
||||
|
||||
bool isFunctionPointerKind() const {
|
||||
return isFunctionPointerKind(getKind());
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isFunctionPointerKind(Kind ComponentKind) {
|
||||
return isUsedFunctionPointerKind(ComponentKind) ||
|
||||
ComponentKind == CK_UnusedFunctionPointer;
|
||||
}
|
||||
static bool isUsedFunctionPointerKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_FunctionPointer ||
|
||||
isDestructorKind(ComponentKind);
|
||||
}
|
||||
static bool isDestructorKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer;
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, CharUnits Offset) {
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
ComponentKind == CK_VBaseOffset ||
|
||||
|
@ -158,12 +178,8 @@ private:
|
|||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
|
||||
assert((ComponentKind == CK_RTTI ||
|
||||
ComponentKind == CK_FunctionPointer ||
|
||||
ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer ||
|
||||
ComponentKind == CK_UnusedFunctionPointer) &&
|
||||
"Invalid component kind!");
|
||||
assert((ComponentKind == CK_RTTI || isFunctionPointerKind(ComponentKind)) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
|
||||
|
||||
|
@ -178,11 +194,7 @@ private:
|
|||
}
|
||||
|
||||
uintptr_t getPointer() const {
|
||||
assert((getKind() == CK_RTTI ||
|
||||
getKind() == CK_FunctionPointer ||
|
||||
getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer ||
|
||||
getKind() == CK_UnusedFunctionPointer) &&
|
||||
assert((getKind() == CK_RTTI || isFunctionPointerKind()) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
return static_cast<uintptr_t>(Value & ~7ULL);
|
||||
|
|
|
@ -306,17 +306,15 @@ public:
|
|||
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
|
||||
|
||||
private:
|
||||
/// Checks if function has any virtual inline function.
|
||||
bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const {
|
||||
bool hasAnyUsedVirtualInlineFunction(const CXXRecordDecl *RD) const {
|
||||
const auto &VtableLayout =
|
||||
CGM.getItaniumVTableContext().getVTableLayout(RD);
|
||||
|
||||
for (const auto &VtableComponent : VtableLayout.vtable_components()) {
|
||||
if (VtableComponent.getKind() !=
|
||||
VTableComponent::Kind::CK_FunctionPointer)
|
||||
if (!VtableComponent.isUsedFunctionPointerKind())
|
||||
continue;
|
||||
|
||||
const auto &Method = VtableComponent.getFunctionDecl();
|
||||
const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
|
||||
if (Method->getCanonicalDecl()->isInlined())
|
||||
return true;
|
||||
}
|
||||
|
@ -1510,7 +1508,7 @@ bool ItaniumCXXABI::canEmitAvailableExternallyVTable(
|
|||
// 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);
|
||||
return !hasAnyUsedVirtualInlineFunction(RD);
|
||||
}
|
||||
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *Ptr,
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
// RUN: FileCheck --check-prefix=CHECK-TEST9 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST10 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST11 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST12 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST13 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST14 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST15 %s < %t.opt
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
|
@ -289,3 +293,76 @@ void g() {
|
|||
g(d);
|
||||
}
|
||||
} // Test 11
|
||||
|
||||
namespace Test12 {
|
||||
|
||||
// CHECK-TEST12: @_ZTVN6Test121AE = external unnamed_addr constant
|
||||
struct A {
|
||||
virtual void foo();
|
||||
virtual ~A() {}
|
||||
};
|
||||
// CHECK-TEST12: @_ZTVN6Test121BE = external unnamed_addr constant
|
||||
struct B : A {
|
||||
void foo();
|
||||
};
|
||||
|
||||
void g() {
|
||||
A a;
|
||||
a.foo();
|
||||
B b;
|
||||
b.foo();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test13 {
|
||||
|
||||
// CHECK-TEST13-DAG: @_ZTVN6Test131AE = available_externally unnamed_addr constant
|
||||
// CHECK-TEST13-DAG: @_ZTVN6Test131BE = external unnamed_addr constant
|
||||
struct A {
|
||||
virtual ~A();
|
||||
};
|
||||
struct B : A {
|
||||
virtual void f();
|
||||
void operator delete(void *);
|
||||
~B() {}
|
||||
};
|
||||
|
||||
void g() {
|
||||
A *b = new B;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test14 {
|
||||
|
||||
// CHECK-TEST14: @_ZTVN6Test141AE = available_externally unnamed_addr constant
|
||||
struct A {
|
||||
virtual void f();
|
||||
void operator delete(void *);
|
||||
~A();
|
||||
};
|
||||
|
||||
void g() {
|
||||
A *b = new A;
|
||||
delete b;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test15 {
|
||||
// In this test D's vtable has two slots for function f(), but uses only one,
|
||||
// so the second slot is set to null.
|
||||
// CHECK-TEST15: @_ZTVN6Test151DE = available_externally unnamed_addr constant
|
||||
struct A { virtual void f() {} };
|
||||
struct B : virtual A {};
|
||||
struct C : virtual A {};
|
||||
struct D : B, C {
|
||||
virtual void g();
|
||||
void f();
|
||||
};
|
||||
|
||||
void test() {
|
||||
D * d = new D;
|
||||
d->f();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue