1 // RUN: %clang_cc1 %s -fno-rtti -std=c++11 -Wno-inaccessible-base -triple=i386-pc-win32 -emit-llvm -o %t 2 // RUN: FileCheck %s < %t 3 // RUN: FileCheck --check-prefix=CHECK2 %s < %t 4 5 // For now, just make sure x86_64 doesn't crash. 6 // RUN: %clang_cc1 %s -fno-rtti -std=c++11 -Wno-inaccessible-base -triple=x86_64-pc-win32 -emit-llvm -o %t 7 8 struct VBase { 9 virtual ~VBase(); 10 virtual void foo(); 11 virtual void bar(); 12 int field; 13 }; 14 15 struct B : virtual VBase { 16 B(); 17 virtual ~B(); 18 virtual void foo(); 19 virtual void bar(); 20 }; 21 22 B::B() { 23 // CHECK-LABEL: define dso_local x86_thiscallcc noundef ptr @"??0B@@QAE@XZ" 24 // CHECK: %[[THIS:.*]] = load ptr, ptr 25 // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] 26 27 // Don't check the INIT_VBASES case as it's covered by the ctor tests. 28 29 // CHECK: %[[SKIP_VBASES]] 30 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 0 31 // ... 32 // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 %{{.*}} 33 // CHECK: store ptr @"??_7B@@6B@", ptr %[[VFPTR_i8]] 34 35 // Initialize vtorDisp: 36 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 0 37 // ... 38 // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}} 39 // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8 40 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 %[[VBASE_OFFSET]] 41 // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8, ptr %[[VBASE_i8]], i32 -4 42 // CHECK: store i32 %[[VTORDISP_VAL]], ptr %[[VTORDISP_i8]] 43 44 // CHECK: ret 45 } 46 47 B::~B() { 48 // CHECK-LABEL: define dso_local x86_thiscallcc void @"??1B@@UAE@XZ" 49 // Store initial this: 50 // CHECK: %[[THIS_ADDR:.*]] = alloca ptr 51 // CHECK: store ptr %{{.*}}, ptr %[[THIS_ADDR]], align 4 52 // Reload and adjust the this parameter: 53 // CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]] 54 // CHECK: %[[THIS_ADJ_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -8 55 56 // Restore the vfptr that could have been changed by a subclass. 57 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 0 58 // ... 59 // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 %{{.*}} 60 // CHECK: store ptr @"??_7B@@6B@", ptr %[[VFPTR_i8]] 61 62 // Initialize vtorDisp: 63 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 0 64 // ... 65 // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}} 66 // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8 67 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 %[[VBASE_OFFSET]] 68 // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8, ptr %[[VBASE_i8]], i32 -4 69 // CHECK: store i32 %[[VTORDISP_VAL]], ptr %[[VTORDISP_i8]] 70 71 foo(); // Avoid the "trivial destructor" optimization. 72 73 // CHECK: ret 74 75 // CHECK2-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"??_DB@@QAEXXZ"(ptr 76 // CHECK2: %[[THIS:.*]] = load ptr, ptr {{.*}} 77 // CHECK2: %[[B_i8:.*]] = getelementptr i8, ptr %[[THIS]], i32 8 78 // CHECK2: call x86_thiscallcc void @"??1B@@UAE@XZ"(ptr{{[^,]*}} %[[B_i8]]) 79 // CHECK2: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 8 80 // CHECK2: call x86_thiscallcc void @"??1VBase@@UAE@XZ"(ptr {{[^,]*}} %[[VBASE_i8]]) 81 // CHECK2: ret 82 83 // CHECK2-LABEL: define linkonce_odr dso_local x86_thiscallcc noundef ptr @"??_GB@@UAEPAXI@Z" 84 // CHECK2: store ptr %{{.*}}, ptr %[[THIS_ADDR:.*]], align 4 85 // CHECK2: %[[THIS_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_PARAM_i8:.*]], i32 -8 86 // CHECK2: call x86_thiscallcc void @"??_DB@@QAEXXZ"(ptr {{[^,]*}} %[[THIS_i8]]) 87 // ... 88 // CHECK2: ret 89 } 90 91 void B::foo() { 92 // CHECK-LABEL: define dso_local x86_thiscallcc void @"?foo@B@@UAEXXZ"(ptr 93 // 94 // B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we 95 // need to adjust 'this' before use. 96 // 97 // Coerce this to correct type: 98 // CHECK: %[[THIS_ADDR:.*]] = alloca ptr 99 // 100 // Store initial this: 101 // CHECK: store ptr {{.*}}, ptr %[[THIS_ADDR]], align 4 102 // 103 // Reload and adjust the this parameter: 104 // CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]] 105 // CHECK: %[[THIS_ADJ_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -8 106 107 field = 42; 108 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 0 109 // CHECK: %[[VBTABLE:.*]] = load ptr, ptr %[[VBPTR]] 110 // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, ptr %[[VBTABLE]], i32 1 111 // CHECK: %[[VBOFFSET32:.*]] = load i32, ptr %[[VBENTRY]] 112 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] 113 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 %[[VBOFFSET]] 114 // CHECK: %[[FIELD:.*]] = getelementptr inbounds nuw %struct.VBase, ptr %[[VBASE_i8]], i32 0, i32 1 115 // CHECK: store i32 42, ptr %[[FIELD]], align 4 116 // 117 // CHECK: ret void 118 } 119 120 void call_vbase_bar(B *obj) { 121 // CHECK-LABEL: define dso_local void @"?call_vbase_bar@@YAXPAUB@@@Z"(ptr noundef %obj) 122 // CHECK: %[[OBJ:.*]] = load ptr 123 124 obj->bar(); 125 // When calling a vbase's virtual method, one needs to adjust 'this' 126 // at the caller site. 127 // 128 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 0 129 // CHECK: %[[VBTABLE:.*]] = load ptr, ptr %[[VBPTR]] 130 // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, ptr %[[VBTABLE]], i32 1 131 // CHECK: %[[VBOFFSET32:.*]] = load i32, ptr %[[VBENTRY]] 132 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] 133 // CHECK: %[[VBASE:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 %[[VBOFFSET]] 134 // 135 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 0 136 // CHECK: %[[VBTABLE:.*]] = load ptr, ptr %[[VBPTR]] 137 // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, ptr %[[VBTABLE]], i32 1 138 // CHECK: %[[VBOFFSET32:.*]] = load i32, ptr %[[VBENTRY]] 139 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] 140 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 %[[VBOFFSET]] 141 // CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[VBASE_i8]] 142 // CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 2 143 // CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]] 144 // 145 // CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr noundef %[[VBASE]]) 146 // 147 // CHECK: ret void 148 } 149 150 void delete_B(B *obj) { 151 // CHECK-LABEL: define dso_local void @"?delete_B@@YAXPAUB@@@Z"(ptr noundef %obj) 152 // CHECK: %[[OBJ:.*]] = load ptr 153 154 delete obj; 155 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 0 156 // CHECK: %[[VBTABLE:.*]] = load ptr, ptr %[[VBPTR]] 157 // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, ptr %[[VBTABLE]], i32 1 158 // CHECK: %[[VBOFFSET32:.*]] = load i32, ptr %[[VBENTRY]] 159 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] 160 // CHECK: %[[VBASE:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 %[[VBOFFSET]] 161 // 162 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 0 163 // CHECK: %[[VBTABLE:.*]] = load ptr, ptr %[[VBPTR]] 164 // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, ptr %[[VBTABLE]], i32 1 165 // CHECK: %[[VBOFFSET32:.*]] = load i32, ptr %[[VBENTRY]] 166 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] 167 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 %[[VBOFFSET]] 168 // CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[VBASE_i8]] 169 // CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0 170 // CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]] 171 // 172 // CHECK: call x86_thiscallcc noundef ptr %[[VFUN_VALUE]](ptr {{[^,]*}} %[[VBASE]], i32 noundef 1) 173 // CHECK: ret void 174 } 175 176 void call_complete_dtor() { 177 // CHECK-LABEL: define dso_local void @"?call_complete_dtor@@YAXXZ" 178 B b; 179 // CHECK: call x86_thiscallcc noundef ptr @"??0B@@QAE@XZ"(ptr {{[^,]*}} %[[B:.*]], i32 noundef 1) 180 // CHECK-NOT: getelementptr 181 // CHECK: call x86_thiscallcc void @"??_DB@@QAEXXZ"(ptr {{[^,]*}} %[[B]]) 182 // CHECK: ret 183 } 184 185 struct C : B { 186 C(); 187 // has an implicit vdtor. 188 }; 189 190 // Used to crash on an assertion. 191 C::C() { 192 // CHECK-LABEL: define dso_local x86_thiscallcc noundef ptr @"??0C@@QAE@XZ" 193 } 194 195 namespace multiple_vbases { 196 struct A { 197 virtual void a(); 198 }; 199 200 struct B { 201 virtual void b(); 202 }; 203 204 struct C { 205 virtual void c(); 206 }; 207 208 struct D : virtual A, virtual B, virtual C { 209 virtual void a(); 210 virtual void b(); 211 virtual void c(); 212 D(); 213 }; 214 215 D::D() { 216 // CHECK-LABEL: define dso_local x86_thiscallcc noundef ptr @"??0D@multiple_vbases@@QAE@XZ" 217 // Just make sure we emit 3 vtordisps after initializing vfptrs. 218 // CHECK: store ptr @"??_7D@multiple_vbases@@6BA@1@@", ptr %{{.*}} 219 // CHECK: store ptr @"??_7D@multiple_vbases@@6BB@1@@", ptr %{{.*}} 220 // CHECK: store ptr @"??_7D@multiple_vbases@@6BC@1@@", ptr %{{.*}} 221 // ... 222 // CHECK: store i32 %{{.*}}, ptr %{{.*}} 223 // CHECK: store i32 %{{.*}}, ptr %{{.*}} 224 // CHECK: store i32 %{{.*}}, ptr %{{.*}} 225 // CHECK: ret 226 } 227 } 228 229 namespace diamond { 230 struct A { 231 A(); 232 virtual ~A(); 233 }; 234 235 struct B : virtual A { 236 B(); 237 ~B(); 238 }; 239 240 struct C : virtual A { 241 C(); 242 ~C(); 243 int c1, c2, c3; 244 }; 245 246 struct Z { 247 int z; 248 }; 249 250 struct D : virtual Z, B, C { 251 D(); 252 ~D(); 253 } d; 254 255 D::~D() { 256 // CHECK-LABEL: define dso_local x86_thiscallcc void @"??1D@diamond@@UAE@XZ"(ptr{{.*}}) 257 // Store initial this: 258 // CHECK: %[[THIS_ADDR:.*]] = alloca ptr 259 // CHECK: store ptr %{{.*}}, ptr %[[THIS_ADDR]], align 4 260 // 261 // Reload and adjust the this parameter: 262 // CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]] 263 // CHECK: %[[THIS_ADJ_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -24 264 // 265 // CHECK: %[[C_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_ADJ_i8]], i32 4 266 // CHECK: %[[ARG:.*]] = getelementptr i8, ptr %{{.*}}, i32 16 267 // CHECK: call x86_thiscallcc void @"??1C@diamond@@UAE@XZ"(ptr{{[^,]*}} %[[ARG]]) 268 269 // CHECK: %[[ARG:.*]] = getelementptr i8, ptr %[[THIS_ADJ_i8]], i32 4 270 // CHECK: call x86_thiscallcc void @"??1B@diamond@@UAE@XZ"(ptr{{[^,]*}} %[[ARG]]) 271 // CHECK: ret void 272 } 273 274 } 275 276 namespace test2 { 277 struct A { A(); }; 278 struct B : virtual A { B() {} }; 279 struct C : B, A { C() {} }; 280 281 // PR18435: Order mattered here. We were generating code for the delegating 282 // call to B() from C(). 283 void callC() { C x; } 284 285 // CHECK-LABEL: define linkonce_odr dso_local x86_thiscallcc noundef ptr @"??0C@test2@@QAE@XZ" 286 // CHECK: (ptr {{[^,]*}} returned align 4 dereferenceable(8) %this, i32 noundef %is_most_derived) 287 // CHECK: br i1 288 // Virtual bases 289 // CHECK: call x86_thiscallcc noundef ptr @"??0A@test2@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}) 290 // CHECK: br label 291 // Non-virtual bases 292 // CHECK: call x86_thiscallcc noundef ptr @"??0B@test2@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}, i32 noundef 0) 293 // CHECK: call x86_thiscallcc noundef ptr @"??0A@test2@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}) 294 // CHECK: ret 295 296 // CHECK2-LABEL: define linkonce_odr dso_local x86_thiscallcc noundef ptr @"??0B@test2@@QAE@XZ" 297 // CHECK2: (ptr {{[^,]*}} returned align 4 dereferenceable(4) %this, i32 noundef %is_most_derived) 298 // CHECK2: call x86_thiscallcc noundef ptr @"??0A@test2@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}) 299 // CHECK2: ret 300 301 } 302 303 namespace test3 { 304 // PR19104: A non-virtual call of a virtual method doesn't use vftable thunks, 305 // so requires only static adjustment which is different to the one used 306 // for virtual calls. 307 struct A { 308 virtual void foo(); 309 }; 310 311 struct B : virtual A { 312 virtual void bar(); 313 }; 314 315 struct C : virtual A { 316 virtual void foo(); 317 }; 318 319 struct D : B, C { 320 virtual void bar(); 321 int field; // Laid out between C and A subobjects in D. 322 }; 323 324 void D::bar() { 325 // CHECK-LABEL: define dso_local x86_thiscallcc void @"?bar@D@test3@@UAEXXZ"(ptr {{[^,]*}} %this) 326 327 C::foo(); 328 // Shouldn't need any vbtable lookups. All we have to do is adjust to C*, 329 // then compensate for the adjustment performed in the C::foo() prologue. 330 // CHECK: %[[C_i8:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 8 331 // CHECK: %[[ARG:.*]] = getelementptr i8, ptr %[[C_i8]], i32 4 332 // CHECK: call x86_thiscallcc void @"?foo@C@test3@@UAEXXZ"(ptr noundef %[[ARG]]) 333 // CHECK: ret 334 } 335 } 336 337 namespace test4{ 338 // PR19172: We used to merge method vftable locations wrong. 339 340 struct A { 341 virtual ~A() {} 342 }; 343 344 struct B { 345 virtual ~B() {} 346 }; 347 348 struct C : virtual A, B { 349 virtual ~C(); 350 }; 351 352 void foo(void*); 353 354 C::~C() { 355 // CHECK-LABEL: define dso_local x86_thiscallcc void @"??1C@test4@@UAE@XZ"(ptr {{[^,]*}} %this) 356 357 // In this case "this" points to the most derived class, so no GEPs needed. 358 // CHECK-NOT: getelementptr 359 // CHECK: store ptr @"??_7C@test4@@6BB@1@@", ptr %{{.*}} 360 361 foo(this); 362 // CHECK: ret 363 } 364 365 void destroy(C *obj) { 366 // CHECK-LABEL: define dso_local void @"?destroy@test4@@YAXPAUC@1@@Z"(ptr noundef %obj) 367 368 delete obj; 369 // CHECK: %[[OBJ:.*]] = load ptr, ptr 370 // CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[OBJ]] 371 // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0 372 // CHECK: %[[VFUN:.*]] = load ptr, ptr %[[VFTENTRY]] 373 // CHECK: call x86_thiscallcc noundef ptr %[[VFUN]](ptr {{[^,]*}} %[[OBJ]], i32 noundef 1) 374 // CHECK: ret 375 } 376 377 struct D { 378 virtual void d(); 379 }; 380 381 // The first non-virtual base doesn't have a vdtor, 382 // but "this adjustment" is not needed. 383 struct E : D, B, virtual A { 384 virtual ~E(); 385 }; 386 387 E::~E() { 388 // CHECK-LABEL: define dso_local x86_thiscallcc void @"??1E@test4@@UAE@XZ"(ptr{{[^,]*}} %this) 389 390 // In this case "this" points to the most derived class, so no GEPs needed. 391 // CHECK-NOT: getelementptr 392 // CHECK: store ptr @"??_7E@test4@@6BD@1@@", ptr %{{.*}} 393 foo(this); 394 } 395 396 void destroy(E *obj) { 397 // CHECK-LABEL: define dso_local void @"?destroy@test4@@YAXPAUE@1@@Z"(ptr noundef %obj) 398 399 // CHECK-NOT: getelementptr 400 // CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i32 4 401 // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8, ptr %[[OBJ:.*]], i32 4 402 // CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[B_i8]] 403 // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0 404 // CHECK: %[[VFUN:.*]] = load ptr, ptr %[[VFTENTRY]] 405 // CHECK: call x86_thiscallcc noundef ptr %[[VFUN]](ptr{{[^,]*}} %[[THIS_i8]], i32 noundef 1) 406 delete obj; 407 } 408 409 } 410 411 namespace test5 { 412 // PR25370: Don't zero-initialize vbptrs in virtual bases. 413 struct A { 414 virtual void f(); 415 }; 416 417 struct B : virtual A { 418 int Field; 419 }; 420 421 struct C : B { 422 C(); 423 }; 424 425 C::C() : B() {} 426 // CHECK-LABEL: define dso_local x86_thiscallcc noundef ptr @"??0C@test5@@QAE@XZ"( 427 // CHECK: %[[THIS:.*]] = load ptr, ptr 428 // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] 429 430 // CHECK: %[[SKIP_VBASES]] 431 // CHECK: %[[FIELD:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 4 432 // CHECK: call void @llvm.memset.p0.i32(ptr align 4 %[[FIELD]], i8 0, i32 4, i1 false) 433 } 434 435 namespace pr27621 { 436 // Devirtualization through a static_cast used to make us compute the 'this' 437 // adjustment for B::g instead of C::g. When we directly call C::g, 'this' is a 438 // B*, and the prologue of C::g will adjust it to a C*. 439 struct A { virtual void f(); }; 440 struct B { virtual void g(); }; 441 struct C final : A, B { 442 virtual void h(); 443 void g() override; 444 }; 445 void callit(C *p) { 446 static_cast<B*>(p)->g(); 447 } 448 // CHECK-LABEL: define dso_local void @"?callit@pr27621@@YAXPAUC@1@@Z"(ptr noundef %{{.*}}) 449 // CHECK: %[[B_i8:.*]] = getelementptr i8, ptr %{{.*}}, i32 4 450 // CHECK: call x86_thiscallcc void @"?g@C@pr27621@@UAEXXZ"(ptr noundef %[[B_i8]]) 451 } 452 453 namespace test6 { 454 class A {}; 455 class B : virtual A {}; 456 class C : virtual B { 457 virtual void m_fn1(); 458 float field; 459 }; 460 class D : C { 461 D(); 462 }; 463 D::D() : C() {} 464 // CHECK-LABEL: define dso_local x86_thiscallcc noundef ptr @"??0D@test6@@AAE@XZ"( 465 // CHECK: %[[THIS:.*]] = load ptr, ptr 466 // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] 467 468 // CHECK: %[[SKIP_VBASES]] 469 // CHECK: %[[FIELD:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 8 470 // CHECK: call void @llvm.memset.p0.i32(ptr align 4 %[[FIELD]], i8 0, i32 4, i1 false) 471 } 472 473 namespace pr36921 { 474 struct A { 475 virtual ~A() {} 476 }; 477 struct B { 478 virtual ~B() {} 479 }; 480 struct C : virtual B {}; 481 struct D : virtual A, C {}; 482 D d; 483 // CHECK2-LABEL: define linkonce_odr dso_local x86_thiscallcc noundef ptr @"??_GD@pr36921@@UAEPAXI@Z"( 484 // CHECK2: %[[THIS_RELOAD:.*]] = load ptr, ptr 485 // CHECK2: %[[THIS_ADJ_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -4 486 } 487 488 namespace issue_60465 { 489 // We used to assume the first argument to all destructors was the derived type 490 // even when there was a 'this' adjustment. 491 struct A { 492 virtual ~A(); 493 }; 494 495 struct alignas(2 * sizeof(void *)) B : virtual A { 496 ~B(); 497 void *x, *y; 498 }; 499 500 B::~B() { 501 // The 'this' parameter should not have a type of ptr and 502 // must not have 'align 8', since at least B's copy of A is only 'align 4'. 503 // CHECK-LABEL: define dso_local x86_thiscallcc void @"??1B@issue_60465@@UAE@XZ"(ptr noundef %this) 504 // CHECK: %[[THIS_ADJ_i8:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 -12 505 // CHECK: %[[X:.*]] = getelementptr inbounds nuw %"struct.issue_60465::B", ptr %[[THIS_ADJ_i8]], i32 0, i32 1 506 // CHECK: store ptr null, ptr %[[X]], align 4 507 // CHECK: %[[Y:.*]] = getelementptr inbounds nuw %"struct.issue_60465::B", ptr %[[THIS_ADJ_i8]], i32 0, i32 2 508 // CHECK: store ptr null, ptr %[[Y]], align 8 509 x = nullptr; 510 y = nullptr; 511 } 512 } 513