зеркало из https://github.com/microsoft/clang-1.git
When compiling ::delete for a class with a virtual destructor, call
the complete destructor and then invoke the global delete operator. Previously, we would invoke the deleting destructor, which calls the wrong delete operator. Fixes PR10341. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135021 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
9f8ee2ea0a
Коммит
a8b20f70d5
|
@ -1211,7 +1211,8 @@ namespace {
|
|||
static void EmitObjectDelete(CodeGenFunction &CGF,
|
||||
const FunctionDecl *OperatorDelete,
|
||||
llvm::Value *Ptr,
|
||||
QualType ElementType) {
|
||||
QualType ElementType,
|
||||
bool UseGlobalDelete) {
|
||||
// Find the destructor for the type, if applicable. If the
|
||||
// destructor is virtual, we'll just emit the vcall and return.
|
||||
const CXXDestructorDecl *Dtor = 0;
|
||||
|
@ -1221,17 +1222,30 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
|
|||
Dtor = RD->getDestructor();
|
||||
|
||||
if (Dtor->isVirtual()) {
|
||||
if (UseGlobalDelete) {
|
||||
// If we're supposed to call the global delete, make sure we do so
|
||||
// even if the destructor throws.
|
||||
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
|
||||
Ptr, OperatorDelete,
|
||||
ElementType);
|
||||
}
|
||||
|
||||
const llvm::Type *Ty =
|
||||
CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor,
|
||||
Dtor_Complete),
|
||||
/*isVariadic=*/false);
|
||||
|
||||
llvm::Value *Callee
|
||||
= CGF.BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
|
||||
= CGF.BuildVirtualCall(Dtor,
|
||||
UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
|
||||
Ptr, Ty);
|
||||
CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
|
||||
0, 0);
|
||||
|
||||
// The dtor took care of deleting the object.
|
||||
if (UseGlobalDelete) {
|
||||
CGF.PopCleanupBlock();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1477,7 +1491,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
|
|||
if (E->isArrayForm()) {
|
||||
EmitArrayDelete(*this, E, Ptr, DeleteTy);
|
||||
} else {
|
||||
EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy);
|
||||
EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy,
|
||||
E->isGlobalDelete());
|
||||
}
|
||||
|
||||
EmitBlock(DeleteEnd);
|
||||
|
|
|
@ -112,3 +112,22 @@ namespace test3 {
|
|||
delete a;
|
||||
}
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
// PR10341: ::delete with a virtual destructor
|
||||
struct X {
|
||||
virtual ~X();
|
||||
void operator delete (void *);
|
||||
};
|
||||
|
||||
// CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE
|
||||
void global_delete_virtual(X *xp) {
|
||||
// CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])***
|
||||
// CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0
|
||||
// CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]]
|
||||
// CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]])
|
||||
// CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8*
|
||||
// CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind
|
||||
::delete xp;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче