Skip to content

Commit 1b0b624

Browse files
committed
[win][clang] Align scalar deleting destructors with MSABI
While working on vector deleting destructors support (GH19772), I noticed that MSVC produces different code in scalar deleting destructor body depending on whether class defined its own operator delete. In MSABI deleting destructors accept an additional implicit flag parameter allowing some sort of flexibility. The mismatch I noticed is that whenever a global operator delete is called, i.e. ::delete, in the code produced by MSVC the implicit flag argument has a value that makes the 3rd bit set, i.e. "5" for scalar deleting destructors "7" for vector deleting destructors. Prior to this patch, clang handled ::delete via calling global operator delete direct after the destructor call and not calling class operator delete in scalar deleting destructor body by passing "0" as implicit flag argument value. This is fine until there is an attempt to link binaries compiled with clang with binaries compiled with MSVC. The problem is that in binaries produced by MSVC the callsite of the destructor won't call global operator delete because it is assumed that the destructor will do that and a destructor body generated by clang will never do. This patch removes call to global operator delete from the callsite and add additional check of the 3rd bit of the implicit parameter inside of scalar deleting destructor body.
1 parent 386f2ca commit 1b0b624

File tree

8 files changed

+202
-44
lines changed

8 files changed

+202
-44
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
28552855
// FIXME: Don't allocate storage for these except in the first declaration
28562856
// of a virtual destructor.
28572857
FunctionDecl *OperatorDelete = nullptr;
2858+
FunctionDecl *OperatorGlobalDelete = nullptr;
28582859
Expr *OperatorDeleteThisArg = nullptr;
28592860

28602861
CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
@@ -2885,6 +2886,16 @@ class CXXDestructorDecl : public CXXMethodDecl {
28852886
return getCanonicalDecl()->OperatorDelete;
28862887
}
28872888

2889+
const FunctionDecl *getOperatorGlobalDelete() const {
2890+
return getCanonicalDecl()->OperatorGlobalDelete;
2891+
}
2892+
2893+
void setOperatorGlobalDelete(FunctionDecl *OD) {
2894+
auto *First = cast<CXXDestructorDecl>(getFirstDecl());
2895+
if (OD && !First->OperatorGlobalDelete)
2896+
First->OperatorGlobalDelete = OD;
2897+
}
2898+
28882899
Expr *getOperatorDeleteThisArg() const {
28892900
return getCanonicalDecl()->OperatorDeleteThisArg;
28902901
}

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8495,10 +8495,12 @@ class Sema final : public SemaBase {
84958495
bool Diagnose = true);
84968496
FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc,
84978497
ImplicitDeallocationParameters,
8498-
DeclarationName Name);
8499-
FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc,
8500-
CXXRecordDecl *RD,
8501-
bool Diagnose = true);
8498+
DeclarationName Name,
8499+
bool Diagnose = true);
8500+
FunctionDecl *
8501+
FindDeallocationFunctionForDestructor(SourceLocation StartLoc,
8502+
CXXRecordDecl *RD, bool Diagnose = true,
8503+
bool LookForGlobal = false);
85028504

85038505
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
85048506
/// @code ::delete ptr; @endcode

