aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/vtable-available-externally.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCXX/vtable-available-externally.cpp')
-rw-r--r--test/CodeGenCXX/vtable-available-externally.cpp241
1 files changed, 240 insertions, 1 deletions
diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp
index e07d48463f4f..f38d177666e6 100644
--- a/test/CodeGenCXX/vtable-available-externally.cpp
+++ b/test/CodeGenCXX/vtable-available-externally.cpp
@@ -1,7 +1,17 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -O2 -disable-llvm-optzns -emit-llvm -o %t.opt
// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t
// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t
// RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-TEST8 %s < %t.opt
+// 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
+// RUN: FileCheck --check-prefix=CHECK-TEST16 %s < %t.opt
#include <typeinfo>
@@ -152,3 +162,232 @@ 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
+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
+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
+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
+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&);
+};
+
+// Cannot emit B's vtable available_externally, because we cannot create
+// a reference to the inline virtual B::operator= function.
+// CHECK-TEST11: @_ZTVN6Test111DE = external 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
+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();
+}
+}
+
+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
+
+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();
+}
+}
+