| // 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 <typeinfo> |
| |
| // 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<Node>. |
| namespace Test4 { |
| |
| template <class T> struct RefPtr { |
| T* p; |
| ~RefPtr() { |
| p->deref(); |
| } |
| }; |
| |
| struct A { |
| virtual ~A(); |
| }; |
| |
| struct Node; |
| |
| struct B : A { |
| virtual void deref(); |
| RefPtr<Node> m; |
| }; |
| |
| void f() { |
| RefPtr<B> 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<class T> |
| 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<class T> |
| 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<class> |
| struct OuterTemplate { |
| template<class T> |
| 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<class T> |
| int use() { |
| T *ptr = new T(); |
| return ptr->foo(42); |
| } |
| |
| void test() { |
| use<Template<int> >(); |
| use<OuterTemplate<long>::NestedTemplateInTemplate<int> >(); |
| use<OuterNonTemplate::NestedTemplateInNonTemplate<int> >(); |
| |
| use<NonTemplate>(); |
| use<OuterTemplate<long>::NestedNonTemplateInTemplate>(); |
| use<OuterNonTemplate::NestedNonTemplateInNonTemplate>(); |
| } |
| } |