clang/lib/CodeGen/CGClass.cpp

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,25 +1589,74 @@ namespace {
15891589
void EmitConditionalDtorDeleteCall(CodeGenFunction &CGF,
15901590
llvm::Value *ShouldDeleteCondition,
15911591
bool ReturnAfterDelete) {
1592+
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
1593+
const CXXRecordDecl *ClassDecl = Dtor->getParent();
1594+
const FunctionDecl *OD = Dtor->getOperatorDelete();
1595+
assert(OD->isDestroyingOperatorDelete() == ReturnAfterDelete &&
1596+
"unexpected value for ReturnAfterDelete");
1597+
auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType());
1598+
if (OD->isDestroyingOperatorDelete()) {
1599+
llvm::BasicBlock *CallDtor = CGF.createBasicBlock("dtor.call_dtor");
1600+
llvm::BasicBlock *DontCallDtor = CGF.createBasicBlock("dtor.entry_cont");
1601+
// Third bit set signals that global operator delete is called. That means
1602+
// despite class having destroying operator delete which is responsible
1603+
// for calling dtor, we need to call dtor because global operator delete
1604+
// won't do that.
1605+
llvm::Value *Check3rdBit = CGF.Builder.CreateAnd(
1606+
ShouldDeleteCondition, llvm::ConstantInt::get(CondTy, 4));
1607+
llvm::Value *ShouldCallDtor = CGF.Builder.CreateIsNull(Check3rdBit);
1608+
CGF.Builder.CreateCondBr(ShouldCallDtor, DontCallDtor, CallDtor);
1609+
CGF.EmitBlock(CallDtor);
1610+
QualType ThisTy = Dtor->getFunctionObjectParameterType();
1611+
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
1612+
/*Delegating=*/false, CGF.LoadCXXThisAddress(),
1613+
ThisTy);
1614+
CGF.Builder.CreateBr(DontCallDtor);
1615+
CGF.EmitBlock(DontCallDtor);
1616+
}
15921617
llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
15931618
llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
1594-
llvm::Value *ShouldCallDelete
1595-
= CGF.Builder.CreateIsNull(ShouldDeleteCondition);
1619+
// First bit set signals that operator delete must be called.
1620+
llvm::Value *Check1stBit = CGF.Builder.CreateAnd(
1621+
ShouldDeleteCondition, llvm::ConstantInt::get(CondTy, 1));
1622+
llvm::Value *ShouldCallDelete = CGF.Builder.CreateIsNull(Check1stBit);
15961623
CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
15971624

15981625
CGF.EmitBlock(callDeleteBB);
1599-
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
1600-
const CXXRecordDecl *ClassDecl = Dtor->getParent();
1601-
CGF.EmitDeleteCall(Dtor->getOperatorDelete(),
1602-
LoadThisForDtorDelete(CGF, Dtor),
1603-
CGF.getContext().getTagDeclType(ClassDecl));
1604-
assert(Dtor->getOperatorDelete()->isDestroyingOperatorDelete() ==
1605-
ReturnAfterDelete &&
1606-
"unexpected value for ReturnAfterDelete");
1607-
if (ReturnAfterDelete)
1608-
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
1609-
else
1610-
CGF.Builder.CreateBr(continueBB);
1626+
auto EmitDeleteAndGoToEnd = [&](const FunctionDecl *DeleteOp) {
1627+
CGF.EmitDeleteCall(DeleteOp, LoadThisForDtorDelete(CGF, Dtor),
1628+
CGF.getContext().getTagDeclType(ClassDecl));
1629+
if (ReturnAfterDelete)
1630+
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
1631+
else
1632+
CGF.Builder.CreateBr(continueBB);
1633+
};
1634+
// If Sema only found a global operator delete previously, the dtor can
1635+
// always call it. Otherwise we need to check the third bit and call the
1636+
// appropriate operator delete, i.e. global or class-specific.
1637+
if (isa<CXXMethodDecl>(OD)) {
1638+
// Third bit set signals that global operator delete is called, i.e.
1639+
// ::delete appears on the callsite.
1640+
llvm::Value *CheckTheBitForGlobDeleteCall = CGF.Builder.CreateAnd(
1641+
ShouldDeleteCondition, llvm::ConstantInt::get(CondTy, 4));
1642+
llvm::Value *ShouldCallGlobDelete =
1643+
CGF.Builder.CreateIsNull(CheckTheBitForGlobDeleteCall);
1644+
llvm::BasicBlock *GlobDelete =
1645+
CGF.createBasicBlock("dtor.call_glob_delete");
1646+
llvm::BasicBlock *ClassDelete =
1647+
CGF.createBasicBlock("dtor.call_class_delete");
1648+
CGF.Builder.CreateCondBr(ShouldCallGlobDelete, ClassDelete, GlobDelete);
1649+
CGF.EmitBlock(GlobDelete);
1650+
1651+
const FunctionDecl *GlobOD = Dtor->getOperatorGlobalDelete();
1652+
if (GlobOD)
1653+
EmitDeleteAndGoToEnd(GlobOD);
1654+
else
1655+
CGF.Builder.CreateUnreachable();
1656+
1657+
CGF.EmitBlock(ClassDelete);
1658+
}
1659+
EmitDeleteAndGoToEnd(OD);
16111660

16121661
CGF.EmitBlock(continueBB);
16131662
}

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -893,13 +893,8 @@ void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
893893
QualType ElementType,
894894
const CXXDestructorDecl *Dtor) {
895895
// FIXME: Provide a source location here even though there's no
896-
// CXXMemberCallExpr for dtor call.
897-
bool UseGlobalDelete = DE->isGlobalDelete();
898-
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
899-
llvm::Value *MDThis = EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE,
900-
/*CallOrInvoke=*/nullptr);
901-
if (UseGlobalDelete)
902-
CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType);
896+
EmitVirtualDestructorCall(CGF, Dtor, Dtor_Deleting, Ptr, DE,
897+
/*CallOrInvoke=*/nullptr);
903898
}
904899

905900
void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
@@ -2016,7 +2011,7 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
20162011
ASTContext &Context = getContext();
20172012
llvm::Value *ImplicitParam = llvm::ConstantInt::get(
20182013
llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
2019-
DtorType == Dtor_Deleting);
2014+
(DtorType == Dtor_Deleting) | 4 * (D && D->isGlobalDelete()));
20202015

20212016
QualType ThisTy;
20222017
if (CE) {

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11400,6 +11400,21 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
1140011400
DiagnoseUseOfDecl(OperatorDelete, Loc);
1140111401
MarkFunctionReferenced(Loc, OperatorDelete);
1140211402
Destructor->setOperatorDelete(OperatorDelete, ThisArg);
11403+
11404+
if (isa<CXXMethodDecl>(OperatorDelete) &&
11405+
Context.getTargetInfo().getCXXABI().isMicrosoft()) {
11406+
// In Microsoft ABI whenever a class has a defined operator delete,
11407+
// scalar deleting destructors check the 3rd bit of the implicit
11408+
// parameter and if it is set, then, global operator delete must be
11409+
// called instead of class-specific one. Find and save global operator
11410+
// for that case. Do not diagnose because even if we fail to find the
11411+
// operator, it won't be possible to compile and execute the code that
11412+
// requires it.
11413+
FunctionDecl *GlobalOperatorDelete =
11414+
FindDeallocationFunctionForDestructor(Loc, RD, /*Diagnose*/ false,
11415+
/*LookForGlobal*/ true);
11416+
Destructor->setOperatorGlobalDelete(GlobalOperatorDelete);
11417+
}
1140311418
}
1140411419
}
1140511420

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3565,7 +3565,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
35653565
FunctionDecl *
35663566
Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
35673567
ImplicitDeallocationParameters IDP,
3568-
DeclarationName Name) {
3568+
DeclarationName Name, bool Diagnose) {
35693569
DeclareGlobalNewDelete();
35703570

35713571
LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName);
@@ -3580,7 +3580,7 @@ Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
35803580
if (!Result)
35813581
return nullptr;
35823582

3583-
if (CheckDeleteOperator(*this, StartLoc, StartLoc, /*Diagnose=*/true,
3583+
if (CheckDeleteOperator(*this, StartLoc, StartLoc, Diagnose,
35843584
FoundDelete.getNamingClass(), Result.Found,
35853585
Result.FD))
35863586
return nullptr;
@@ -3591,7 +3591,8 @@ Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
35913591

35923592
FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
35933593
CXXRecordDecl *RD,
3594-
bool Diagnose) {
3594+
bool Diagnose,
3595+
bool LookForGlobal) {
35953596
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete);
35963597

35973598
FunctionDecl *OperatorDelete = nullptr;
@@ -3600,18 +3601,20 @@ FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
36003601
DeallocType, ShouldUseTypeAwareOperatorNewOrDelete(),
36013602
AlignedAllocationMode::No, SizedDeallocationMode::No};
36023603

3603-
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, IDP, Diagnose))
3604-
return nullptr;
3604+
if (!LookForGlobal) {
3605+
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, IDP, Diagnose))
3606+
return nullptr;
36053607

3606-
if (OperatorDelete)
3607-
return OperatorDelete;
3608+
if (OperatorDelete)
3609+
return OperatorDelete;
3610+
}
36083611

36093612
// If there's no class-specific operator delete, look up the global
36103613
// non-array delete.
36113614
IDP.PassAlignment = alignedAllocationModeFromBool(
36123615
hasNewExtendedAlignment(*this, DeallocType));
36133616
IDP.PassSize = SizedDeallocationMode::Yes;
3614-
return FindUsualDeallocationFunction(Loc, IDP, Name);
3617+
return FindUsualDeallocationFunction(Loc, IDP, Name, Diagnose);
36153618
}
36163619

36173620
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,

clang/test/CodeGenCXX/cxx2a-destroying-delete.cpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,20 +159,43 @@ H::~H() { call_in_dtor(); }
159159
// CHECK-ITANIUM-NOT: call
160160
// CHECK-ITANIUM: }
161161

