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 6 struct 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 }; 21 A a; 22 // EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] 23 void use(A *obj) { obj->f(); } 24 25 struct 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 }; 41 B b; 42 // EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 43 void use(B *obj) { obj->f(); } 44 45 struct 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 }; 56 void C::f() {} 57 // NO-VFTABLE-NOT: @"\01??_7C@@6B@" 58 void use(C *obj) { obj->f(); } 59 60 struct 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 }; 71 D d; 72 // EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] 73 void use(D *obj) { obj->f(); } 74 75 struct 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 }; 91 void E::i() {} 92 // NO-VFTABLE-NOT: @"\01??_7E@@6B@" 93 void use(E *obj) { obj->i(); } 94 95 struct 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 }; 109 F f; 110 // EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 111 void use(F *obj) { obj->i(); } 112 113 struct 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 }; 130 void G::j() {} 131 // NO-VFTABLE-NOT: @"\01??_7G@@6B@" 132 void use(G *obj) { obj->j(); } 133 134 // Test that the usual Itanium-style key method does not emit a vtable. 135 struct H { 136 virtual void f(); 137 }; 138 void H::f() {} 139 // NO-VFTABLE-NOT: @"\01??_7H@@6B@" 140 141 struct Empty { }; 142 143 struct 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 151 I i; 152 void use(I *obj) { obj->f(); } 153 154 struct 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 170 J j; 171 void use(J *obj) { obj->foo(42); } 172 173 struct 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 189 K k; 190 void use(K *obj) { obj->foo(42.0f); } 191 192 struct 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 212 L l; 213 void use(L *obj) { obj->foo(42.0f); } 214 215 struct 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 237 M m; 238 void use(M *obj) { obj->foo(42.0f); } 239 240 struct 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 252 N n; 253 void use(N *obj) { obj->operator+(42); } 254 255 struct O { virtual A *f(); }; 256 struct P : O { virtual B *f(); }; 257 P p; 258 void use(O *obj) { obj->f(); } 259 void 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 266 struct 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 276 Q q; 277 void use(Q *obj) { obj->foo(42); } 278 279 // Inherited non-virtual overloads don't participate in the ordering. 280 struct 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 290 R r; 291 void use(R *obj) { obj->foo(42l); } 292 293 struct 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 301 S::S() {} 302