// 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 --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-TEST15 %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-TEST16 %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-TEST17 %s < %t.opt
+// RUN: FileCheck --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 {
// 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();
// 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();
};
// 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
// 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) {
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();
};
// 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();
};
// 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();
// 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();
}
} // 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>();
+}
+}