162-
// CHECK-MSABI64-LABEL: define {{.*}} @"??_GH@@UEAAPEAXI@Z"(
162+
// CHECK-MSABI64-LABEL: define {{.*}} @"??_GH@@UEAAPEAXI@Z"({{.*}},
163163
// CHECK-MSABI32-LABEL: define {{.*}} @"??_GH@@UAEPAXI@Z"(
164+
// CHECK-MSABI-SAME: i32 noundef %[[IP:.*]])
164165
// CHECK-MSABI-NOT: call{{ }}
165-
// CHECK-MSABI: load i32
166-
// CHECK-MSABI: icmp eq i32 {{.*}}, 0
167-
// CHECK-MSABI: br i1
166+
// CHECK-MSABI: store i32 %[[IP]], ptr %[[IP_ALLOCA:.*]]
167+
// CHECK-MSABI: %[[IMP_PARAM:.*]] = load i32, ptr %[[IP_ALLOCA]]
168+
// CHECK-MSABI-NEXT: %[[THIRDBIT:.*]] = and i32 %[[IMP_PARAM]], 4
169+
// CHECK-MSABI-NEXT: %[[CHCK:.*]] = icmp eq i32 %[[THIRDBIT]], 0
170+
// CHECK-MSABI-NEXT: br i1 %[[CHCK]], label %dtor.entry_cont, label %dtor.call_dtor
171+
//
172+
// CHECK_MSABI-LABEL: dtor.call_dtor:
173+
// CHECK_MSABI-NEXT: call void @"??1H@@UEAA@XZ"({{.*}})
174+
// CHECK_MSABI-NEXT: br label %dtor.entry_cont
175+
//
176+
// CHECK_MSABI-LABEL: dtor.entry_cont:
177+
// CHECK_MSABI-NEXT: %[[FIRSTBIT:.*]] = and i32 %[[IMP_PARAM]], 1
178+
// CHECK_MSABI-NEXT: %[[CHCK1:.*]] = icmp eq i32 %[[FIRSTBIT]], 0
179+
// CHECK_MSABI-NEXT: br i1 %[[CHCK1]], label %dtor.continue, label %dtor.call_delete
180+
//
181+
// CHECK_MSABI-LABEL: dtor.call_delete:
182+
// CHECK-MSABI: %[[THIRDBIT1:.*]] = and i32 %[[IMP_PARAM]], 4
183+
// CHECK-MSABI-NEXT: %[[CHCK2:.*]] = icmp eq i32 %[[THIRDBIT1]], 0
184+
// CHECK-MSABI-NEXT: br i1 %[[CHCK2]], label %dtor.call_class_delete, label %dtor.call_glob_delete
185+
//
186+
// CHECK-MSABI-LABEL: dtor.call_glob_delete:
187+
// CHECK-MSABI64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %{{.*}}, i64 noundef 48)
188+
// CHECK-MSABI32: call void @"??3@YAXPAXIW4align_val_t@std@@@Z"(ptr noundef %{{.*}}, i32 noundef 32, i32 noundef 16)
189+
// CHECK-MSABI-NEXT: br label %[[RETURN:.*]]
168190
//
191+
// CHECK-MSABI: dtor.call_class_delete:
169192
// CHECK-MSABI-NOT: call{{ }}
170193
// CHECK-MSABI64: getelementptr {{.*}}, i64 24
171194
// CHECK-MSABI32: getelementptr {{.*}}, i32 20
172195
// CHECK-MSABI-NOT: call{{ }}
173196
// CHECK-MSABI64: call void @"??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 noundef 48, i64 noundef 16)
174197
// CHECK-MSABI32: call void @"??3F@@SAXPAU0@Udestroying_delete_t@std@@IW4align_val_t@2@@Z"({{.*}}, i32 noundef 32, i32 noundef 16)
175-
// CHECK-MSABI: br label %[[RETURN:.*]]
198+
// CHECK-MSABI: br label %[[RETURN:]]
176199
//
177200
// CHECK-MSABI64: call void @"??1H@@UEAA@XZ"(
178201
// CHECK-MSABI32: call x86_thiscallcc void @"??1H@@UAE@XZ"(
@@ -194,9 +217,31 @@ I::~I() { call_in_dtor(); }
194217
// CHECK-MSABI32-LABEL: define {{.*}} @"??_GI@@UAEPAXI@Z"(
195218
// CHECK-MSABI-NOT: call{{ }}
196219
// CHECK-MSABI: load i32
197-
// CHECK-MSABI: icmp eq i32 {{.*}}, 0
198-
// CHECK-MSABI: br i1
220+
// CHECK-MSABI-NEXT: and i32 %[[IMP_PARAM:.*]], 4
221+
// CHECK-MSABI-NEXT: icmp eq i32 {{.*}}, 0
222+
// CHECK-MSABI-NEXT: br i1 %[[CHCK]], label %dtor.entry_cont, label %dtor.call_dtor
223+
//
224+
// CHECK-MSABI: dtor.call_dtor:
225+
// CHECK-MSABI64-NEXT: call void @"??1I@@UEAA@XZ"({{.*}})
226+
// CHECK-MSABI32-NEXT: call x86_thiscallcc void @"??1I@@UAE@XZ"({{.*}})
227+
// CHECK-MSABI-NEXT: br label %dtor.entry_cont
228+
//
229+
// CHECK-MSABI: dtor.entry_cont:
230+
// CHECK-MSABI-NEXT: and i32 %[[IMP_PARAM]], 1
231+
// CHECK-MSABI-NEXT: icmp eq i32 %{{.*}}, 0
232+
// CHECK-MSABI-NEXT: br i1 %{{.*}}, label %dtor.continue, label %dtor.call_delete
233+
//
234+
// CHECK-MSABI: dtor.call_delete:
235+
// CHECK-MSABI-NEXT: %[[THIRDBIT1:.*]] = and i32 %[[IMP_PARAM]], 4
236+
// CHECK-MSABI-NEXT: %[[CHCK2:.*]] = icmp eq i32 %[[THIRDBIT1]], 0
237+
// CHECK-MSABI-NEXT: br i1 %[[CHCK2]], label %dtor.call_class_delete, label %dtor.call_glob_delete
238+
//
239+
// CHECK-MSABI-LABEL: dtor.call_glob_delete:
240+
// CHECK-MSABI64: call void @"??3@YAXPEAX_KW4align_val_t@std@@@Z"(ptr noundef %{{.*}}, i64 noundef 96, i64 noundef 32)
241+
// CHECK-MSABI32: call void @"??3@YAXPAXIW4align_val_t@std@@@Z"(ptr noundef %{{.*}}, i32 noundef 64, i32 noundef 32)
242+
// CHECK-MSABI-NEXT: br label %[[RETURN:.*]]
199243
//
244+
// CHECK_MSABI: dtor.call_class_delete:
200245
// CHECK-MSABI-NOT: call{{ }}
201246
// CHECK-MSABI64: getelementptr {{.*}}, i64 24
202247
// CHECK-MSABI32: getelementptr {{.*}}, i32 20

