// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -std=c++98 -emit-llvm -o %t // RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -std=c++98 -O2 -disable-llvm-passes -emit-llvm -o %t.opt // RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -std=c++98 -O2 -disable-llvm-passes -emit-llvm -o %t.vtable -fforce-emit-vtables -fstrict-vtable-pointers -mconstructor-aliases // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST1 %s < %t // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST2 %s < %t // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST5 %s < %t // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST8 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST9 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST10 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST11 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST12 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST13 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST14 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST15 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST16 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-TEST17 %s < %t.opt // RUN: FileCheck -allow-deprecated-dag-overlap --check-prefix=CHECK-FORCE-EMIT %s < %t.vtable #include // CHECK-TEST1: @_ZTVN5Test11AE = external unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN5Test11AE = available_externally unnamed_addr constant namespace Test1 { struct A { A(); virtual void f(); virtual ~A() { } }; A::A() { } void f(A* a) { a->f(); }; // CHECK-LABEL: define void @_ZN5Test11gEv // CHECK: call void @_ZN5Test11A1fEv void g() { A a; f(&a); } } // Test2::A's key function (f) is defined in this translation unit, but when // we're doing codegen for the typeid(A) call, we don't know that yet. // This tests mainly that the typeinfo and typename constants have their linkage // updated correctly. // CHECK-TEST2: @_ZTSN5Test21AE = constant // CHECK-TEST2: @_ZTIN5Test21AE = constant // CHECK-TEST2: @_ZTVN5Test21AE = unnamed_addr constant namespace Test2 { struct A { virtual void f(); }; const std::type_info &g() { return typeid(A); }; 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-LABEL: define linkonce_odr void @_ZN5Test51A1fEv namespace Test5 { struct A { virtual void f() { } }; struct B : A { virtual ~B(); }; B::~B() { } } // Check that we don't assert on this test. namespace Test6 { struct A { virtual ~A(); int a; }; struct B { virtual ~B(); int b; }; struct C : A, B { C(); }; struct D : C { virtual void f(); D(); }; D::D() { } } namespace Test7 { struct c1 {}; struct c10 : c1{ virtual void foo (); }; struct c11 : c10, c1{ virtual void f6 (); }; struct c28 : virtual c11{ void f6 (); }; } namespace Test8 { // CHECK-TEST8: @_ZTVN5Test81YE = available_externally unnamed_addr constant // vtable for X is not generated because there are no stores here struct X { X(); virtual void foo(); }; struct Y : X { void foo(); }; void g(X* p) { p->foo(); } void f() { Y y; g(&y); X x; g(&x); } } // Test8 namespace Test9 { // All virtual functions are outline, so we can assume that it will // be generated in translation unit where foo is defined. // CHECK-TEST9-DAG: @_ZTVN5Test91AE = available_externally unnamed_addr constant // CHECK-TEST9-DAG: @_ZTVN5Test91BE = available_externally unnamed_addr constant struct A { virtual void foo(); virtual void bar(); }; void A::bar() {} struct B : A { void foo(); }; void g() { A a; a.foo(); B b; b.foo(); } } // Test9 namespace Test10 { // because A's key function is defined here, vtable is generated in this TU // CHECK-TEST10-DAG: @_ZTVN6Test101AE = unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101AE = unnamed_addr constant struct A { virtual void foo(); virtual void bar(); }; void A::foo() {} // Because key function is inline we will generate vtable as linkonce_odr. // CHECK-TEST10-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant struct D : A { void bar(); }; inline void D::bar() {} // Because B has outline all virtual functions, we can refer to them. // CHECK-TEST10-DAG: @_ZTVN6Test101BE = available_externally unnamed_addr constant struct B : A { void foo(); void bar(); }; // C's key function (car) is outline, but C has inline virtual function so we // can't guarantee that we will be able to refer to bar from name // so (at the moment) we can't emit vtable available_externally. // CHECK-TEST10-DAG: @_ZTVN6Test101CE = external unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101CE = available_externally unnamed_addr constant struct C : A { void bar() {} // defined in body - not key function virtual inline void gar(); // inline in body - not key function virtual void car(); }; // no key function, vtable will be generated everywhere it will be used // CHECK-TEST10-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant struct E : A {}; void g(A& a) { a.foo(); a.bar(); } void f() { A a; g(a); B b; g(b); C c; g(c); D d; g(d); E e; g(e); } } // Test10 namespace Test11 { struct D; // Can emit C's vtable available_externally. // CHECK-TEST11: @_ZTVN6Test111CE = available_externally unnamed_addr constant struct C { virtual D& operator=(const D&); }; // Can emit D's vtable available_externally. // CHECK-TEST11: @_ZTVN6Test111DE = available_externally unnamed_addr constant struct D : C { virtual void key(); }; D f(); void g(D& a) { C c; c = a; a.key(); a.key(); } void g() { D d; d = f(); g(d); } } // Test 11 namespace Test12 { // CHECK-TEST12: @_ZTVN6Test121AE = external unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test121AE = available_externally unnamed_addr constant struct A { virtual void foo(); virtual ~A() {} }; // CHECK-TEST12: @_ZTVN6Test121BE = external unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test121BE = available_externally 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 // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test131AE = available_externally unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test131BE = available_externally 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(); } } namespace Test16 { // S has virtual method that is hidden, because of it we can't // generate available_externally vtable for it. // CHECK-TEST16-DAG: @_ZTVN6Test161SE = external unnamed_addr constant // CHECK-TEST16-DAG: @_ZTVN6Test162S2E = available_externally // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test161SE = external unnamed_addr constant // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test162S2E = available_externally struct S { __attribute__((visibility("hidden"))) virtual void doStuff(); }; struct S2 { virtual void doStuff(); __attribute__((visibility("hidden"))) void unused(); }; void test() { S *s = new S; s->doStuff(); S2 *s2 = new S2; s2->doStuff(); } } namespace Test17 { // This test checks if we emit vtables opportunistically. // CHECK-TEST17-DAG: @_ZTVN6Test171AE = available_externally // CHECK-TEST17-DAG: @_ZTVN6Test171BE = external // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test171AE = available_externally // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test171BE = available_externally // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test171BD2Ev( // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test171BD0Ev( struct A { virtual void key(); virtual void bar() {} }; // We won't gonna use deleting destructor for this type, which will disallow // emitting vtable as available_externally struct B { virtual void key(); virtual ~B() {} }; void testcaseA() { A a; a.bar(); // this forces to emit definition of bar } void testcaseB() { B b; // This only forces emitting of complete object destructor } } // namespace Test17 namespace Test18 { // Here vtable will be only emitted because it is referenced by assume-load // after the Derived construction. // CHECK-FORCE-EMIT-DAG: @_ZTVN6Test187DerivedE = linkonce_odr unnamed_addr constant {{.*}} @_ZTIN6Test187DerivedE {{.*}} @_ZN6Test184Base3funEv {{.*}} @_ZN6Test184BaseD2Ev {{.*}} @_ZN6Test187DerivedD0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test187DerivedD0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test184BaseD2Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN6Test184Base3funEv // CHECK-FORCE-EMIT-DAG: @_ZTIN6Test187DerivedE = linkonce_odr constant struct Base { virtual int fun() { return 42; } virtual ~Base() { } }; struct Derived : Base { Derived(); }; int foo() { Derived *der = new Derived(); return der->fun(); } } namespace TestTemplates { // CHECK-FORCE-EMIT-DAG: @_ZTVN13TestTemplates8TemplateIiEE = linkonce_odr unnamed_addr constant {{.*}} @_ZTIN13TestTemplates8TemplateIiEE {{.*}} @_ZN13TestTemplates8TemplateIiE3fooEi {{.*}}@_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi {{.*}}@_ZN13TestTemplates8TemplateIiED1Ev {{.*}}@_ZN13TestTemplates8TemplateIiED0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi template struct Template { Template(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~Template(); }; struct NonTemplate { typedef int T; NonTemplate(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates11NonTemplate22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~NonTemplate(); }; // CHECK-FORCE-EMIT-DAG: @_ZTVN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiEE = linkonce_odr {{.*}} @_ZTIN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiEE {{.*}} @_ZN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiE3fooEi {{.*}} @_ZN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiE22thisShouldBeEmittedTooEi {{.*}} @_ZN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiED1Ev {{.*}} @_ZN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiED0Ev struct OuterNonTemplate { template struct NestedTemplateInNonTemplate { NestedTemplateInNonTemplate(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates16OuterNonTemplate27NestedTemplateInNonTemplateIiE22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~NestedTemplateInNonTemplate(); }; struct NestedNonTemplateInNonTemplate { typedef int T; NestedNonTemplateInNonTemplate(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates16OuterNonTemplate30NestedNonTemplateInNonTemplate22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~NestedNonTemplateInNonTemplate(); }; }; template struct OuterTemplate { template struct NestedTemplateInTemplate { NestedTemplateInTemplate(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates13OuterTemplateIlE24NestedTemplateInTemplateIiE22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~NestedTemplateInTemplate(); }; struct NestedNonTemplateInTemplate { typedef int T; NestedNonTemplateInTemplate(); virtual T foo(T val); // CHECK-FORCE-EMIT-DAG: define linkonce_odr i32 @_ZN13TestTemplates13OuterTemplateIlE27NestedNonTemplateInTemplate22thisShouldBeEmittedTooEi virtual T thisShouldBeEmittedToo(T val) { return val; } virtual ~NestedNonTemplateInTemplate(); }; }; template int use() { T *ptr = new T(); return ptr->foo(42); } void test() { use >(); use::NestedTemplateInTemplate >(); use >(); use(); use::NestedNonTemplateInTemplate>(); use(); } }