1// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t 2// RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll 3// RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll 4// RUN: FileCheck %s < %t 5 6struct A { 7 // CHECK-LABEL: VFTable for 'A' (3 entries) 8 // CHECK-NEXT: 0 | void A::f() 9 // CHECK-NEXT: 1 | void A::g() 10 // CHECK-NEXT: 2 | void A::h() 11 // CHECK-LABEL: VFTable indices for 'A' (3 entries) 12 // CHECK-NEXT: 0 | void A::f() 13 // CHECK-NEXT: 1 | void A::g() 14 // CHECK-NEXT: 2 | void A::h() 15 16 virtual void f(); 17 virtual void g(); 18 virtual void h(); 19 int ia; 20}; 21A a; 22// EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] 23void use(A *obj) { obj->f(); } 24 25struct B : A { 26 // CHECK-LABEL: VFTable for 'A' in 'B' (5 entries) 27 // CHECK-NEXT: 0 | void B::f() 28 // CHECK-NEXT: 1 | void A::g() 29 // CHECK-NEXT: 2 | void A::h() 30 // CHECK-NEXT: 3 | void B::i() 31 // CHECK-NEXT: 4 | void B::j() 32 // CHECK-LABEL: VFTable indices for 'B' (3 entries) 33 // CHECK-NEXT: 0 | void B::f() 34 // CHECK-NEXT: 3 | void B::i() 35 // CHECK-NEXT: 4 | void B::j() 36 37 virtual void f(); // overrides A::f() 38 virtual void i(); 39 virtual void j(); 40}; 41B b; 42// EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 43void use(B *obj) { obj->f(); } 44 45struct C { 46 // CHECK-LABEL: VFTable for 'C' (2 entries) 47 // CHECK-NEXT: 0 | C::~C() [scalar deleting] 48 // CHECK-NEXT: 1 | void C::f() 49 // CHECK-LABEL: VFTable indices for 'C' (2 entries). 50 // CHECK-NEXT: 0 | C::~C() [scalar deleting] 51 // CHECK-NEXT: 1 | void C::f() 52 53 virtual ~C(); 54 virtual void f(); 55}; 56void C::f() {} 57// NO-VFTABLE-NOT: @"\01??_7C@@6B@" 58void use(C *obj) { obj->f(); } 59 60struct D { 61 // CHECK-LABEL: VFTable for 'D' (2 entries) 62 // CHECK-NEXT: 0 | void D::f() 63 // CHECK-NEXT: 1 | D::~D() [scalar deleting] 64 // CHECK-LABEL: VFTable indices for 'D' (2 entries) 65 // CHECK-NEXT: 0 | void D::f() 66 // CHECK-NEXT: 1 | D::~D() [scalar deleting] 67 68 virtual void f(); 69 virtual ~D(); 70}; 71D d; 72// EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] 73void use(D *obj) { obj->f(); } 74 75struct E : A { 76 // CHECK-LABEL: VFTable for 'A' in 'E' (5 entries) 77 // CHECK-NEXT: 0 | void A::f() 78 // CHECK-NEXT: 1 | void A::g() 79 // CHECK-NEXT: 2 | void A::h() 80 // CHECK-NEXT: 3 | E::~E() [scalar deleting] 81 // CHECK-NEXT: 4 | void E::i() 82 // CHECK-LABEL: VFTable indices for 'E' (2 entries). 83 // CHECK-NEXT: 3 | E::~E() [scalar deleting] 84 // CHECK-NEXT: 4 | void E::i() 85 86 // ~E would be the key method, but it isn't used, and MS ABI has no key 87 // methods. 88 virtual ~E(); 89 virtual void i(); 90}; 91void E::i() {} 92// NO-VFTABLE-NOT: @"\01??_7E@@6B@" 93void use(E *obj) { obj->i(); } 94 95struct F : A { 96 // CHECK-LABEL: VFTable for 'A' in 'F' (5 entries) 97 // CHECK-NEXT: 0 | void A::f() 98 // CHECK-NEXT: 1 | void A::g() 99 // CHECK-NEXT: 2 | void A::h() 100 // CHECK-NEXT: 3 | void F::i() 101 // CHECK-NEXT: 4 | F::~F() [scalar deleting] 102 // CHECK-LABEL: VFTable indices for 'F' (2 entries). 103 // CHECK-NEXT: 3 | void F::i() 104 // CHECK-NEXT: 4 | F::~F() [scalar deleting] 105 106 virtual void i(); 107 virtual ~F(); 108}; 109F f; 110// EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 111void use(F *obj) { obj->i(); } 112 113struct G : E { 114 // CHECK-LABEL: VFTable for 'A' in 'E' in 'G' (6 entries) 115 // CHECK-NEXT: 0 | void G::f() 116 // CHECK-NEXT: 1 | void A::g() 117 // CHECK-NEXT: 2 | void A::h() 118 // CHECK-NEXT: 3 | G::~G() [scalar deleting] 119 // CHECK-NEXT: 4 | void E::i() 120 // CHECK-NEXT: 5 | void G::j() 121 // CHECK-LABEL: VFTable indices for 'G' (3 entries). 122 // CHECK-NEXT: 0 | void G::f() 123 // CHECK-NEXT: 3 | G::~G() [scalar deleting] 124 // CHECK-NEXT: 5 | void G::j() 125 126 virtual void f(); // overrides A::f() 127 virtual ~G(); 128 virtual void j(); 129}; 130void G::j() {} 131// NO-VFTABLE-NOT: @"\01??_7G@@6B@" 132void use(G *obj) { obj->j(); } 133 134// Test that the usual Itanium-style key method does not emit a vtable. 135struct H { 136 virtual void f(); 137}; 138void H::f() {} 139// NO-VFTABLE-NOT: @"\01??_7H@@6B@" 140 141struct Empty { }; 142 143struct I : Empty { 144 // CHECK-LABEL: VFTable for 'I' (2 entries) 145 // CHECK-NEXT: 0 | void I::f() 146 // CHECK-NEXT: 1 | void I::g() 147 virtual void f(); 148 virtual void g(); 149}; 150 151I i; 152void use(I *obj) { obj->f(); } 153 154struct J { 155 // CHECK-LABEL: VFTable for 'J' (6 entries) 156 // CHECK-NEXT: 0 | void J::foo(long) 157 // CHECK-NEXT: 1 | void J::foo(int) 158 // CHECK-NEXT: 2 | void J::foo(short) 159 // CHECK-NEXT: 3 | void J::bar(long) 160 // CHECK-NEXT: 4 | void J::bar(int) 161 // CHECK-NEXT: 5 | void J::bar(short) 162 virtual void foo(short); 163 virtual void bar(short); 164 virtual void foo(int); 165 virtual void bar(int); 166 virtual void foo(long); 167 virtual void bar(long); 168}; 169 170J j; 171void use(J *obj) { obj->foo(42); } 172 173struct K : J { 174 // CHECK-LABEL: VFTable for 'J' in 'K' (9 entries) 175 // CHECK-NEXT: 0 | void J::foo(long) 176 // CHECK-NEXT: 1 | void J::foo(int) 177 // CHECK-NEXT: 2 | void J::foo(short) 178 // CHECK-NEXT: 3 | void J::bar(long) 179 // CHECK-NEXT: 4 | void J::bar(int) 180 // CHECK-NEXT: 5 | void J::bar(short) 181 // CHECK-NEXT: 6 | void K::bar(double) 182 // CHECK-NEXT: 7 | void K::bar(float) 183 // CHECK-NEXT: 8 | void K::foo(float) 184 virtual void bar(float); 185 virtual void foo(float); 186 virtual void bar(double); 187}; 188 189K k; 190void use(K *obj) { obj->foo(42.0f); } 191 192struct L : J { 193 // CHECK-LABEL: VFTable for 'J' in 'L' (9 entries) 194 // CHECK-NEXT: 0 | void J::foo(long) 195 // CHECK-NEXT: 1 | void L::foo(int) 196 // CHECK-NEXT: 2 | void J::foo(short) 197 // CHECK-NEXT: 3 | void J::bar(long) 198 // CHECK-NEXT: 4 | void J::bar(int) 199 // CHECK-NEXT: 5 | void J::bar(short) 200 // CHECK-NEXT: 6 | void L::foo(float) 201 // CHECK-NEXT: 7 | void L::bar(double) 202 // CHECK-NEXT: 8 | void L::bar(float) 203 204 // This case is interesting. Since the J::foo(int) override is the first method in 205 // the class, foo(float) precedes the bar(double) and bar(float) in the vftable. 206 virtual void foo(int); 207 virtual void bar(float); 208 virtual void foo(float); 209 virtual void bar(double); 210}; 211 212L l; 213void use(L *obj) { obj->foo(42.0f); } 214 215struct M : J { 216 // CHECK-LABEL: VFTable for 'J' in 'M' (11 entries) 217 // CHECK-NEXT: 0 | void J::foo(long) 218 // CHECK-NEXT: 1 | void M::foo(int) 219 // CHECK-NEXT: 2 | void J::foo(short) 220 // CHECK-NEXT: 3 | void J::bar(long) 221 // CHECK-NEXT: 4 | void J::bar(int) 222 // CHECK-NEXT: 5 | void J::bar(short) 223 // CHECK-NEXT: 6 | void M::foo(float) 224 // CHECK-NEXT: 7 | void M::spam(long) 225 // CHECK-NEXT: 8 | void M::spam(int) 226 // CHECK-NEXT: 9 | void M::bar(double) 227 // CHECK-NEXT: 10 | void M::bar(float) 228 229 virtual void foo(int); 230 virtual void spam(int); 231 virtual void bar(float); 232 virtual void bar(double); 233 virtual void foo(float); 234 virtual void spam(long); 235}; 236 237M m; 238void use(M *obj) { obj->foo(42.0f); } 239 240struct N { 241 // CHECK-LABEL: VFTable for 'N' (4 entries) 242 // CHECK-NEXT: 0 | void N::operator+(int) 243 // CHECK-NEXT: 1 | void N::operator+(short) 244 // CHECK-NEXT: 2 | void N::operator*(int) 245 // CHECK-NEXT: 3 | void N::operator*(short) 246 virtual void operator+(short); 247 virtual void operator*(short); 248 virtual void operator+(int); 249 virtual void operator*(int); 250}; 251 252N n; 253void use(N *obj) { obj->operator+(42); } 254 255struct O { virtual A *f(); }; 256struct P : O { virtual B *f(); }; 257P p; 258void use(O *obj) { obj->f(); } 259void use(P *obj) { obj->f(); } 260// CHECK-LABEL: VFTable for 'O' (1 entry) 261// CHECK-NEXT: 0 | A *O::f() 262 263// CHECK-LABEL: VFTable for 'O' in 'P' (1 entry) 264// CHECK-NEXT: 0 | B *P::f() 265 266struct Q { 267 // CHECK-LABEL: VFTable for 'Q' (2 entries) 268 // CHECK-NEXT: 0 | void Q::foo(int) 269 // CHECK-NEXT: 1 | void Q::bar(int) 270 void foo(short); 271 void bar(short); 272 virtual void bar(int); 273 virtual void foo(int); 274}; 275 276Q q; 277void use(Q *obj) { obj->foo(42); } 278 279// Inherited non-virtual overloads don't participate in the ordering. 280struct R : Q { 281 // CHECK-LABEL: VFTable for 'Q' in 'R' (4 entries) 282 // CHECK-NEXT: 0 | void Q::foo(int) 283 // CHECK-NEXT: 1 | void Q::bar(int) 284 // CHECK-NEXT: 2 | void R::bar(long) 285 // CHECK-NEXT: 3 | void R::foo(long) 286 virtual void bar(long); 287 virtual void foo(long); 288}; 289 290R r; 291void use(R *obj) { obj->foo(42l); } 292 293struct S { 294 // CHECK-LABEL: VFTable for 'S' (1 entry). 295 // CHECK-NEXT: 0 | void S::f() [deleted] 296 virtual void f() = delete; 297 S(); 298 // EMITS-VFTABLE-DAG: @"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)] 299}; 300 301S::S() {} 302 303struct T { 304 struct U {}; 305}; 306struct V : T { 307 // CHECK-LABEL: VFTable for 'V' (2 entries). 308 // CHECK-NEXT: 0 | void V::U() 309 // CHECK-NEXT: 1 | void V::f() 310 using T::U; 311 virtual void f(); 312 virtual void U(); 313 V(); 314}; 315 316V::V() {} 317