clang/test/CodeGenCXX/microsoft-abi-structors.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ struct C {
5252
// DTORS: store ptr %{{.*}}, ptr %[[RETVAL:retval]]
5353
// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]
5454
// DTORS: call x86_thiscallcc void @"??1C@basic@@UAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])
55-
// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[SHOULD_DELETE_VALUE]], 0
55+
// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1
56+
// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0
5657
// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]
5758
//
5859
// DTORS: [[CALL_DELETE_LABEL]]
@@ -113,8 +114,7 @@ void call_deleting_dtor_and_global_delete(C *obj_ptr) {
113114
// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]
114115
// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0
115116
// CHECK-NEXT: %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]
116-
// CHECK-NEXT: %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 0)
117-
// CHECK-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[CALL]])
117+
// CHECK-NEXT: %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 5)
118118
// CHECK: ret void
119119
}
120120

@@ -458,3 +458,41 @@ class G {
458458
extern void testG() {
459459
G g;
460460
}
461+
462+
namespace operator_delete {
463+
464+
class H { virtual ~H();
465+
void operator delete(void *);
466+
};
467+
H::~H() { }
468+
469+
void checkH() {
470+
new H();
471+
}
472+
// DTORS: define linkonce_odr dso_local x86_thiscallcc ptr @"??_GH@operator_delete@@EAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {
473+
// DTORS: store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4
474+
// DTORS: store ptr %{{.*}}, ptr %[[RETVAL:retval]]
475+
// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]
476+
// DTORS: call x86_thiscallcc void @"??1H@operator_delete@@EAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])
477+
// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1
478+
// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0
479+
// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]
480+
//
481+
// DTORS: [[CALL_DELETE_LABEL]]
482+
// DTORS-NEXT: %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 4
483+
// DTORS-NEXT: %[[CONDITION1:[0-9]+]] = icmp eq i32 %[[AND]], 0
484+
// DTORS-NEXT: br i1 %[[CONDITION1]], label %[[CALL_CLASS_DELETE:[0-9a-z._]+]], label %[[CALL_GLOB_DELETE:[0-9a-z._]+]]
485+
//
486+
// DTORS: [[CALL_GLOB_DELETE]]
487+
// DTORS-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[THIS]])
488+
// DTORS-NEXT: br label %[[CONTINUE_LABEL]]
489+
//
490+
// DTORS: [[CALL_CLASS_DELETE]]
491+
// DTORS-NEXT: call void @"??3H@operator_delete@@CAXPAX@Z"(ptr %[[THIS]])
492+
// DTORS-NEXT: br label %[[CONTINUE_LABEL]]
493+
//
494+
// DTORS: [[CONTINUE_LABEL]]
495+
// DTORS-NEXT: %[[RET:.*]] = load ptr, ptr %[[RETVAL]]
496+
// DTORS-NEXT: ret ptr %[[RET]]
497+
498+
}

0 commit comments

Comments
 (0)