summaryrefslogtreecommitdiff
path: root/test/CodeGenCXX
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCXX')
-rw-r--r--test/CodeGenCXX/constructor-init.cpp21
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp54
-rw-r--r--test/CodeGenCXX/member-expressions.cpp40
-rw-r--r--test/CodeGenCXX/multi-dim-operator-new.cpp49
-rw-r--r--test/CodeGenCXX/references.cpp8
-rw-r--r--test/CodeGenCXX/rtti-fundamental.cpp71
-rw-r--r--test/CodeGenCXX/rtti-linkage.cpp1
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp76
-rw-r--r--test/CodeGenCXX/temporaries.cpp13
-rw-r--r--test/CodeGenCXX/thunks.cpp137
-rw-r--r--test/CodeGenCXX/virt.cpp52
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp23
-rw-r--r--test/CodeGenCXX/vtable-layout-abi-examples.cpp1
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp49
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp20
15 files changed, 527 insertions, 88 deletions
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index a0a35fa16f1bd..284b8b5938f94 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -80,3 +80,24 @@ void f() {
// CHECK-NOT: call void @_ZN1AIsED1Ev
// CHECK: ret void
}
+
+template<typename T>
+struct X {
+ X(const X &);
+
+ T *start;
+ T *end;
+};
+
+template<typename T> struct X;
+
+// Make sure that the instantiated constructor initializes start and
+// end properly.
+// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_
+// CHECK: {{store.*null}}
+// CHECK: {{store.*null}}
+// CHECK: ret
+template<typename T>
+X<T>::X(const X &other) : start(0), end(0) { }
+
+X<int> get_X(X<int> x) { return x; }
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
index ae8eefa7fe40d..9cafd0accdb67 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -1,7 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
extern "C" int printf(...);
@@ -24,6 +21,7 @@ struct P {
};
+// CHECK: define linkonce_odr void @_ZN1XC1ERKS_
struct X : M, N, P { // ...
X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd),
au_i1(1234), au1_4("MASKED") {}
@@ -113,10 +111,46 @@ void f(const B &b1) {
B b2(b1);
}
-// CHECK-LP64: .globl __ZN1XC1ERKS_
-// CHECK-LP64: .weak_definition __ZN1XC1ERKS_
-// CHECK-LP64: __ZN1XC1ERKS_:
+// PR6628
+namespace PR6628 {
+
+struct T {
+ T();
+ ~T();
+
+ double d;
+};
+
+struct A {
+ A(const A &other, const T &t = T(), const T& t2 = T());
+};
+
+struct B : A {
+ A a1;
+ A a2;
+ A a[10];
+};
+
+// Force the copy constructor to be synthesized.
+void f(B b1) {
+ B b2 = b1;
+}
+
+// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+}
-// CHECK-LP32: .globl __ZN1XC1ERKS_
-// CHECK-LP32: .weak_definition __ZN1XC1ERKS_
-// CHECK-LP32: __ZN1XC1ERKS_:
diff --git a/test/CodeGenCXX/member-expressions.cpp b/test/CodeGenCXX/member-expressions.cpp
index 720a9a70d07bb..d9fb3940b05b0 100644
--- a/test/CodeGenCXX/member-expressions.cpp
+++ b/test/CodeGenCXX/member-expressions.cpp
@@ -44,3 +44,43 @@ int f() {
return A().foo();
}
}
+
+namespace test4 {
+ struct A {
+ int x;
+ };
+ struct B {
+ int x;
+ void foo();
+ };
+ struct C : A, B {
+ };
+
+ extern C *c_ptr;
+
+ // CHECK: define i32 @_ZN5test44testEv()
+ int test() {
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @_ZN5test41B3fooEv
+ c_ptr->B::foo();
+
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i32 5
+ c_ptr->B::x = 5;
+
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: load i32*
+ return c_ptr->B::x;
+ }
+}
diff --git a/test/CodeGenCXX/multi-dim-operator-new.cpp b/test/CodeGenCXX/multi-dim-operator-new.cpp
new file mode 100644
index 0000000000000..7a235e83a78da
--- /dev/null
+++ b/test/CodeGenCXX/multi-dim-operator-new.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -emit-llvm -o - | FileCheck %s
+// PR6641
+
+extern "C" int printf(const char *, ...);
+
+struct Foo {
+ Foo() : iFoo (2) {
+ printf("%p\n", this);
+ }
+ int iFoo;
+};
+
+
+typedef Foo (*T)[3][4];
+
+T bar() {
+ return new Foo[2][3][4];
+}
+
+T bug(int i) {
+ return new Foo[i][3][4];
+}
+
+void pr(T a) {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 4; j++)
+ printf("%p\n", a[i][j]);
+}
+
+Foo *test() {
+ return new Foo[5];
+}
+
+int main() {
+ T f = bar();
+ pr(f);
+ f = bug(3);
+ pr(f);
+
+ Foo * g = test();
+ for (int i = 0; i < 5; i++)
+ printf("%d\n", g[i].iFoo);
+ return 0;
+}
+
+// CHECK: call noalias i8* @_Znam
+// CHECK: call noalias i8* @_Znam
+// CHECK: call noalias i8* @_Znam
+
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 39b5909fb9a4f..5a5947dd81624 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -147,3 +147,11 @@ void f(int &a) {
struct s0;
struct s1 { struct s0 &s0; };
void f0(s1 a) { s1 b = a; }
+
+// PR6024
+// CHECK: @_Z2f2v()
+// CHECK: alloca
+// CHECK: store
+// CHECK: load
+// CHECK: ret
+const int &f2() { return 0; }
diff --git a/test/CodeGenCXX/rtti-fundamental.cpp b/test/CodeGenCXX/rtti-fundamental.cpp
new file mode 100644
index 0000000000000..473f48db67add
--- /dev/null
+++ b/test/CodeGenCXX/rtti-fundamental.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+#include <typeinfo>
+
+std::type_info foo() {
+ return typeid(void);
+}
+
+namespace __cxxabiv1 {
+ struct __fundamental_type_info {
+ virtual ~__fundamental_type_info() {}
+ };
+}
+
+// CHECK: @_ZTIv = weak_odr constant
+// CHECK: @_ZTIPv = weak_odr constant
+// CHECK: @_ZTIPKv = weak_odr constant
+// CHECK: @_ZTIDi = weak_odr constant
+// CHECK: @_ZTIPDi = weak_odr constant
+// CHECK: @_ZTIPKDi = weak_odr constant
+// CHECK: @_ZTIDs = weak_odr constant
+// CHECK: @_ZTIPDs = weak_odr constant
+// CHECK: @_ZTIPKDs = weak_odr constant
+// CHECK: @_ZTIy = weak_odr constant
+// CHECK: @_ZTIPy = weak_odr constant
+// CHECK: @_ZTIPKy = weak_odr constant
+// CHECK: @_ZTIx = weak_odr constant
+// CHECK: @_ZTIPx = weak_odr constant
+// CHECK: @_ZTIPKx = weak_odr constant
+// CHECK: @_ZTIw = weak_odr constant
+// CHECK: @_ZTIPw = weak_odr constant
+// CHECK: @_ZTIPKw = weak_odr constant
+// CHECK: @_ZTIt = weak_odr constant
+// CHECK: @_ZTIPt = weak_odr constant
+// CHECK: @_ZTIPKt = weak_odr constant
+// CHECK: @_ZTIs = weak_odr constant
+// CHECK: @_ZTIPs = weak_odr constant
+// CHECK: @_ZTIPKs = weak_odr constant
+// CHECK: @_ZTIm = weak_odr constant
+// CHECK: @_ZTIPm = weak_odr constant
+// CHECK: @_ZTIPKm = weak_odr constant
+// CHECK: @_ZTIl = weak_odr constant
+// CHECK: @_ZTIPl = weak_odr constant
+// CHECK: @_ZTIPKl = weak_odr constant
+// CHECK: @_ZTIj = weak_odr constant
+// CHECK: @_ZTIPj = weak_odr constant
+// CHECK: @_ZTIPKj = weak_odr constant
+// CHECK: @_ZTIi = weak_odr constant
+// CHECK: @_ZTIPi = weak_odr constant
+// CHECK: @_ZTIPKi = weak_odr constant
+// CHECK: @_ZTIh = weak_odr constant
+// CHECK: @_ZTIPh = weak_odr constant
+// CHECK: @_ZTIPKh = weak_odr constant
+// CHECK: @_ZTIf = weak_odr constant
+// CHECK: @_ZTIPf = weak_odr constant
+// CHECK: @_ZTIPKf = weak_odr constant
+// CHECK: @_ZTIe = weak_odr constant
+// CHECK: @_ZTIPe = weak_odr constant
+// CHECK: @_ZTIPKe = weak_odr constant
+// CHECK: @_ZTId = weak_odr constant
+// CHECK: @_ZTIPd = weak_odr constant
+// CHECK: @_ZTIPKd = weak_odr constant
+// CHECK: @_ZTIc = weak_odr constant
+// CHECK: @_ZTIPc = weak_odr constant
+// CHECK: @_ZTIPKc = weak_odr constant
+// CHECK: @_ZTIb = weak_odr constant
+// CHECK: @_ZTIPb = weak_odr constant
+// CHECK: @_ZTIPKb = weak_odr constant
+// CHECK: @_ZTIa = weak_odr constant
+// CHECK: @_ZTIPa = weak_odr constant
+// CHECK: @_ZTIPKa = weak_odr constant
diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp
index 799c1d41c7261..b9eb5b4ad4113 100644
--- a/test/CodeGenCXX/rtti-linkage.cpp
+++ b/test/CodeGenCXX/rtti-linkage.cpp
@@ -92,6 +92,7 @@ const std::type_info &t2() {
(void)typeid(D *);
(void)typeid(D (*)());
(void)typeid(void (*)(D));
+ (void)typeid(void (*)(D&));
// The exception specification is not part of the RTTI descriptor, so it should not have
// internal linkage.
(void)typeid(void (*)() throw (D));
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
new file mode 100644
index 0000000000000..416c0a1a20729
--- /dev/null
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
+// CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE
+// CHECK: @_ZTVN5test018stdio_sync_filebufIwEE = constant
+
+// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(
+// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
+// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd(
+
+namespace test0 {
+ struct basic_streambuf {
+ virtual ~basic_streambuf();
+ };
+ template<typename _CharT >
+ struct stdio_sync_filebuf : public basic_streambuf {
+ virtual void xsgetn();
+ };
+
+ // This specialization should cause the vtable to be emitted, even with
+ // the following extern template declaration.
+ template<> void stdio_sync_filebuf<wchar_t>::xsgetn() {
+ }
+ extern template class stdio_sync_filebuf<wchar_t>;
+}
+
+namespace test1 {
+ struct basic_streambuf {
+ virtual ~basic_streambuf();
+ };
+ template<typename _CharT >
+ struct stdio_sync_filebuf : public basic_streambuf {
+ virtual void xsgetn();
+ };
+
+ // Just a declaration should not force the vtable to be emitted.
+ template<> void stdio_sync_filebuf<wchar_t>::xsgetn();
+}
+
+namespace test2 {
+ template<typename T1>
+ class C {
+ virtual ~C();
+ void zedbar(double) {
+ }
+ template<typename T2>
+ void foobar(T2 foo) {
+ }
+ };
+ extern template class C<int>;
+ void g() {
+ // The extern template declaration should not prevent us from producing
+ // the implicit constructor (test at the top).
+ C<int> a;
+
+ // or foobar(test at the top).
+ a.foobar(0.0);
+
+ // But it should prevent zebbar
+ // (test at the top).
+ a.zedbar(0.0);
+ }
+}
+
+namespace test3 {
+ template<typename T>
+ class basic_fstreamXX {
+ virtual void foo(){}
+ virtual void is_open() const { }
+ };
+
+ extern template class basic_fstreamXX<char>;
+ // This template instantiation should not cause us to produce a vtable.
+ // (test at the top).
+ template void basic_fstreamXX<char>::is_open() const;
+}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index cd0cf77f53b2d..4aad3c0056ca0 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -288,3 +288,16 @@ void g() {
}
}
+
+namespace PR6648 {
+ struct B {
+ ~B();
+ };
+ B foo;
+ struct D;
+ D& zed(B);
+ void foobar() {
+ // CHECK: call %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE
+ zed(foo);
+ }
+}
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
new file mode 100644
index 0000000000000..b91ba3239b1e1
--- /dev/null
+++ b/test/CodeGenCXX/thunks.cpp
@@ -0,0 +1,137 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+namespace Test1 {
+
+// Check that we emit a non-virtual thunk for C::f.
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define void @_ZThn8_N5Test11C1fEv(
+void C::f() { }
+
+}
+
+namespace Test2 {
+
+// Check that we emit a thunk for B::f since it's overriding a virtual base.
+
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A {
+ virtual void b();
+ virtual void f();
+};
+
+// CHECK: define void @_ZTv0_n24_N5Test21B1fEv(
+void B::f() { }
+
+}
+
+namespace Test3 {
+
+// Check that we emit a covariant thunk for B::f.
+
+struct V1 { };
+struct V2 : virtual V1 { };
+
+struct A {
+ virtual V1 *f();
+};
+
+struct B : A {
+ virtual void b();
+
+ virtual V2 *f();
+};
+
+// CHECK: define %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv(
+V2 *B::f() { return 0; }
+
+}
+
+namespace Test4 {
+
+// Check that the thunk for 'C::f' has the same visibility as the function itself.
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct __attribute__((visibility("protected"))) C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define protected void @_ZThn8_N5Test41C1fEv(
+void C::f() { }
+
+}
+
+// This is from Test5:
+// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
+
+// Check that the thunk gets internal linkage.
+namespace {
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv(
+void C::f() { }
+
+}
+
+// Force C::f to be used.
+void f() {
+ C c;
+
+ c.f();
+}
+
+namespace Test5 {
+
+// Check that the thunk for 'B::f' gets the same linkage as the function itself.
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A {
+ virtual void f() { }
+};
+
+void f(B b) {
+ b.f();
+}
+}
+
+
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index 9d671c4e5f0ef..c40412963097d 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -693,55 +693,3 @@ void test12_foo() {
// CHECK-LPLL64: call void %
// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}})
-
-// FIXME: This is the wrong thunk, but until these issues are fixed, better
-// than nothing.
-// CHECK-LPLL64define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
-// CHECK-LPLL64 %{{retval|2}} = alloca %class.test8_D*
-// CHECK-LPLL64 %.addr = alloca %class.test8_D*
-// CHECK-LPLL64 store %class.test8_D* %0, %class.test8_D** %.addr
-// CHECK-LPLL64 %{{this|3}} = load %class.test8_D** %.addr
-// CHECK-LPLL64 %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8*
-// CHECK-LPLL64 %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16
-// CHECK-LPLL64 %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D*
-// CHECK-LPLL64 %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8*
-// CHECK-LPLL64 %{{5|8}} = bitcast %class.test8_D* %3 to i64**
-// CHECK-LPLL64 %{{vtable|9}} = load i64** %{{5|8}}
-// CHECK-LPLL64 %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9
-// CHECK-LPLL64 %{{7|11}} = load i64* %{{6|10}}
-// CHECK-LPLL64 %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}}
-// CHECK-LPLL64 %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D*
-// CHECK-LPLL64 %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}})
-// CHECK-LPLL64 store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64 %{{10|15}} = load %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64 ret %class.test8_D* %{{10|15}}
-// CHECK-LPLL64}
-
-// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%{{class.test8_D|.*}}*)
-// CHECK-LPLL64: %{{retval|1}} = alloca %class.test8_D*
-// CHECK-LPLL64: %{{.addr|2}} = alloca %class.test8_D*
-// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %{{.addr|2}}
-// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %{{.addr|2}}
-// CHECK-LPLL64: %{{call|4}} = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %{{this|3}})
-// CHECK-LPLL64: %{{1|5}} = icmp ne %class.test8_D* %{{call|4}}, null
-// CHECK-LPLL64: br i1 %{{1|5}}, label %{{2|6}}, label %{{12|17}}
-// CHECK-LPLL64:; <label>:{{2|6}}
-// CHECK-LPLL64: %{{3|7}} = bitcast %class.test8_D* %{{call|4}} to i8*
-// CHECK-LPLL64: %{{4|8}} = getelementptr inbounds i8* %{{3|7}}, i64 16
-// CHECK-LPLL64: %{{5|9}} = bitcast i8* %4 to %class.test8_D*
-// CHECK-LPLL64: %{{6|10}} = bitcast %class.test8_D* %{{5|9}} to i8*
-// CHECK-LPLL64: %{{7|11}} = bitcast %class.test8_D* %{{5|9}} to i64**
-// CHECK-LPLL64: %{{vtable|12}} = load i64** %{{7|11}}
-// CHECK-LPLL64: %{{8|13}} = getelementptr inbounds i64* %vtable, i64 -4
-// CHECK-LPLL64: %{{9|14}} = load i64* %{{8|13}}
-// CHECK-LPLL64: %{{10|15}} = getelementptr i8* %{{6|10}}, i64 %{{9|14}}
-// CHECK-LPLL64: %{{11|16}} = bitcast i8* %{{10|15}} to %class.test8_D*
-// CHECK-LPLL64: br label %{{13|18}}
-// CHECK-LPLL64:; <label>:{{12|17}}
-// CHECK-LPLL64: br label %{{13|18}}
-// CHECK-LPLL64:; <label>:{{13|18}}
-// CHECK-LPLL64: %{{14|19}} = phi %class.test8_D* [ %{{11|16}}, %{{2|6}} ], [ %{{call|4}}, %{{12|17}} ]
-// CHECK-LPLL64: store %class.test8_D* %{{14|19}}, %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64: %{{15|20}} = load %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64: ret %class.test8_D* %{{15|20}}
-// CHECK-LPLL64:}
diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
index 627717576302e..61de3153fd509 100644
--- a/test/CodeGenCXX/virtual-bases.cpp
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -23,3 +23,26 @@ struct C : virtual A {
// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext)
// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext)
C::C(bool) { }
+
+// PR6251
+namespace PR6251 {
+
+// Test that we don't call the A<char> constructor twice.
+
+template<typename T>
+struct A { A(); };
+
+struct B : virtual A<char> { };
+struct C : virtual A<char> { };
+
+struct D : B, C {
+ D();
+};
+
+// CHECK: define void @_ZN6PR62511DC1Ev
+// CHECK: call void @_ZN6PR62511AIcEC2Ev
+// CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev
+// CHECK: ret void
+D::D() { }
+
+}
diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
index a82fca736c79d..c01c5ef72cc52 100644
--- a/test/CodeGenCXX/vtable-layout-abi-examples.cpp
+++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
@@ -178,7 +178,6 @@ struct C : virtual public A { int j; };
// CHECK-NEXT: 7 | vcall_offset (-16)
// CHECK-NEXT: 8 | offset_to_top (-16)
// CHECK-NEXT: 9 | Test2::D RTTI
-// CHECK-NEXT: -- (Test2::A, 16) vtable address --
// CHECK-NEXT: -- (Test2::C, 16) vtable address --
// CHECK-NEXT: 10 | [unused] void Test2::A::f()
struct D : public B, public C {
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index bc3d54b8e4a7b..3a0dae41c3b06 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -635,7 +635,6 @@ struct D : virtual B, virtual C { virtual void f(); };
// CHECK-NEXT: 9 | vcall_offset (-8)
// CHECK-NEXT: 10 | offset_to_top (-8)
// CHECK-NEXT: 11 | Test17::E RTTI
-// CHECK-NEXT: -- (Test17::A, 8) vtable address --
// CHECK-NEXT: -- (Test17::C, 8) vtable address --
// CHECK-NEXT: 12 | void Test17::E::f()
// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
@@ -693,7 +692,6 @@ struct C : A, B {
// CHECK-NEXT: 19 | vcall_offset (-16)
// CHECK-NEXT: 20 | offset_to_top (-16)
// CHECK-NEXT: 21 | Test18::D RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 22 | void Test18::D::f()
// CHECK-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
@@ -725,7 +723,6 @@ struct C : A, B {
// CHECK-NEXT: 9 | vcall_offset (0)
// CHECK-NEXT: 10 | offset_to_top (-8)
// CHECK-NEXT: 11 | Test18::C RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 12 | void Test18::B::f()
// CHECK-NEXT: 13 | [unused] void Test18::C::g()
@@ -745,7 +742,6 @@ struct C : A, B {
// CHECK-NEXT: 2 | vcall_offset (0)
// CHECK-NEXT: 3 | offset_to_top (0)
// CHECK-NEXT: 4 | Test18::B RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 5 | void Test18::B::f()
// CHECK-NEXT: 6 | [unused] void Test18::A::g()
@@ -881,9 +877,6 @@ class E : virtual C { };
// CHECK-NEXT: 12 | vcall_offset (-8)
// CHECK-NEXT: 13 | offset_to_top (-8)
// CHECK-NEXT: 14 | Test21::F RTTI
-// CHECK-NEXT: -- (Test21::A, 8) vtable address --
-// CHECK-NEXT: -- (Test21::B, 8) vtable address --
-// CHECK-NEXT: -- (Test21::C, 8) vtable address --
// CHECK-NEXT: -- (Test21::E, 8) vtable address --
// CHECK-NEXT: 15 | [unused] void Test21::F::f()
//
@@ -1012,7 +1005,6 @@ struct C : virtual A { };
// CHECK-NEXT: 6 | vcall_offset (-8)
// CHECK-NEXT: 7 | offset_to_top (-8)
// CHECK-NEXT: 8 | Test24::D RTTI
-// CHECK-NEXT: -- (Test24::A, 8) vtable address --
// CHECK-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-NEXT: 9 | [unused] void Test24::D::f()
@@ -1030,14 +1022,13 @@ struct C : virtual A { };
// CHECK-NEXT: 1 | vcall_offset (-8)
// CHECK-NEXT: 2 | offset_to_top (0)
// CHECK-NEXT: 3 | Test24::C RTTI
-// CHECK-NEXT: -- (Test24::A, 8) vtable address --
// CHECK-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-NEXT: 4 | [unused] void Test24::A::f()
// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (8)
-// CHECK-NEXT: 7 | Test24::C RTTI
-// CHECK-NEXT: -- (Test24::A, 0) vtable address --
-// CHECK-NEXT: 8 | void Test24::A::f()
+// CHECK-NEXT: 6 | offset_to_top (8)
+// CHECK-NEXT: 7 | Test24::C RTTI
+// CHECK-NEXT: -- (Test24::A, 0) vtable address --
+// CHECK-NEXT: 8 | void Test24::A::f()
struct D : B, C {
virtual void f();
};
@@ -1071,7 +1062,6 @@ struct B : virtual V { };
// CHECK-NEXT: 8 | offset_to_top (-8)
// CHECK-NEXT: 9 | Test25::C RTTI
// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: -- (Test25::V, 8) vtable address --
// CHECK-NEXT: 10 | [unused] void Test25::V::f()
// CHECK: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
@@ -1089,7 +1079,6 @@ struct B : virtual V { };
// CHECK-NEXT: 2 | offset_to_top (0)
// CHECK-NEXT: 3 | Test25::B RTTI
// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: -- (Test25::V, 8) vtable address --
// CHECK-NEXT: 4 | [unused] void Test25::V::f()
// CHECK-NEXT: 5 | vcall_offset (0)
// CHECK-NEXT: 6 | offset_to_top (8)
@@ -1284,3 +1273,33 @@ struct E : D {
void E::e() { }
}
+
+namespace Test29 {
+
+// Test that the covariant return thunk for B::f will have a virtual 'this' adjustment,
+// matching gcc.
+
+struct V1 { };
+struct V2 : virtual V1 { };
+
+struct A {
+ virtual V1 *f();
+};
+
+// CHECK: Vtable for 'Test29::B' (6 entries).
+// CHECK-NEXT: 0 | vbase_offset (0)
+// CHECK-NEXT: 1 | vcall_offset (0)
+// CHECK-NEXT: 2 | offset_to_top (0)
+// CHECK-NEXT: 3 | Test29::B RTTI
+// CHECK-NEXT: -- (Test29::A, 0) vtable address --
+// CHECK-NEXT: -- (Test29::B, 0) vtable address --
+// CHECK-NEXT: 4 | Test29::V2 *Test29::B::f()
+// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT: 5 | Test29::V2 *Test29::B::f()
+struct B : virtual A {
+ virtual V2 *f();
+};
+V2 *B::f() { return 0; }
+
+}
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index 63e17431c467a..a4ea2a19c2380 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -84,54 +84,54 @@ void use_F(F<char> &fc) {
// CHECK: @_ZTV1B = external constant
// C has no key function, so its vtable should have weak_odr linkage.
+// CHECK: @_ZTV1C = weak_odr constant
// CHECK: @_ZTS1C = weak_odr constant
// CHECK: @_ZTI1C = weak_odr constant
-// CHECK: @_ZTV1C = weak_odr constant
// D has a key function that is defined in this translation unit so its vtable is
// defined in the translation unit.
+// CHECK: @_ZTV1D = constant
// CHECK: @_ZTS1D = constant
// CHECK: @_ZTI1D = constant
-// CHECK: @_ZTV1D = constant
// E<char> is an explicit specialization with a key function defined
// in this translation unit, so its vtable should have external
// linkage.
+// CHECK: @_ZTV1EIcE = constant
// CHECK: @_ZTS1EIcE = constant
// CHECK: @_ZTI1EIcE = constant
-// CHECK: @_ZTV1EIcE = constant
// E<short> is an explicit template instantiation with a key function
// defined in this translation unit, so its vtable should have
// weak_odr linkage.
+// CHECK: @_ZTV1EIsE = weak_odr constant
// CHECK: @_ZTS1EIsE = weak_odr constant
// CHECK: @_ZTI1EIsE = weak_odr constant
-// CHECK: @_ZTV1EIsE = weak_odr constant
// F<short> is an explicit template instantiation without a key
// function, so its vtable should have weak_odr linkage
+// CHECK: @_ZTV1FIsE = weak_odr constant
// CHECK: @_ZTS1FIsE = weak_odr constant
// CHECK: @_ZTI1FIsE = weak_odr constant
-// CHECK: @_ZTV1FIsE = weak_odr constant
// E<long> is an implicit template instantiation with a key function
// defined in this translation unit, so its vtable should have
// weak_odr linkage.
+// CHECK: @_ZTV1EIlE = weak_odr constant
// CHECK: @_ZTS1EIlE = weak_odr constant
// CHECK: @_ZTI1EIlE = weak_odr constant
-// CHECK: @_ZTV1EIlE = weak_odr constant
// F<long> is an implicit template instantiation with no key function,
// so its vtable should have weak_odr linkage.
+// CHECK: @_ZTV1FIlE = weak_odr constant
// CHECK: @_ZTS1FIlE = weak_odr constant
// CHECK: @_ZTI1FIlE = weak_odr constant
-// CHECK: @_ZTV1FIlE = weak_odr constant
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have weak_odr linkage.
+// CHECK: @_ZTV1FIiE = weak_odr constant
// CHECK: @_ZTS1FIiE = weak_odr constant
// CHECK: @_ZTI1FIiE = weak_odr constant
-// CHECK: @_ZTV1FIiE = weak_odr constant
// E<int> is an explicit template instantiation declaration. It has a
// key function that is not instantiated, so we should only reference
@@ -140,14 +140,14 @@ void use_F(F<char> &fc) {
// The anonymous struct for e has no linkage, so the vtable should have
// internal linkage.
+// CHECK: @"_ZTV3$_0" = internal constant
// CHECK: @"_ZTS3$_0" = internal constant
// CHECK: @"_ZTI3$_0" = internal constant
-// CHECK: @"_ZTV3$_0" = internal constant
// The A vtable should have internal linkage since it is inside an anonymous
// namespace.
+// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant
// CHECK: @_ZTSN12_GLOBAL__N_11AE = internal constant
// CHECK: @_ZTIN12_GLOBAL__N_11AE = internal constant
-// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant