518 lines · cpp
1// RUN: %clang_cc1 -no-enable-noundef-analysis -emit-llvm -fno-rtti %s -std=c++11 -o - -mconstructor-aliases -triple=i386-pc-win32 -fno-rtti > %t2// RUN: FileCheck --check-prefixes CHECK,CLANG22 %s < %t3// vftables are emitted very late, so do another pass to try to keep the checks4// in source order.5// RUN: FileCheck --check-prefix DTORS %s < %t6// RUN: FileCheck --check-prefix DTORS2 %s < %t7// RUN: FileCheck --check-prefix DTORS3 %s < %t8// RUN: FileCheck --check-prefix DTORS4 %s < %t9//10// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti -std=c++11 | FileCheck --check-prefix DTORS-X64 %s11// RUN: %clang_cc1 -no-enable-noundef-analysis -emit-llvm -fno-rtti %s -std=c++11 -o - -mconstructor-aliases -triple=i386-pc-win32 -fclang-abi-compat=20 | FileCheck --check-prefixes CHECK,CLANG21 %s12 13namespace basic {14 15class A {16 public:17 A() { }18 ~A();19};20 21void no_constructor_destructor_infinite_recursion() {22 A a;23 24// CHECK: define linkonce_odr dso_local x86_thiscallcc ptr @"??0A@basic@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this) {{.*}} comdat {{.*}} {25// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca ptr, align 426// CHECK-NEXT: store ptr %this, ptr [[THIS_ADDR]], align 427// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load ptr, ptr [[THIS_ADDR]]28// CHECK-NEXT: ret ptr [[T1]]29// CHECK-NEXT: }30}31 32A::~A() {33// Make sure that the destructor doesn't call itself:34// CHECK: define {{.*}} @"??1A@basic@@QAE@XZ"35// CHECK-NOT: call void @"??1A@basic@@QAE@XZ"36// CHECK: ret37}38 39struct B {40 B();41};42 43// Tests that we can define constructors outside the class (PR12784).44B::B() {45 // CHECK: define dso_local x86_thiscallcc ptr @"??0B@basic@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this)46 // CHECK: ret47}48 49struct C {50 virtual ~C() {51// DTORS: define linkonce_odr dso_local x86_thiscallcc ptr @"??_GC@basic@@UAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {52// DTORS: store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 453// DTORS: store ptr %{{.*}}, ptr %[[RETVAL:retval]]54// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]55// DTORS: call x86_thiscallcc void @"??1C@basic@@UAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])56// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 157// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 058// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]59//60// DTORS: [[CALL_DELETE_LABEL]]61// DTORS-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[THIS]])62// DTORS-NEXT: br label %[[CONTINUE_LABEL]]63//64// DTORS: [[CONTINUE_LABEL]]65// DTORS-NEXT: %[[RET:.*]] = load ptr, ptr %[[RETVAL]]66// DTORS-NEXT: ret ptr %[[RET]]67 68// Check that we do the mangling correctly on x64.69// DTORS-X64: @"??_GC@basic@@UEAAPEAXI@Z"70 }71 virtual void foo();72};73 74// Emits the vftable in the output.75void C::foo() {}76 77void check_vftable_offset() {78 C c;79// The vftable pointer should point at the beginning of the vftable.80// CHECK: store ptr @"??_7C@basic@@6B@", ptr {{.*}}81}82 83void call_complete_dtor(C *obj_ptr) {84// CHECK: define dso_local void @"?call_complete_dtor@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)85 obj_ptr->~C();86// CHECK: %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 487// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]88// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 089// CHECK-NEXT: %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]90// CHECK-NEXT: call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 0)91// CHECK-NEXT: ret void92}93 94void call_deleting_dtor(C *obj_ptr) {95// CHECK: define dso_local void @"?call_deleting_dtor@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)96 delete obj_ptr;97// CHECK: %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 498// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]99 100// CHECK: [[DELETE_NOTNULL]]101// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]102// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0103// CHECK-NEXT: %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]104// CHECK-NEXT: call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 1)105// CHECK: ret void106}107 108void call_deleting_dtor_and_global_delete(C *obj_ptr) {109// CHECK: define dso_local void @"?call_deleting_dtor_and_global_delete@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)110 ::delete obj_ptr;111// CHECK: %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 4112// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]113 114// CHECK: [[DELETE_NOTNULL]]115// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]116// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0117// CHECK-NEXT: %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]118// CLANG22-NEXT: %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 5)119// CLANG21-NEXT: %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 0)120// CLANG21-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[CALL]])121// CHECK: ret void122}123 124struct D {125 static int foo();126 127 D() {128 static int ctor_static = foo();129 // CHECK that the static in the ctor gets mangled correctly:130 // CHECK: @"?ctor_static@?1???0D@basic@@QAE@XZ@4HA"131 }132 ~D() {133 static int dtor_static = foo();134 // CHECK that the static in the dtor gets mangled correctly:135 // CHECK: @"?dtor_static@?1???1D@basic@@QAE@XZ@4HA"136 }137};138 139void use_D() { D c; }140 141} // end namespace basic142 143namespace dtor_in_second_nvbase {144 145struct A {146 virtual void f(); // A needs vftable to be primary.147};148struct B {149 virtual ~B();150};151struct C : A, B {152 virtual ~C();153};154 155C::~C() {156// CHECK-LABEL: define dso_local x86_thiscallcc void @"??1C@dtor_in_second_nvbase@@UAE@XZ"(ptr{{[^,]*}} %this)157// No this adjustment!158// CHECK-NOT: getelementptr159// CHECK: load ptr, ptr %{{.*}}160// Now we this-adjust before calling ~B.161// CHECK: getelementptr inbounds i8, ptr %{{.*}}, i32 4162// CHECK: call x86_thiscallcc void @"??1B@dtor_in_second_nvbase@@UAE@XZ"(ptr{{[^,]*}} %{{.*}})163// CHECK: ret void164}165 166void foo() {167 C c;168}169// DTORS2-LABEL: define linkonce_odr dso_local x86_thiscallcc ptr @"??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"(ptr %this, i32 %should_call_delete)170// Do an adjustment from B* to C*.171// DTORS2: getelementptr i8, ptr %{{.*}}, i32 -4172// DTORS2: %[[CALL:.*]] = tail call x86_thiscallcc ptr @"??_GC@dtor_in_second_nvbase@@UAEPAXI@Z"173// DTORS2: ret ptr %[[CALL]]174}175 176namespace test2 {177// Just like dtor_in_second_nvbase, except put that in a vbase of a diamond.178 179// C's dtor is in the non-primary base.180struct A { virtual void f(); };181struct B { virtual ~B(); };182struct C : A, B { virtual ~C(); int c; };183 184// Diamond hierarchy, with C as the shared vbase.185struct D : virtual C { int d; };186struct E : virtual C { int e; };187struct F : D, E { ~F(); int f; };188 189F::~F() {190// CHECK-LABEL: define dso_local x86_thiscallcc void @"??1F@test2@@UAE@XZ"(ptr{{[^,]*}})191// Do an adjustment from C vbase subobject to F as though F was the192// complete type.193// CHECK: getelementptr inbounds i8, ptr %{{.*}}, i32 -20194// CHECK: store ptr195}196 197void foo() {198 F f;199}200// DTORS3-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"??_DF@test2@@QAEXXZ"({{.*}} {{.*}} comdat201// Do an adjustment from C* to F*.202// DTORS3: getelementptr i8, ptr %{{.*}}, i32 20203// DTORS3: call x86_thiscallcc void @"??1F@test2@@UAE@XZ"204// DTORS3: ret void205 206}207 208namespace constructors {209 210struct A {211 A() {}212};213 214struct B : A {215 B();216 ~B();217};218 219B::B() {220 // CHECK: define dso_local x86_thiscallcc ptr @"??0B@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this)221 // CHECK: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})222 // CHECK: ret223}224 225struct C : virtual A {226 C();227};228 229C::C() {230 // CHECK: define dso_local x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived)231 // TODO: make sure this works in the Release build too;232 // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4233 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]234 // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0235 // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]236 //237 // CHECK: [[INIT_VBASES]]238 // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0239 // CHECK-NEXT: store ptr @"??_8C@constructors@@7B@", ptr %[[vbptr_off]]240 // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4241 // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})242 // CHECK-NEXT: br label %[[SKIP_VBASES]]243 //244 // CHECK: [[SKIP_VBASES]]245 // Class C does not define or override methods, so shouldn't change the vfptr.246 // CHECK-NOT: @"??_7C@constructors@@6B@"247 // CHECK: ret248}249 250void create_C() {251 C c;252 // CHECK: define dso_local void @"?create_C@constructors@@YAXXZ"()253 // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %c, i32 1)254 // CHECK: ret255}256 257struct D : C {258 D();259};260 261D::D() {262 // CHECK: define dso_local x86_thiscallcc ptr @"??0D@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived) unnamed_addr263 // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4264 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]265 // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0266 // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]267 //268 // CHECK: [[INIT_VBASES]]269 // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0270 // CHECK-NEXT: store ptr @"??_8D@constructors@@7B@", ptr %[[vbptr_off]]271 // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4272 // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})273 // CHECK-NEXT: br label %[[SKIP_VBASES]]274 //275 // CHECK: [[SKIP_VBASES]]276 // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}, i32 0)277 // CHECK: ret278}279 280struct E : virtual C {281 E();282};283 284E::E() {285 // CHECK: define dso_local x86_thiscallcc ptr @"??0E@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived) unnamed_addr286 // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4287 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]288 // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0289 // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]290 //291 // CHECK: [[INIT_VBASES]]292 // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0293 // CHECK-NEXT: store ptr @"??_8E@constructors@@7B01@@", ptr %[[offs]]294 // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 4295 // CHECK-NEXT: store ptr @"??_8E@constructors@@7BC@1@@", ptr %[[offs]]296 // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4297 // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})298 // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}, i32 0)299 // CHECK-NEXT: br label %[[SKIP_VBASES]]300 //301 // CHECK: [[SKIP_VBASES]]302 // CHECK: ret303}304 305// PR16735 - even abstract classes should have a constructor emitted.306struct F {307 F();308 virtual void f() = 0;309};310 311F::F() {}312// CHECK: define dso_local x86_thiscallcc ptr @"??0F@constructors@@QAE@XZ"313 314} // end namespace constructors315 316namespace dtors {317 318struct A {319 ~A();320};321 322void call_nv_complete(A *a) {323 a->~A();324// CHECK: define dso_local void @"?call_nv_complete@dtors@@YAXPAUA@1@@Z"325// CHECK: call x86_thiscallcc void @"??1A@dtors@@QAE@XZ"326// CHECK: ret327}328 329// CHECK: declare dso_local x86_thiscallcc void @"??1A@dtors@@QAE@XZ"330 331// Now try some virtual bases, where we need the complete dtor.332 333struct B : virtual A { ~B(); };334struct C : virtual A { ~C(); };335struct D : B, C { ~D(); };336 337void call_vbase_complete(D *d) {338 d->~D();339// CHECK: define dso_local void @"?call_vbase_complete@dtors@@YAXPAUD@1@@Z"340// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})341// CHECK: ret342}343 344// The complete dtor should call the base dtors for D and the vbase A (once).345// CHECK: define linkonce_odr dso_local x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"({{.*}}) {{.*}} comdat346// CHECK-NOT: call347// CHECK: call x86_thiscallcc void @"??1D@dtors@@QAE@XZ"348// CHECK-NOT: call349// CHECK: call x86_thiscallcc void @"??1A@dtors@@QAE@XZ"350// CHECK-NOT: call351// CHECK: ret352 353void destroy_d_complete() {354 D d;355// CHECK: define dso_local void @"?destroy_d_complete@dtors@@YAXXZ"356// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})357// CHECK: ret358}359 360// FIXME: Clang manually inlines the deletion, so we don't get a call to the361// deleting dtor (_G). The only way to call deleting dtors currently is through362// a vftable.363void call_nv_deleting_dtor(D *d) {364 delete d;365// CHECK: define dso_local void @"?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z"366// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})367// CHECK: call void @"??3@YAXPAX@Z"368// CHECK: ret369}370 371}372 373namespace test1 {374struct A { };375struct B : virtual A {376 B(int *a);377 B(const char *a, ...);378 __cdecl B(short *a);379};380B::B(int *a) {}381B::B(const char *a, ...) {}382B::B(short *a) {}383// CHECK: define dso_local x86_thiscallcc ptr @"??0B@test1@@QAE@PAH@Z"384// CHECK: (ptr {{[^,]*}} returned {{[^,]*}} %this, ptr %a, i32 %is_most_derived)385// CHECK: define dso_local ptr @"??0B@test1@@QAA@PBDZZ"386// CHECK: (ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived, ptr %a, ...)387// CHECK: define dso_local x86_thiscallcc ptr @"??0B@test1@@QAE@PAF@Z"388// CHECK: (ptr {{[^,]*}} returned {{[^,]*}} %this, ptr %a, i32 %is_most_derived)389 390void construct_b() {391 int a;392 B b1(&a);393 B b2("%d %d", 1, 2);394}395// CHECK-LABEL: define dso_local void @"?construct_b@test1@@YAXXZ"()396// CHECK: call x86_thiscallcc ptr @"??0B@test1@@QAE@PAH@Z"397// CHECK: (ptr {{.*}}, ptr {{.*}}, i32 1)398// CHECK: call ptr (ptr, i32, ptr, ...) @"??0B@test1@@QAA@PBDZZ"399// CHECK: (ptr {{.*}}, i32 1, ptr {{.*}}, i32 1, i32 2)400}401 402namespace implicit_copy_vtable {403// This was a crash that only reproduced in ABIs without key functions.404struct ImplicitCopy {405 // implicit copy ctor406 virtual ~ImplicitCopy();407};408void CreateCopy(ImplicitCopy *a) {409 new ImplicitCopy(*a);410}411// CHECK: store {{.*}} @"??_7ImplicitCopy@implicit_copy_vtable@@6B@"412 413struct MoveOnly {414 MoveOnly(MoveOnly &&o) = default;415 virtual ~MoveOnly();416};417MoveOnly &&f();418void g() { new MoveOnly(f()); }419// CHECK: store {{.*}} @"??_7MoveOnly@implicit_copy_vtable@@6B@"420}421 422namespace delegating_ctor {423struct Y {};424struct X : virtual Y {425 X(int);426 X();427};428X::X(int) : X() {}429}430// CHECK: define dso_local x86_thiscallcc ptr @"??0X@delegating_ctor@@QAE@H@Z"(431// CHECK: %[[is_most_derived_addr:.*]] = alloca i32, align 4432// CHECK: store i32 %is_most_derived, ptr %[[is_most_derived_addr]]433// CHECK: %[[is_most_derived:.*]] = load i32, ptr %[[is_most_derived_addr]]434// CHECK: call x86_thiscallcc ptr @"??0X@delegating_ctor@@QAE@XZ"({{.*}} i32 %[[is_most_derived]])435 436// Dtor thunks for classes in anonymous namespaces should be internal, not437// linkonce_odr.438namespace {439struct A {440 virtual ~A() { }441};442}443void *getA() {444 return (void*)new A();445}446// CHECK: define internal x86_thiscallcc ptr @"??_GA@?A0x{{[^@]*}}@@UAEPAXI@Z"447// CHECK: (ptr {{[^,]*}} %this, i32 %should_call_delete)448// CHECK: define internal x86_thiscallcc void @"??1A@?A0x{{[^@]*}}@@UAE@XZ"449// CHECK: (ptr {{[^,]*}} %this)450 451// Check that we correctly transform __stdcall to __thiscall for ctors and452// dtors.453class G {454 public:455 __stdcall G() {};456// DTORS4: define linkonce_odr dso_local x86_thiscallcc ptr @"??0G@@QAE@XZ"457 __stdcall ~G() {};458// DTORS4: define linkonce_odr dso_local x86_thiscallcc void @"??1G@@QAE@XZ"459};460 461extern void testG() {462 G g;463}464 465namespace operator_delete {466 467class H { virtual ~H();468 void operator delete(void *);469};470H::~H() { }471 472void checkH() {473 new H();474}475// DTORS: define linkonce_odr dso_local x86_thiscallcc ptr @"??_GH@operator_delete@@EAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {476// DTORS: store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4477// DTORS: store ptr %{{.*}}, ptr %[[RETVAL:retval]]478// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]479// DTORS: call x86_thiscallcc void @"??1H@operator_delete@@EAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])480// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1481// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0482// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]483//484// DTORS: [[CALL_DELETE_LABEL]]485// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 4486// DTORS-NEXT: %[[CONDITION1:[0-9]+]] = icmp eq i32 %[[AND]], 0487// DTORS-NEXT: br i1 %[[CONDITION1]], label %[[CALL_CLASS_DELETE:[0-9a-z._]+]], label %[[CALL_GLOB_DELETE:[0-9a-z._]+]]488//489// DTORS: [[CALL_GLOB_DELETE]]490// DTORS-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[THIS]])491// DTORS-NEXT: br label %[[CONTINUE_LABEL]]492//493// DTORS: [[CALL_CLASS_DELETE]]494// DTORS-NEXT: call void @"??3H@operator_delete@@CAXPAX@Z"(ptr %[[THIS]])495// DTORS-NEXT: br label %[[CONTINUE_LABEL]]496//497// DTORS: [[CONTINUE_LABEL]]498// DTORS-NEXT: %[[RET:.*]] = load ptr, ptr %[[RETVAL]]499// DTORS-NEXT: ret ptr %[[RET]]500 501// CLANG21: define linkonce_odr dso_local x86_thiscallcc ptr @"??_GH@operator_delete@@EAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {502// CLANG21: store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4503// CLANG21: store ptr %{{.*}}, ptr %[[RETVAL:retval]]504// CLANG21: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]505// CLANG21: call x86_thiscallcc void @"??1H@operator_delete@@EAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])506// CLANG21-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1507// CLANG21-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0508// CLANG21-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]509//510// CLANG21: [[CALL_DELETE_LABEL]]511// CLANG21-NEXT: call void @"??3H@operator_delete@@CAXPAX@Z"(ptr %[[THIS:[0-9a-z]+]])512// CLANG21-NEXT: br label %[[CONTINUE_LABEL]]513//514// CLANG21: [[CONTINUE_LABEL]]515// CLANG21-NEXT: %[[RET:.*]] = load ptr, ptr %[[RETVAL]]516// CLANG21-NEXT: ret ptr %[[RET]]517}518