1 // RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t 2 // RUN: FileCheck %s < %t 3 // RUN: FileCheck --check-prefix=BITCODE %s < %t.ll 4 5 namespace test1 { 6 struct 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 12 struct 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. 17 struct 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 38 void build_vftable(X *obj) { obj->g(); } 39 } 40 41 namespace test2 { 42 struct A { 43 virtual void f(); 44 }; 45 46 struct B { 47 virtual void g(); 48 virtual void h(); 49 }; 50 51 struct C { 52 virtual void g(); 53 }; 54 55 struct 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 4 72 // 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 81 void build_vftable(X *obj) { obj->g(); } 82 } 83 84 namespace test3 { 85 struct A { 86 virtual void f(); 87 }; 88 89 struct B { 90 virtual void g(); 91 virtual void h(); 92 }; 93 94 struct C: A, B { 95 // Overrides only the left child's method (A::f), needs no thunks. 96 virtual void f(); 97 }; 98 99 struct 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. 106 struct 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 0 131 // CHECK-NEXT: 0 | void test3::X::f() 132 // CHECK-NEXT: via vfptr at offset 4 133 // CHECK-NEXT: 0 | void test3::X::g() 134 135 virtual void f(); 136 virtual void g(); 137 } x; 138 139 void build_vftable(X *obj) { obj->g(); } 140 } 141 142 namespace test4 { 143 struct A { 144 virtual void foo(); 145 }; 146 struct B { 147 virtual int filler(); 148 virtual int operator-(); 149 virtual int bar(); 150 }; 151 struct 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@@Z 158 void ffun(C &c) { 159 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4 160 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]]) 161 c.bar(); 162 } 163 164 // BITCODE-LABEL: define {{.*}}"?fop@test4@@YAXAAUC@1@@Z 165 void fop(C &c) { 166 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4 167 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]]) 168 -c; 169 } 170 171 } 172 173 namespace pr30293 { 174 struct NonTrivial { 175 ~NonTrivial(); 176 int x; 177 }; 178 struct A { virtual void f(); }; 179 struct B { virtual void __cdecl g(NonTrivial); }; 180 struct C final : A, B { 181 void f() override; 182 void __cdecl g(NonTrivial) override; 183 }; 184 C *whatsthis; 185 void C::f() { g(NonTrivial()); } 186 void 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 0 192 // BITCODE: %[[this1:[^ ]*]] = load ptr, ptr %[[thisaddr]], align 4 193 // BITCODE: %[[this3:[^ ]*]] = getelementptr inbounds i8, ptr %[[this1]], i32 -4 194 // BITCODE: store ptr %[[this3]], ptr @"?whatsthis@pr30293@@3PAUC@1@A", align 4 195 } 196