diff options
| author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
|---|---|---|
| committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
| commit | 79ade4e028932fcb9dab15e2fb2305ca15ab0f14 (patch) | |
| tree | e1a885aadfd80632f5bd70d4bd2d37e715e35a79 /test/CodeGenCXX | |
| parent | ecb7e5c8afe929ee38155db94de6b084ec32a645 (diff) | |
Notes
Diffstat (limited to 'test/CodeGenCXX')
| -rw-r--r-- | test/CodeGenCXX/alloca-align.cpp | 26 | ||||
| -rw-r--r-- | test/CodeGenCXX/constructors.cpp | 94 | ||||
| -rw-r--r-- | test/CodeGenCXX/default-arguments.cpp | 6 | ||||
| -rw-r--r-- | test/CodeGenCXX/destructors.cpp | 107 | ||||
| -rw-r--r-- | test/CodeGenCXX/mangle-subst-std.cpp | 6 | ||||
| -rw-r--r-- | test/CodeGenCXX/mangle-template.cpp | 40 | ||||
| -rw-r--r-- | test/CodeGenCXX/mangle.cpp | 42 | ||||
| -rw-r--r-- | test/CodeGenCXX/virtual-base-destructor-call.cpp | 34 | ||||
| -rw-r--r-- | test/CodeGenCXX/virtual-bases.cpp | 4 | ||||
| -rw-r--r-- | test/CodeGenCXX/virtual-destructor-calls.cpp | 40 | ||||
| -rw-r--r-- | test/CodeGenCXX/vtable-layout-abi-examples.cpp | 189 | ||||
| -rw-r--r-- | test/CodeGenCXX/vtable-layout-extreme.cpp | 210 | ||||
| -rw-r--r-- | test/CodeGenCXX/vtable-layout.cpp | 671 | ||||
| -rw-r--r-- | test/CodeGenCXX/vtable-pointer-initialization.cpp | 15 |
14 files changed, 1453 insertions, 31 deletions
diff --git a/test/CodeGenCXX/alloca-align.cpp b/test/CodeGenCXX/alloca-align.cpp index de6b34d06072..b70e366f4cfb 100644 --- a/test/CodeGenCXX/alloca-align.cpp +++ b/test/CodeGenCXX/alloca-align.cpp @@ -1,12 +1,28 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s -// -// CHECK: alloca %struct.MemsetRange, align 16 -struct MemsetRange { +struct s0 { int Start, End; unsigned Alignment; int TheStores __attribute__((aligned(16))); }; -void foobar() { - (void) MemsetRange(); + +// CHECK: define void @f0 +// CHECK: alloca %struct.s0, align 16 +extern "C" void f0() { + (void) s0(); +} + +// CHECK: define void @f1 +// CHECK: alloca %struct.s0, align 16 +extern "C" void f1() { + (void) (struct s0) { 0, 0, 0, 0 }; +} + +// CHECK: define i64 @f2 +// CHECK: alloca %struct.s1, align 2 +struct s1 { short x; short y; }; +extern "C" struct s1 f2(int a, struct s1 *x, struct s1 *y) { + if (a) + return *x; + return *y; } diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp new file mode 100644 index 000000000000..2c95c91e1114 --- /dev/null +++ b/test/CodeGenCXX/constructors.cpp @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s + +struct Member { int x; Member(); Member(int); Member(const Member &); }; +struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); }; + +struct ValueClass { + ValueClass(int x, int y) : x(x), y(y) {} + int x; + int y; +}; // subject to ABI trickery + + + +/* Test basic functionality. */ +class A { + A(struct Undeclared &); + A(ValueClass); + Member mem; +}; + +A::A(struct Undeclared &ref) : mem(0) {} + +// Check that delegation works. +// CHECK: define void @_ZN1AC1ER10Undeclared( +// CHECK: call void @_ZN1AC2ER10Undeclared( + +// CHECK: define void @_ZN1AC2ER10Undeclared( +// CHECK: call void @_ZN6MemberC1Ei( + +A::A(ValueClass v) : mem(v.y - v.x) {} + +// CHECK: define void @_ZN1AC1E10ValueClass( +// CHECK: call void @_ZN1AC2E10ValueClass( + +// CHECK: define void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + + +/* Test that things work for inheritance. */ +struct B : A { + B(struct Undeclared &); + Member mem; +}; + +B::B(struct Undeclared &ref) : A(ref), mem(1) {} + +// CHECK: define void @_ZN1BC1ER10Undeclared( +// CHECK: call void @_ZN1BC2ER10Undeclared( + +// CHECK: define void @_ZN1BC2ER10Undeclared( +// CHECK: call void @_ZN1AC2ER10Undeclared( +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for classes with + virtual bases (for now). This is necessary because a vbase + initializer could access one of the parameter variables by + reference. That's a solvable problem, but let's not solve it right + now. */ +struct C : virtual A { + C(int); + Member mem; +}; +C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {} + +// CHECK: define void @_ZN1CC1Ei( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1CC2Ei( +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for varargs + constructors. */ +struct D : A { + D(int, ...); + Member mem; +}; + +D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} + +// CHECK: define void @_ZN1DC1Eiz( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1DC2Eiz( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp index 282e5d0d5042..2ed1567697ca 100644 --- a/test/CodeGenCXX/default-arguments.cpp +++ b/test/CodeGenCXX/default-arguments.cpp @@ -43,11 +43,7 @@ struct C { }; // CHECK: define void @_ZN1CC1Ev( -// CHECK: call void @_ZN2A1C1Ev( -// CHECK: call void @_ZN2A2C1Ev( -// CHECK: call void @_ZN1BC1ERK2A1RK2A2( -// CHECK: call void @_ZN2A2D1Ev -// CHECK: call void @_ZN2A1D1Ev +// CHECK: call void @_ZN1CC2Ev( // CHECK: define void @_ZN1CC2Ev( // CHECK: call void @_ZN2A1C1Ev( diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 0a7e1e5505ed..d40b174012ff 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -1,4 +1,11 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - +// RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s + +// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev +// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev + struct A { int a; @@ -42,3 +49,101 @@ namespace PR5529 { B::~B() {} } + +// FIXME: there's a known problem in the codegen here where, if one +// destructor throws, the remaining destructors aren't run. Fix it, +// then make this code check for it. +namespace test0 { + void foo(); + struct VBase { ~VBase(); }; + struct Base { ~Base(); }; + struct Member { ~Member(); }; + + struct A : Base { + Member M; + ~A(); + }; + + // The function-try-block won't suppress -mconstructor-aliases here. + A::~A() try { } catch (int i) {} + +// complete destructor alias tested above + +// CHECK: define void @_ZN5test01AD2Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] + + struct B : Base, virtual VBase { + Member M; + ~B(); + }; + B::~B() try { } catch (int i) {} + // It will suppress the delegation optimization here, though. + +// CHECK: define void @_ZN5test01BD1Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test05VBaseD2Ev +// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]] + +// CHECK: define void @_ZN5test01BD2Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +} + +// Test base-class aliasing. +namespace test1 { + struct A { ~A(); char ***m; }; // non-trivial destructor + struct B { ~B(); }; // non-trivial destructor + struct Empty { }; // trivial destructor, empty + struct NonEmpty { int x; }; // trivial destructor, non-empty + + // There must be a definition in this translation unit for the alias + // optimization to apply. + A::~A() { delete m; } + + struct M : A { ~M(); }; + M::~M() {} // alias tested above + + struct N : A, Empty { ~N(); }; + N::~N() {} // alias tested above + + struct O : Empty, A { ~O(); }; + O::~O() {} // alias tested above + + struct P : NonEmpty, A { ~P(); }; + P::~P() {} // CHECK: define void @_ZN5test11PD2Ev + + struct Q : A, B { ~Q(); }; + Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev + + struct R : A { ~R(); }; + R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev + + struct S : A { ~S(); int x; }; + S::~S() {} // alias tested above + + struct T : A { ~T(); B x; }; + T::~T() {} // CHECK: define void @_ZN5test11TD2Ev + + // The VTT parameter prevents this. We could still make this work + // for calling conventions that are safe against extra parameters. + struct U : A, virtual B { ~U(); }; + U::~U() {} // CHECK: define void @_ZN5test11UD2Ev +} + +// PR6471 +namespace test2 { + struct A { ~A(); char ***m; }; + struct B : A { ~B(); }; + + B::~B() {} + // CHECK: define void @_ZN5test21BD2Ev + // CHECK: call void @_ZN5test21AD2Ev +} diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index 913c8f101b54..062610bd74a6 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -55,3 +55,9 @@ namespace std terminate_handler set_terminate(terminate_handler) { return 0; } } } + +// Make sure we don't treat the following like std::string +// CHECK: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE +template<typename, typename, typename> struct basic_string { }; +typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string; +void f(not_string) { } diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp index c8296f3c4bd7..57f30a762ed0 100644 --- a/test/CodeGenCXX/mangle-template.cpp +++ b/test/CodeGenCXX/mangle-template.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s - namespace test1 { int x; template <int& D> class T { }; @@ -66,3 +65,42 @@ template <void(A::*)(float)> class T { }; // CHECK-FAIL: void @_ZN5test62f0ENS_1TIXadL_ZNS_1A3im0EfEEEE( void f0(T<&A::im0> a0) {} } + +namespace test7 { + template<typename T> + struct meta { + static const unsigned value = sizeof(T); + }; + + template<unsigned> struct int_c { + typedef float type; + }; + + template<typename T> + struct X { + template<typename U> + X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } + }; + + // CHECK: define void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE + template X<int>::X(double*, float*); +} + +namespace test8 { + template<typename T> + struct meta { + struct type { + static const unsigned value = sizeof(T); + }; + }; + + template<unsigned> struct int_c { + typedef float type; + }; + + template<typename T> + void f(int_c<meta<T>::type::value>) { } + + // CHECK: define void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE + template void f<int>(int_c<sizeof(int)>); +} diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 07183782e75e..e18ca03d1be2 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks -std=c++0x | FileCheck %s struct X { }; struct Y { }; @@ -363,7 +363,7 @@ namespace test0 { char buffer[1024]; j<A>(buffer); } - // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszmecvT__E6buffer_c( + // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c( } namespace test1 { @@ -376,3 +376,41 @@ namespace test1 { // CHECK: define internal void @_Z27functionWithInternalLinkagev() static void functionWithInternalLinkage() { } void g() { functionWithInternalLinkage(); } + +namespace test2 { + template <class T> decltype(((T*) 0)->member) read_member(T& obj) { + return obj.member; + } + + struct A { int member; } obj; + int test() { + return read_member(obj); + } + + // CHECK: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_( +} + +namespace test3 { + struct AmbiguousBase { int ab; }; + struct Path1 : AmbiguousBase { float p; }; + struct Path2 : AmbiguousBase { double p; }; + struct Derived : Path1, Path2 { }; + + //template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; } + //template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; } + + // define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_( + template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; } + + // define linkonce_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_( + template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; } + + Derived obj; + void test() { + // FIXME: uncomment these when we support diamonds competently + //get_ab_1(obj); + //get_ab_2(obj); + get_p_1(obj); + get_p_2(obj); + } +} diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index 1ee598afdc3f..b6e85e208b15 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -16,4 +16,36 @@ basic_iostream<char> res; int main() { } -// CHECK: call void @_ZN9basic_iosD2Ev +// basic_iostream's complete dtor calls its base dtor, then its +// virtual base's dtor. +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev +// CHECK: call void @_ZN14basic_iostreamIcED2Ev +// CHECK: call void @_ZN9basic_iosD2Ev + +// basic_iostream's deleting dtor calls its complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev +// CHECK: call void @_ZN14basic_iostreamIcED1Ev +// CHECK: call void @_ZdlPv + +// basic_istream's complete dtor calls the base dtor, +// then its virtual base's base dtor. +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev +// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: call void @_ZN9basic_iosD2Ev + +// basic_istream's deleting dtor calls the complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev +// CHECK: call void @_ZN13basic_istreamIcED1Ev +// CHECK: call void @_ZdlPv + +// basic_iostream's base dtor calls its non-virtual base dtor. +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev +// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: } + +// basic_istream's base dtor is a no-op. +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev +// CHECK-NOT: call +// CHECK: } diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp index 200f21a5da72..627717576302 100644 --- a/test/CodeGenCXX/virtual-bases.cpp +++ b/test/CodeGenCXX/virtual-bases.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s struct A { A(); }; -// CHECK: define void @_ZN1AC1Ev(%struct.A* %this) +// CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev // CHECK: define void @_ZN1AC2Ev(%struct.A* %this) A::A() { } diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp index 01ca1442f2c4..c5b9262a0678 100644 --- a/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -1,24 +1,48 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s + +struct Member { + ~Member(); +}; struct A { virtual ~A(); }; struct B : A { + Member m; virtual ~B(); }; -// Complete dtor. -// CHECK: define void @_ZN1BD1Ev -// CHECK: call void @_ZN1AD2Ev +// Complete dtor: just an alias because there are no virtual bases. +// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev -// Deleting dtor. +// (aliases from C) +// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev +// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev + +// Deleting dtor: defers to the complete dtor. // CHECK: define void @_ZN1BD0Ev -// CHECK: call void @_ZN1AD2Ev -// check: call void @_ZdlPv +// CHECK: call void @_ZN1BD1Ev +// CHECK: call void @_ZdlPv -// Base dtor. +// Base dtor: actually calls A's base dtor. // CHECK: define void @_ZN1BD2Ev +// CHECK: call void @_ZN6MemberD1Ev // CHECK: call void @_ZN1AD2Ev B::~B() { } + +struct C : B { + ~C(); +}; + +C::~C() { } + +// Complete dtor: just an alias (checked above). + +// Deleting dtor: defers to the complete dtor. +// CHECK: define void @_ZN1CD0Ev +// CHECK: call void @_ZN1CD1Ev +// CHECK: call void @_ZdlPv + +// Base dtor: just an alias to B's base dtor. diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp new file mode 100644 index 000000000000..2c6b7a48ccfe --- /dev/null +++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp @@ -0,0 +1,189 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s + +/// Examples from the Itanium C++ ABI specification. +/// http://www.codesourcery.com/public/cxx-abi/ + +namespace Test1 { + +// This is from http://www.codesourcery.com/public/cxx-abi/cxx-vtable-ex.html + +// CHECK: Vtable for 'Test1::A' (5 entries). +// CHECK-NEXT: 0 | offset_to_top (0) +// CHECK-NEXT: 1 | Test1::A RTTI +// CHECK-NEXT: -- (Test1::A, 0) vtable address -- +// CHECK-NEXT: 2 | void Test1::A::f() +// CHECK-NEXT: 3 | void Test1::A::g() +// CHECK-NEXT: 4 | void Test1::A::h() +struct A { + virtual void f (); + virtual void g (); + virtual void h (); + int ia; +}; +void A::f() {} + +// CHECK: Vtable for 'Test1::B' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test1::B RTTI +// CHECK-NEXT: -- (Test1::B, 0) vtable address -- +// CHECK-NEXT: 3 | void Test1::B::f() +// CHECK-NEXT: 4 | void Test1::B::h() +// CHECK-NEXT: 5 | vcall_offset (-16) +// CHECK-NEXT: 6 | vcall_offset (0) +// CHECK-NEXT: 7 | vcall_offset (-16) +// CHECK-NEXT: 8 | offset_to_top (-16) +// CHECK-NEXT: 9 | Test1::B RTTI +// CHECK-NEXT: -- (Test1::A, 16) vtable address -- +// CHECK-NEXT: 10 | void Test1::B::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 11 | void Test1::A::g() +// CHECK-NEXT: 12 | void Test1::B::h() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct B: public virtual A { + void f (); + void h (); + int ib; +}; +void B::f() {} + +// CHECK: Vtable for 'Test1::C' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test1::C RTTI +// CHECK-NEXT: -- (Test1::C, 0) vtable address -- +// CHECK-NEXT: 3 | void Test1::C::g() +// CHECK-NEXT: 4 | void Test1::C::h() +// CHECK-NEXT: 5 | vcall_offset (-16) +// CHECK-NEXT: 6 | vcall_offset (-16) +// CHECK-NEXT: 7 | vcall_offset (0) +// CHECK-NEXT: 8 | offset_to_top (-16) +// CHECK-NEXT: 9 | Test1::C RTTI +// CHECK-NEXT: -- (Test1::A, 16) vtable address -- +// CHECK-NEXT: 10 | void Test1::A::f() +// CHECK-NEXT: 11 | void Test1::C::g() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 12 | void Test1::C::h() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct C: public virtual A { + void g (); + void h (); + int ic; +}; +void C::g() {} + +// CHECK: Vtable for 'Test1::D' (18 entries). +// CHECK-NEXT: 0 | vbase_offset (32) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test1::D RTTI +// CHECK-NEXT: -- (Test1::B, 0) vtable address -- +// CHECK-NEXT: -- (Test1::D, 0) vtable address -- +// CHECK-NEXT: 3 | void Test1::B::f() +// CHECK-NEXT: 4 | void Test1::D::h() +// CHECK-NEXT: 5 | vbase_offset (16) +// CHECK-NEXT: 6 | offset_to_top (-16) +// CHECK-NEXT: 7 | Test1::D RTTI +// CHECK-NEXT: -- (Test1::C, 16) vtable address -- +// CHECK-NEXT: 8 | void Test1::C::g() +// CHECK-NEXT: 9 | void Test1::D::h() +// CHECK-NEXT: [this adjustment: -16 non-virtual] +// CHECK-NEXT: 10 | vcall_offset (-32) +// CHECK-NEXT: 11 | vcall_offset (-16) +// CHECK-NEXT: 12 | vcall_offset (-32) +// CHECK-NEXT: 13 | offset_to_top (-32) +// CHECK-NEXT: 14 | Test1::D RTTI +// CHECK-NEXT: -- (Test1::A, 32) vtable address -- +// CHECK-NEXT: 15 | void Test1::B::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 16 | void Test1::C::g() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 17 | void Test1::D::h() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct D: public B, public C { + void h (); + int id; +}; +void D::h() { } + +struct X { + int ix; + virtual void x(); +}; + +// CHECK: Vtable for 'Test1::E' (24 entries). +// CHECK-NEXT: 0 | vbase_offset (56) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test1::E RTTI +// CHECK-NEXT: -- (Test1::E, 0) vtable address -- +// CHECK-NEXT: -- (Test1::X, 0) vtable address -- +// CHECK-NEXT: 3 | void Test1::X::x() +// CHECK-NEXT: 4 | void Test1::E::f() +// CHECK-NEXT: 5 | void Test1::E::h() +// CHECK-NEXT: 6 | vbase_offset (40) +// CHECK-NEXT: 7 | offset_to_top (-16) +// CHECK-NEXT: 8 | Test1::E RTTI +// CHECK-NEXT: -- (Test1::B, 16) vtable address -- +// CHECK-NEXT: -- (Test1::D, 16) vtable address -- +// CHECK-NEXT: 9 | void Test1::E::f() +// CHECK-NEXT: [this adjustment: -16 non-virtual] +// CHECK-NEXT: 10 | void Test1::E::h() +// CHECK-NEXT: [this adjustment: -16 non-virtual] +// CHECK-NEXT: 11 | vbase_offset (24) +// CHECK-NEXT: 12 | offset_to_top (-32) +// CHECK-NEXT: 13 | Test1::E RTTI +// CHECK-NEXT: -- (Test1::C, 32) vtable address -- +// CHECK-NEXT: 14 | void Test1::C::g() +// CHECK-NEXT: 15 | void Test1::E::h() +// CHECK-NEXT: [this adjustment: -32 non-virtual] +// CHECK-NEXT: 16 | vcall_offset (-56) +// CHECK-NEXT: 17 | vcall_offset (-24) +// CHECK-NEXT: 18 | vcall_offset (-56) +// CHECK-NEXT: 19 | offset_to_top (-56) +// CHECK-NEXT: 20 | Test1::E RTTI +// CHECK-NEXT: -- (Test1::A, 56) vtable address -- +// CHECK-NEXT: 21 | void Test1::E::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 22 | void Test1::C::g() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 23 | void Test1::E::h() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct E : X, D { + int ie; + void f(); + void h (); +}; +void E::f() { } + +} + +namespace Test2 { + +// From http://www.codesourcery.com/public/cxx-abi/abi.html#class-types. + +struct A { virtual void f(); }; +struct B : virtual public A { int i; }; +struct C : virtual public A { int j; }; + +// CHECK: Vtable for 'Test2::D' (11 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test2::D RTTI +// CHECK-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-NEXT: -- (Test2::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test2::A::f() +// CHECK-NEXT: 5 | void Test2::D::d() +// CHECK-NEXT: 6 | vbase_offset (-16) +// 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 { + virtual void d(); +}; +void D::d() { } + +} diff --git a/test/CodeGenCXX/vtable-layout-extreme.cpp b/test/CodeGenCXX/vtable-layout-extreme.cpp new file mode 100644 index 000000000000..14e787940c20 --- /dev/null +++ b/test/CodeGenCXX/vtable-layout-extreme.cpp @@ -0,0 +1,210 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s + +// A collection of big class hierarchies and their vtables. + +namespace Test1 { + +class C0 +{ +}; +class C1 + : virtual public C0 +{ + int k0; +}; +class C2 + : public C0 + , virtual public C1 +{ + int k0; +}; +class C3 + : virtual public C0 + , virtual public C1 + , public C2 +{ + int k0; + int k1; + int k2; + int k3; +}; +class C4 + : public C2 + , virtual public C3 + , public C0 +{ + int k0; +}; +class C5 + : public C0 + , virtual public C4 + , public C2 + , public C1 + , virtual public C3 +{ + int k0; +}; +class C6 + : virtual public C3 + , public C0 + , public C5 + , public C4 + , public C1 +{ + int k0; +}; +class C7 + : virtual public C5 + , virtual public C6 + , virtual public C3 + , public C4 + , virtual public C2 +{ + int k0; + int k1; +}; +class C8 + : public C7 + , public C5 + , public C3 + , virtual public C4 + , public C1 + , public C2 +{ + int k0; + int k1; +}; + +// CHECK: Vtable for 'Test1::C9' (87 entries). +// CHECK-NEXT: 0 | vbase_offset (344) +// CHECK-NEXT: 1 | vbase_offset (312) +// CHECK-NEXT: 2 | vbase_offset (184) +// CHECK-NEXT: 3 | vbase_offset (168) +// CHECK-NEXT: 4 | vbase_offset (120) +// CHECK-NEXT: 5 | vbase_offset (48) +// CHECK-NEXT: 6 | vbase_offset (148) +// CHECK-NEXT: 7 | vbase_offset (152) +// CHECK-NEXT: 8 | offset_to_top (0) +// CHECK-NEXT: 9 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 0) vtable address -- +// CHECK-NEXT: -- (Test1::C9, 0) vtable address -- +// CHECK-NEXT: 10 | void Test1::C9::f() +// CHECK-NEXT: 11 | vbase_offset (104) +// CHECK-NEXT: 12 | vbase_offset (132) +// CHECK-NEXT: 13 | vbase_offset (136) +// CHECK-NEXT: 14 | offset_to_top (-16) +// CHECK-NEXT: 15 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 16) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 16) vtable address -- +// CHECK-NEXT: 16 | vbase_offset (72) +// CHECK-NEXT: 17 | vbase_offset (120) +// CHECK-NEXT: 18 | vbase_offset (100) +// CHECK-NEXT: 19 | vbase_offset (104) +// CHECK-NEXT: 20 | offset_to_top (-48) +// CHECK-NEXT: 21 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C6, 48) vtable address -- +// CHECK-NEXT: 22 | vbase_offset (84) +// CHECK-NEXT: 23 | offset_to_top (-64) +// CHECK-NEXT: 24 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 64) vtable address -- +// CHECK-NEXT: 25 | vbase_offset (32) +// CHECK-NEXT: 26 | vbase_offset (60) +// CHECK-NEXT: 27 | vbase_offset (64) +// CHECK-NEXT: 28 | offset_to_top (-88) +// CHECK-NEXT: 29 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 88) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 88) vtable address -- +// CHECK-NEXT: 30 | vbase_offset (44) +// CHECK-NEXT: 31 | offset_to_top (-104) +// CHECK-NEXT: 32 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 104) vtable address -- +// CHECK-NEXT: 33 | vbase_offset (28) +// CHECK-NEXT: 34 | vbase_offset (32) +// CHECK-NEXT: 35 | offset_to_top (-120) +// CHECK-NEXT: 36 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 120) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 120) vtable address -- +// CHECK-NEXT: 37 | vbase_offset (-4) +// CHECK-NEXT: 38 | offset_to_top (-152) +// CHECK-NEXT: 39 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 152) vtable address -- +// CHECK-NEXT: 40 | vbase_offset (-48) +// CHECK-NEXT: 41 | vbase_offset (-20) +// CHECK-NEXT: 42 | vbase_offset (-16) +// CHECK-NEXT: 43 | offset_to_top (-168) +// CHECK-NEXT: 44 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 168) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 168) vtable address -- +// CHECK-NEXT: 45 | vbase_offset (160) +// CHECK-NEXT: 46 | vbase_offset (-136) +// CHECK-NEXT: 47 | vbase_offset (-16) +// CHECK-NEXT: 48 | vbase_offset (128) +// CHECK-NEXT: 49 | vbase_offset (-64) +// CHECK-NEXT: 50 | vbase_offset (-36) +// CHECK-NEXT: 51 | vbase_offset (-32) +// CHECK-NEXT: 52 | offset_to_top (-184) +// CHECK-NEXT: 53 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C7, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C8, 184) vtable address -- +// CHECK-NEXT: 54 | vbase_offset (-88) +// CHECK-NEXT: 55 | vbase_offset (-40) +// CHECK-NEXT: 56 | vbase_offset (-60) +// CHECK-NEXT: 57 | vbase_offset (-56) +// CHECK-NEXT: 58 | offset_to_top (-208) +// CHECK-NEXT: 59 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 208) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 208) vtable address -- +// CHECK-NEXT: 60 | vbase_offset (-76) +// CHECK-NEXT: 61 | offset_to_top (-224) +// CHECK-NEXT: 62 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 224) vtable address -- +// CHECK-NEXT: 63 | vbase_offset (-92) +// CHECK-NEXT: 64 | vbase_offset (-88) +// CHECK-NEXT: 65 | offset_to_top (-240) +// CHECK-NEXT: 66 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 240) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 240) vtable address -- +// CHECK-NEXT: 67 | vbase_offset (-124) +// CHECK-NEXT: 68 | offset_to_top (-272) +// CHECK-NEXT: 69 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 272) vtable address -- +// CHECK-NEXT: 70 | vbase_offset (-140) +// CHECK-NEXT: 71 | vbase_offset (-136) +// CHECK-NEXT: 72 | offset_to_top (-288) +// CHECK-NEXT: 73 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 288) vtable address -- +// CHECK-NEXT: 74 | vbase_offset (-192) +// CHECK-NEXT: 75 | vbase_offset (-144) +// CHECK-NEXT: 76 | vbase_offset (-164) +// CHECK-NEXT: 77 | vbase_offset (-160) +// CHECK-NEXT: 78 | offset_to_top (-312) +// CHECK-NEXT: 79 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 312) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 312) vtable address -- +// CHECK-NEXT: 80 | vbase_offset (-180) +// CHECK-NEXT: 81 | offset_to_top (-328) +// CHECK-NEXT: 82 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 328) vtable address -- +// CHECK-NEXT: 83 | vbase_offset (-196) +// CHECK-NEXT: 84 | vbase_offset (-192) +// CHECK-NEXT: 85 | offset_to_top (-344) +// CHECK-NEXT: 86 | Test1::C9 RTTI +class C9 + : virtual public C6 + , public C2 + , public C4 + , virtual public C8 +{ + int k0; + int k1; + int k2; + int k3; + virtual void f(); +}; +void C9::f() { } + +} diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index 8fbe486faa47..a65af6ed33da 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -365,3 +365,674 @@ struct B : virtual A1, virtual A2 { void B::f() { } } + +namespace Test10 { + +// Test for a bug where we would not emit secondary vtables for bases +// of a primary base. +struct A1 { virtual void a1(); }; +struct A2 { virtual void a2(); }; + +// CHECK: Vtable for 'Test10::C' (7 entries). +// CHECK-NEXT: 0 | offset_to_top (0) +// CHECK-NEXT: 1 | Test10::C RTTI +// CHECK-NEXT: -- (Test10::A1, 0) vtable address -- +// CHECK-NEXT: -- (Test10::B, 0) vtable address -- +// CHECK-NEXT: -- (Test10::C, 0) vtable address -- +// CHECK-NEXT: 2 | void Test10::A1::a1() +// CHECK-NEXT: 3 | void Test10::C::f() +// CHECK-NEXT: 4 | offset_to_top (-8) +// CHECK-NEXT: 5 | Test10::C RTTI +// CHECK-NEXT: -- (Test10::A2, 8) vtable address -- +// CHECK-NEXT: 6 | void Test10::A2::a2() +struct B : A1, A2 { + int b; +}; + +struct C : B { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test11 { + +// Very simple test of vtables for virtual bases. +struct A1 { int a; }; +struct A2 { int b; }; + +struct B : A1, virtual A2 { + int b; +}; + +// CHECK: Vtable for 'Test11::C' (8 entries). +// CHECK-NEXT: 0 | vbase_offset (24) +// CHECK-NEXT: 1 | vbase_offset (8) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test11::C RTTI +// CHECK-NEXT: -- (Test11::C, 0) vtable address -- +// CHECK-NEXT: 4 | void Test11::C::f() +// CHECK-NEXT: 5 | vbase_offset (16) +// CHECK-NEXT: 6 | offset_to_top (-8) +// CHECK-NEXT: 7 | Test11::C RTTI +struct C : virtual B { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test12 { + +// Test that the right vcall offsets are generated in the right order. + +// CHECK: Vtable for 'Test12::B' (19 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::B, 0) vtable address -- +// CHECK-NEXT: 3 | void Test12::B::f() +// CHECK-NEXT: 4 | void Test12::B::a() +// CHECK-NEXT: 5 | vcall_offset (32) +// CHECK-NEXT: 6 | vcall_offset (16) +// CHECK-NEXT: 7 | vcall_offset (-8) +// CHECK-NEXT: 8 | vcall_offset (0) +// CHECK-NEXT: 9 | offset_to_top (-8) +// CHECK-NEXT: 10 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A, 8) vtable address -- +// CHECK-NEXT: -- (Test12::A1, 8) vtable address -- +// CHECK-NEXT: 11 | void Test12::A1::a1() +// CHECK-NEXT: 12 | void Test12::B::a() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 13 | offset_to_top (-24) +// CHECK-NEXT: 14 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A2, 24) vtable address -- +// CHECK-NEXT: 15 | void Test12::A2::a2() +// CHECK-NEXT: 16 | offset_to_top (-40) +// CHECK-NEXT: 17 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A3, 40) vtable address -- +// CHECK-NEXT: 18 | void Test12::A3::a3() +struct A1 { + virtual void a1(); + int a; +}; + +struct A2 { + virtual void a2(); + int a; +}; + +struct A3 { + virtual void a3(); + int a; +}; + +struct A : A1, A2, A3 { + virtual void a(); + int i; +}; + +struct B : virtual A { + virtual void f(); + + virtual void a(); +}; +void B::f() { } + +} + +namespace Test13 { + +// Test that we don't try to emit a vtable for 'A' twice. +struct A { + virtual void f(); +}; + +struct B : virtual A { + virtual void f(); +}; + +// CHECK: Vtable for 'Test13::C' (6 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vbase_offset (0) +// CHECK-NEXT: 2 | vcall_offset (0) +// CHECK-NEXT: 3 | offset_to_top (0) +// CHECK-NEXT: 4 | Test13::C RTTI +// CHECK-NEXT: -- (Test13::A, 0) vtable address -- +// CHECK-NEXT: -- (Test13::B, 0) vtable address -- +// CHECK-NEXT: -- (Test13::C, 0) vtable address -- +// CHECK-NEXT: 5 | void Test13::C::f() +struct C : virtual B, virtual A { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test14 { + +// Verify that we handle A being a non-virtual base of B, which is a virtual base. + +struct A { + virtual void f(); +}; + +struct B : A { }; + +struct C : virtual B { }; + +// CHECK: Vtable for 'Test14::D' (5 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test14::D RTTI +// CHECK-NEXT: -- (Test14::A, 0) vtable address -- +// CHECK-NEXT: -- (Test14::B, 0) vtable address -- +// CHECK-NEXT: -- (Test14::C, 0) vtable address -- +// CHECK-NEXT: -- (Test14::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test14::D::f() +struct D : C, virtual B { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test15 { + +// Test that we don't emit an extra vtable for B since it's a primary base of C. +struct A { virtual void a(); }; +struct B { virtual void b(); }; + +struct C : virtual B { }; + +// CHECK: Vtable for 'Test15::D' (11 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | vbase_offset (8) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test15::D RTTI +// CHECK-NEXT: -- (Test15::A, 0) vtable address -- +// CHECK-NEXT: -- (Test15::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test15::A::a() +// CHECK-NEXT: 5 | void Test15::D::f() +// CHECK-NEXT: 6 | vbase_offset (0) +// CHECK-NEXT: 7 | vcall_offset (0) +// CHECK-NEXT: 8 | offset_to_top (-8) +// CHECK-NEXT: 9 | Test15::D RTTI +// CHECK-NEXT: -- (Test15::B, 8) vtable address -- +// CHECK-NEXT: -- (Test15::C, 8) vtable address -- +// CHECK-NEXT: 10 | void Test15::B::b() +struct D : A, virtual B, virtual C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test16 { + +// Test that destructors share vcall offsets. + +struct A { virtual ~A(); }; +struct B { virtual ~B(); }; + +struct C : A, B { virtual ~C(); }; + +// CHECK: Vtable for 'Test16::D' (15 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test16::D RTTI +// CHECK-NEXT: -- (Test16::D, 0) vtable address -- +// CHECK-NEXT: 3 | void Test16::D::f() +// CHECK-NEXT: 4 | Test16::D::~D() [complete] +// CHECK-NEXT: 5 | Test16::D::~D() [deleting] +// CHECK-NEXT: 6 | vcall_offset (-8) +// CHECK-NEXT: 7 | offset_to_top (-8) +// CHECK-NEXT: 8 | Test16::D RTTI +// CHECK-NEXT: -- (Test16::A, 8) vtable address -- +// CHECK-NEXT: -- (Test16::C, 8) vtable address -- +// CHECK-NEXT: 9 | Test16::D::~D() [complete] +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 10 | Test16::D::~D() [deleting] +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 11 | offset_to_top (-16) +// CHECK-NEXT: 12 | Test16::D RTTI +// CHECK-NEXT: -- (Test16::B, 16) vtable address -- +// CHECK-NEXT: 13 | Test16::D::~D() [complete] +// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 14 | Test16::D::~D() [deleting] +// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +struct D : virtual C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test17 { + +// Test that we don't mark E::f in the C-in-E vtable as unused. +struct A { virtual void f(); }; +struct B : virtual A { virtual void f(); }; +struct C : virtual A { virtual void f(); }; +struct D : virtual B, virtual C { virtual void f(); }; + +// CHECK: Vtable for 'Test17::E' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vbase_offset (8) +// CHECK-NEXT: 2 | vbase_offset (0) +// CHECK-NEXT: 3 | vbase_offset (0) +// CHECK-NEXT: 4 | vcall_offset (0) +// CHECK-NEXT: 5 | offset_to_top (0) +// CHECK-NEXT: 6 | Test17::E RTTI +// CHECK-NEXT: -- (Test17::A, 0) vtable address -- +// CHECK-NEXT: -- (Test17::B, 0) vtable address -- +// CHECK-NEXT: -- (Test17::D, 0) vtable address -- +// CHECK-NEXT: -- (Test17::E, 0) vtable address -- +// CHECK-NEXT: 7 | void Test17::E::f() +// CHECK-NEXT: 8 | vbase_offset (-8) +// 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] +class E : virtual D { + virtual void f(); +}; +void E::f() {} + +} + +namespace Test18 { + +// Test that we compute the right 'this' adjustment offsets. + +struct A { + virtual void f(); + virtual void g(); +}; + +struct B : virtual A { + virtual void f(); +}; + +struct C : A, B { + virtual void g(); +}; + +// CHECK: Vtable for 'Test18::D' (24 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | vbase_offset (0) +// CHECK-NEXT: 2 | vbase_offset (0) +// CHECK-NEXT: 3 | vcall_offset (8) +// CHECK-NEXT: 4 | vcall_offset (0) +// CHECK-NEXT: 5 | offset_to_top (0) +// CHECK-NEXT: 6 | Test18::D RTTI +// CHECK-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-NEXT: -- (Test18::D, 0) vtable address -- +// CHECK-NEXT: 7 | void Test18::D::f() +// CHECK-NEXT: 8 | void Test18::C::g() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 9 | void Test18::D::h() +// CHECK-NEXT: 10 | vcall_offset (0) +// CHECK-NEXT: 11 | vcall_offset (-8) +// CHECK-NEXT: 12 | vbase_offset (-8) +// CHECK-NEXT: 13 | offset_to_top (-8) +// CHECK-NEXT: 14 | Test18::D RTTI +// CHECK-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-NEXT: 15 | void Test18::D::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 16 | void Test18::C::g() +// CHECK-NEXT: 17 | vbase_offset (-16) +// CHECK-NEXT: 18 | vcall_offset (-8) +// 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] +// CHECK-NEXT: 23 | [unused] void Test18::C::g() +struct D : virtual B, virtual C, virtual A +{ + virtual void f(); + virtual void h(); +}; +void D::f() {} + +} + +namespace Test19 { + +// Another 'this' adjustment test. + +struct A { + int a; + + virtual void f(); +}; + +struct B : A { + int b; + + virtual void g(); +}; + +struct C { + virtual void c(); +}; + +// CHECK: Vtable for 'Test19::D' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (24) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test19::D RTTI +// CHECK-NEXT: -- (Test19::C, 0) vtable address -- +// CHECK-NEXT: -- (Test19::D, 0) vtable address -- +// CHECK-NEXT: 3 | void Test19::C::c() +// CHECK-NEXT: 4 | void Test19::D::f() +// CHECK-NEXT: 5 | offset_to_top (-8) +// CHECK-NEXT: 6 | Test19::D RTTI +// CHECK-NEXT: -- (Test19::A, 8) vtable address -- +// CHECK-NEXT: -- (Test19::B, 8) vtable address -- +// CHECK-NEXT: 7 | void Test19::D::f() +// CHECK-NEXT: [this adjustment: -8 non-virtual] +// CHECK-NEXT: 8 | void Test19::B::g() +// CHECK-NEXT: 9 | vcall_offset (-24) +// CHECK-NEXT: 10 | offset_to_top (-24) +// CHECK-NEXT: 11 | Test19::D RTTI +// CHECK-NEXT: -- (Test19::A, 24) vtable address -- +// CHECK-NEXT: 12 | void Test19::D::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct D : C, B, virtual A { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test20 { + +// pure virtual member functions should never have 'this' adjustments. + +struct A { + virtual void f() = 0; + virtual void g(); +}; + +struct B : A { }; + +// CHECK: Vtable for 'Test20::C' (9 entries). +// CHECK-NEXT: 0 | offset_to_top (0) +// CHECK-NEXT: 1 | Test20::C RTTI +// CHECK-NEXT: -- (Test20::A, 0) vtable address -- +// CHECK-NEXT: -- (Test20::C, 0) vtable address -- +// CHECK-NEXT: 2 | void Test20::C::f() [pure] +// CHECK-NEXT: 3 | void Test20::A::g() +// CHECK-NEXT: 4 | void Test20::C::h() +// CHECK-NEXT: 5 | offset_to_top (-8) +// CHECK-NEXT: 6 | Test20::C RTTI +// CHECK-NEXT: -- (Test20::A, 8) vtable address -- +// CHECK-NEXT: -- (Test20::B, 8) vtable address -- +// CHECK-NEXT: 7 | void Test20::C::f() [pure] +// CHECK-NEXT: 8 | void Test20::A::g() +struct C : A, B { + virtual void f() = 0; + virtual void h(); +}; +void C::h() { } + +} + +namespace Test21 { + +// Test that we get vbase offsets right in secondary vtables. +struct A { + virtual void f(); +}; + +struct B : virtual A { }; +class C : virtual B { }; +class D : virtual C { }; + +class E : virtual C { }; + +// CHECK: Vtable for 'Test21::F' (16 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | vbase_offset (0) +// CHECK-NEXT: 2 | vbase_offset (0) +// CHECK-NEXT: 3 | vbase_offset (0) +// CHECK-NEXT: 4 | vbase_offset (0) +// CHECK-NEXT: 5 | vcall_offset (0) +// CHECK-NEXT: 6 | offset_to_top (0) +// CHECK-NEXT: 7 | Test21::F RTTI +// CHECK-NEXT: -- (Test21::A, 0) vtable address -- +// CHECK-NEXT: -- (Test21::B, 0) vtable address -- +// CHECK-NEXT: -- (Test21::C, 0) vtable address -- +// CHECK-NEXT: -- (Test21::D, 0) vtable address -- +// CHECK-NEXT: -- (Test21::F, 0) vtable address -- +// CHECK-NEXT: 8 | void Test21::F::f() +// CHECK-NEXT: 9 | vbase_offset (-8) +// CHECK-NEXT: 10 | vbase_offset (-8) +// CHECK-NEXT: 11 | vbase_offset (-8) +// 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() +class F : virtual D, virtual E { + virtual void f(); +}; +void F::f() { } + +} + +namespace Test22 { + +// Very simple construction vtable test. +struct V1 { + int v1; +}; + +struct V2 : virtual V1 { + int v2; +}; + +// CHECK: Vtable for 'Test22::C' (8 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | vbase_offset (12) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test22::C RTTI +// CHECK-NEXT: -- (Test22::C, 0) vtable address -- +// CHECK-NEXT: 4 | void Test22::C::f() +// CHECK-NEXT: 5 | vbase_offset (-4) +// CHECK-NEXT: 6 | offset_to_top (-16) +// CHECK-NEXT: 7 | Test22::C RTTI +// CHECK-NEXT: -- (Test22::V2, 16) vtable address -- + +// CHECK: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries). +// CHECK-NEXT: 0 | vbase_offset (-4) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test22::V2 RTTI + +struct C : virtual V1, virtual V2 { + int c; + virtual void f(); +}; +void C::f() { } + +} + +namespace Test23 { + +struct A { + int a; +}; + +struct B : virtual A { + int b; +}; + +struct C : A, virtual B { + int c; +}; + +// CHECK: Vtable for 'Test23::D' (7 entries). +// CHECK-NEXT: 0 | vbase_offset (20) +// CHECK-NEXT: 1 | vbase_offset (24) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test23::D RTTI +// CHECK-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-NEXT: -- (Test23::D, 0) vtable address -- +// CHECK-NEXT: 4 | vbase_offset (-4) +// CHECK-NEXT: 5 | offset_to_top (-24) +// CHECK-NEXT: 6 | Test23::D RTTI +// CHECK-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries). +// CHECK-NEXT: 0 | vbase_offset (20) +// CHECK-NEXT: 1 | vbase_offset (24) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test23::C RTTI +// CHECK-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-NEXT: 4 | vbase_offset (-4) +// CHECK-NEXT: 5 | offset_to_top (-24) +// CHECK-NEXT: 6 | Test23::C RTTI +// CHECK-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries). +// CHECK-NEXT: 0 | vbase_offset (-4) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test23::B RTTI +// CHECK-NEXT: -- (Test23::B, 24) vtable address -- + +struct D : virtual A, virtual B, C { + int d; + + void f(); +}; +void D::f() { } + +} + +namespace Test24 { + +// Another construction vtable test. + +struct A { + virtual void f(); +}; + +struct B : virtual A { }; +struct C : virtual A { }; + +// CHECK: Vtable for 'Test24::D' (10 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test24::D RTTI +// CHECK-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-NEXT: -- (Test24::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test24::D::f() +// CHECK-NEXT: 5 | vbase_offset (-8) +// 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() + +// CHECK: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test24::B RTTI +// CHECK-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-NEXT: 4 | void Test24::A::f() + +// CHECK: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries). +// CHECK-NEXT: 0 | vbase_offset (-8) +// 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() +struct D : B, C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test25 { + +// This mainly tests that we don't assert on this class hierarchy. + +struct V { + virtual void f(); +}; + +struct A : virtual V { }; +struct B : virtual V { }; + +// CHECK: Vtable for 'Test25::C' (11 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test25::C RTTI +// CHECK-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-NEXT: -- (Test25::C, 0) vtable address -- +// CHECK-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-NEXT: 4 | void Test25::V::f() +// CHECK-NEXT: 5 | void Test25::C::g() +// CHECK-NEXT: 6 | vbase_offset (-8) +// CHECK-NEXT: 7 | vcall_offset (-8) +// 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). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test25::A RTTI +// CHECK-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-NEXT: 4 | void Test25::V::f() + +// CHECK: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries). +// CHECK-NEXT: 0 | vbase_offset (-8) +// CHECK-NEXT: 1 | vcall_offset (-8) +// 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) +// CHECK-NEXT: 7 | Test25::B RTTI +// CHECK-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-NEXT: 8 | void Test25::V::f() +struct C : A, virtual V, B { + virtual void g(); +}; +void C::g() { } + +} diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp index 92e011752f3f..75620ab8e62a 100644 --- a/test/CodeGenCXX/vtable-pointer-initialization.cpp +++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp @@ -19,14 +19,14 @@ struct A : Base { Field field; }; -// CHECK: define void @_ZN1AC1Ev( +// CHECK: define void @_ZN1AC2Ev( // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev( // CHECK: ret void A::A() { } -// CHECK: define void @_ZN1AD1Ev( +// CHECK: define void @_ZN1AD2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( @@ -42,13 +42,16 @@ struct B : Base { void f() { B b; } // CHECK: define linkonce_odr void @_ZN1BC1Ev( -// CHECK: call void @_ZN4BaseC2Ev( -// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) -// CHECK: call void @_ZN5FieldC1Ev -// CHECK: ret void +// CHECK: call void @_ZN1BC2Ev( // CHECK: define linkonce_odr void @_ZN1BD1Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( // CHECK: ret void + +// CHECK: define linkonce_odr void @_ZN1BC2Ev( +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) +// CHECK: call void @_ZN5FieldC1Ev +// CHECK: ret void |
