317 lines · cpp
1// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t2// RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll3// RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll4// RUN: FileCheck %s < %t5 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: @"??_7A@@6B@" = linkonce_odr unnamed_addr constant { [3 x ptr] }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: @"??_7B@@6B@" = linkonce_odr unnamed_addr constant { [5 x ptr] }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: @"??_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: @"??_7D@@6B@" = linkonce_odr unnamed_addr constant { [2 x ptr] }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 key87 // methods.88 virtual ~E();89 virtual void i();90};91void E::i() {}92// NO-VFTABLE-NOT: @"??_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: @"??_7F@@6B@" = linkonce_odr unnamed_addr constant { [5 x ptr] }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: @"??_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: @"??_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 in205 // 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: @"??_7S@@6B@" = linkonce_odr unnamed_addr constant { [1 x ptr] } { [1 x ptr] [ptr @_purecall] }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