llvm-project/clang/test/CodeGenCXX/key-function-vtable.cpp

52 lines
1.6 KiB
C++
Raw Normal View History

// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s
// Simple key function test
struct testa { virtual void a(); };
void testa::a() {}
// Simple key function test
struct testb { virtual void a() {} };
testb *testbvar = new testb;
// Key function with out-of-line inline definition
struct testc { virtual void a(); };
inline void testc::a() {}
// Functions with inline specifier are not key functions (PR5705)
struct testd { inline virtual void a(); };
void testd::a() {}
// Functions with inline specifier are not key functions (PR5705)
struct teste { inline virtual void a(); };
teste *testevar = new teste;
// Key functions with namespace (PR5711)
namespace {
struct testf { virtual void a(); };
}
void testf::a() {}
// Key functions with namespace (PR5711)
namespace {
struct testg { virtual void a(); };
}
void testg::a() {}
testg *testgvar = new testg;
struct X0 { virtual ~X0(); };
struct X1 : X0 {
virtual void f();
};
inline void X1::f() { }
Don't let virtual calls and dynamic casts call Sema::MarkVTableUsed(). clang currently calls MarkVTableUsed() for classes that get their virtual methods called or that participate in a dynamic_cast. This is unnecessary, since CodeGen only emits vtables when it generates constructor, destructor, and vtt code. (*) Note that Sema::MarkVTableUsed() doesn't cause the emission of a vtable. Its main user-visible effect is that it instantiates virtual member functions of template classes, to make sure that if codegen decides to write a vtable all the entries in the vtable are defined. While this shouldn't change the behavior of codegen (other than being faster), it does make clang more permissive: virtual methods of templates (in particular destructors) end up being instantiated less often. In particular, classes that have members that are smart pointers to incomplete types will now get their implicit virtual destructor instantiated less frequently. For example, this used to not compile but does now compile: template <typename T> struct OwnPtr { ~OwnPtr() { static_assert((sizeof(T) > 0), "TypeMustBeComplete"); } }; class ScriptLoader; struct Base { virtual ~Base(); }; struct Sub : public Base { virtual void someFun() const {} OwnPtr<ScriptLoader> m_loader; }; void f(Sub *s) { s->someFun(); } The more permissive behavior matches both gcc (where this is not often observable, since in practice most things with virtual methods have a key function, and Sema::DefineUsedVTables() skips vtables for classes with key functions) and cl (which is my motivation for this change) – this fixes PR20337. See this issue and the review thread for some discussions about optimizations. This is similar to r213109 in spirit. r225761 was a prerequisite for this change. Various tests relied on "a->f()" marking a's vtable as used (in the sema sense), switch these to just construct a on the stack. This forces instantiation of the implicit constructor, which will mark the vtable as used. (*) The exception is -fapple-kext mode: In this mode, qualified calls to virtual functions (`a->Base::f()`) still go through the vtable, and since the vtable pointer off this doesn't point to Base's vtable, this needs to reference Base's vtable directly. To keep this working, keep referencing the vtable for virtual calls in apple kext mode. llvm-svn: 227073
2015-01-26 14:23:36 +08:00
void use_X1() { X1 x1; }
// CHECK-DAG: @_ZTV2X1 = linkonce_odr unnamed_addr constant
// CHECK-DAG: @_ZTV5testa = unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null
// CHECK-DAG: @_ZTV5testc = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null
// CHECK-DAG: @_ZTV5testb = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null
// CHECK-DAG: @_ZTV5teste = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null
// CHECK-DAG: @_ZTVN12_GLOBAL__N_15testgE = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null