196 lines · cpp
1// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t2// RUN: FileCheck %s < %t3// RUN: FileCheck --check-prefix=BITCODE %s < %t.ll4 5namespace test1 {6struct A {7 virtual void g();8 // Add an extra virtual method so it's easier to check for the absence of thunks.9 virtual void h();10};11 12struct B {13 virtual void g(); // Collides with A::g if both are bases of some class.14};15 16// Overrides methods of two bases at the same time, thus needing thunks.17struct X : A, B {18 // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (2 entries).19 // CHECK-NEXT: 0 | void test1::X::g()20 // CHECK-NEXT: 1 | void test1::A::h()21 22 // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (1 entry).23 // CHECK-NEXT: 0 | void test1::X::g()24 // CHECK-NEXT: [this adjustment: -4 non-virtual]25 26 // CHECK-LABEL: Thunks for 'void test1::X::g()' (1 entry).27 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]28 29 // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).30 // CHECK-NEXT: 0 | void test1::X::g()31 32 // BITCODE-DAG: @"??_7X@test1@@6BA@1@@"33 // BITCODE-DAG: @"??_7X@test1@@6BB@1@@"34 35 virtual void g();36} x;37 38void build_vftable(X *obj) { obj->g(); }39}40 41namespace test2 {42struct A {43 virtual void f();44};45 46struct B {47 virtual void g();48 virtual void h();49};50 51struct C {52 virtual void g();53};54 55struct X : A, B, C {56 // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry).57 // CHECK-NEXT: 0 | void test2::A::f()58 59 // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries).60 // CHECK-NEXT: 0 | void test2::X::g()61 // CHECK-NEXT: 1 | void test2::B::h()62 63 // CHECK-LABEL: VFTable for 'test2::C' in 'test2::X' (1 entry).64 // CHECK-NEXT: 0 | void test2::X::g()65 // CHECK-NEXT: [this adjustment: -4 non-virtual]66 67 // CHECK-LABEL: Thunks for 'void test2::X::g()' (1 entry).68 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]69 70 // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).71 // CHECK-NEXT: via vfptr at offset 472 // CHECK-NEXT: 0 | void test2::X::g()73 74 // BITCODE-DAG: @"??_7X@test2@@6BA@1@@"75 // BITCODE-DAG: @"??_7X@test2@@6BB@1@@"76 // BITCODE-DAG: @"??_7X@test2@@6BC@1@@"77 78 virtual void g();79} x;80 81void build_vftable(X *obj) { obj->g(); }82}83 84namespace test3 {85struct A {86 virtual void f();87};88 89struct B {90 virtual void g();91 virtual void h();92};93 94struct C: A, B {95 // Overrides only the left child's method (A::f), needs no thunks.96 virtual void f();97};98 99struct D: A, B {100 // Overrides only the right child's method (B::g),101 // needs this adjustment but not thunks.102 virtual void g();103};104 105// Overrides methods of two bases at the same time, thus needing thunks.106struct X: C, D {107 // CHECK-LABEL: VFTable for 'test3::A' in 'test3::C' in 'test3::X' (1 entry).108 // CHECK-NEXT: 0 | void test3::X::f()109 110 // CHECK-LABEL: VFTable for 'test3::B' in 'test3::C' in 'test3::X' (2 entries).111 // CHECK-NEXT: 0 | void test3::X::g()112 // CHECK-NEXT: 1 | void test3::B::h()113 114 // CHECK-LABEL: VFTable for 'test3::A' in 'test3::D' in 'test3::X' (1 entry).115 // CHECK-NEXT: 0 | void test3::X::f()116 // CHECK-NEXT: [this adjustment: -8 non-virtual]117 118 // CHECK-LABEL: Thunks for 'void test3::X::f()' (1 entry).119 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]120 121 // CHECK-LABEL: VFTable for 'test3::B' in 'test3::D' in 'test3::X' (2 entries).122 // CHECK-NEXT: 0 | void test3::X::g()123 // CHECK-NEXT: [this adjustment: -8 non-virtual]124 // CHECK-NEXT: 1 | void test3::B::h()125 126 // CHECK-LABEL: Thunks for 'void test3::X::g()' (1 entry).127 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]128 129 // CHECK-LABEL: VFTable indices for 'test3::X' (2 entries).130 // CHECK-NEXT: via vfptr at offset 0131 // CHECK-NEXT: 0 | void test3::X::f()132 // CHECK-NEXT: via vfptr at offset 4133 // CHECK-NEXT: 0 | void test3::X::g()134 135 virtual void f();136 virtual void g();137} x;138 139void build_vftable(X *obj) { obj->g(); }140}141 142namespace test4 {143struct A {144 virtual void foo();145};146struct B {147 virtual int filler();148 virtual int operator-();149 virtual int bar();150};151struct C : public A, public B {152 virtual int filler();153 virtual int operator-();154 virtual int bar();155};156 157// BITCODE-LABEL: define {{.*}}"?ffun@test4@@YAXAAUC@1@@Z158void ffun(C &c) {159 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4160 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]])161 c.bar();162}163 164// BITCODE-LABEL: define {{.*}}"?fop@test4@@YAXAAUC@1@@Z165void fop(C &c) {166 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4167 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]])168 -c;169}170 171}172 173namespace pr30293 {174struct NonTrivial {175 ~NonTrivial();176 int x;177};178struct A { virtual void f(); };179struct B { virtual void __cdecl g(NonTrivial); };180struct C final : A, B {181 void f() override;182 void __cdecl g(NonTrivial) override;183};184C *whatsthis;185void C::f() { g(NonTrivial()); }186void C::g(NonTrivial o) {187 whatsthis = this;188}189 190// BITCODE-LABEL: define dso_local void @"?g@C@pr30293@@UAAXUNonTrivial@2@@Z"(ptr inalloca(<{ ptr, %"struct.pr30293::NonTrivial" }>) %0)191// BITCODE: %[[thisaddr:[^ ]*]] = getelementptr inbounds nuw <{ ptr, %"struct.pr30293::NonTrivial" }>, ptr {{.*}}, i32 0, i32 0192// BITCODE: %[[this1:[^ ]*]] = load ptr, ptr %[[thisaddr]], align 4193// BITCODE: %[[this3:[^ ]*]] = getelementptr inbounds i8, ptr %[[this1]], i32 -4194// BITCODE: store ptr %[[this3]], ptr @"?whatsthis@pr30293@@3PAUC@1@A", align 4195}196