Index: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -80,8 +80,7 @@ ASTContext &getContext() const { return CGM.getContext(); } - virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType); - virtual bool requiresArrayCookie(const CXXNewExpr *E); + /// Determine whether there's something special about the rules of /// the ABI tell us that 'this' is a complete object within the @@ -461,6 +460,9 @@ /**************************** Array cookies ******************************/ + virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType); + virtual bool requiresArrayCookie(const CXXNewExpr *E); + /// Returns the extra size required in order to store the array /// cookie for the given new-expression. May return 0 to indicate that no /// array cookie is required. Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -1971,26 +1971,57 @@ CGF.PopCleanupBlock(); } -void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { - const Expr *Arg = E->getArgument(); - Address Ptr = EmitPointerWithAlignment(Arg); +// Will we read through the deleted pointer? If so, +// we must first check it is not null. +static bool DeleteMightAccessObject(CodeGenFunction &CGF, + const CXXDeleteExpr *E, QualType DeleteTy) { - // Null check the pointer. - llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); - llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); + if (E->getOperatorDelete()->isDestroyingOperatorDelete()) { + // It is safe to call destroying operator delete with nullptr arguments + // ([expr.delete] tells us it is unspecified whether a deallocation + // function is called) but a virtual destructor must be resolved + // to find the right function, which we can't do on nullptr. + auto *Dtor = DeleteTy->getAsCXXRecordDecl()->getDestructor(); + return Dtor && Dtor->isVirtual(); + } - llvm::Value *IsNull = Builder.CreateIsNull(Ptr.getPointer(), "isnull"); + if (E->isArrayForm()) { + return CGF.CGM.getCXXABI().requiresArrayCookie(E, DeleteTy); + } - Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); - EmitBlock(DeleteNotNull); + // Otherwise, we should avoid invoking any nontrivial destructor on + // a null object. + return DeleteTy.isDestructedType(); +} +void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { + const Expr *Arg = E->getArgument(); + Address Ptr = EmitPointerWithAlignment(Arg); QualType DeleteTy = E->getDestroyedType(); + // Null check the pointer, unless the destructor is trivial. In that case, + // all we'll be doing is passing Ptr to ::operator delete(), which is + // well formed for nullptr arguments (and allowed by [expr.delete.7] + // The overwhelming majority of deletes are of non-nullptr, so there's + // no efficiency gain to be had by skipping the very rare exceptions, and + // it bleeds code size (and unneeded branches.) + llvm::BasicBlock *DeleteEnd = nullptr; + if (DeleteMightAccessObject(*this, E, DeleteTy)) { + llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); + DeleteEnd = createBasicBlock("delete.end"); + + llvm::Value *IsNull = Builder.CreateIsNull(Ptr.getPointer(), "isnull"); + + Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); + EmitBlock(DeleteNotNull); + } + + // A destroying operator delete overrides the entire operation of the // delete expression. if (E->getOperatorDelete()->isDestroyingOperatorDelete()) { EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy); - EmitBlock(DeleteEnd); + if (DeleteEnd) EmitBlock(DeleteEnd); return; } @@ -2018,14 +2049,14 @@ } assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); - + if (E->isArrayForm()) { EmitArrayDelete(*this, E, Ptr, DeleteTy); } else { EmitObjectDelete(*this, E, Ptr, DeleteTy); } - EmitBlock(DeleteEnd); + if (DeleteEnd) EmitBlock(DeleteEnd); } static bool isGLValueFromPointerDeref(const Expr *E) { Index: test/CodeGenCXX/cxx2a-destroying-delete.cpp =================================================================== --- test/CodeGenCXX/cxx2a-destroying-delete.cpp +++ test/CodeGenCXX/cxx2a-destroying-delete.cpp @@ -15,9 +15,8 @@ void delete_A(A *a) { delete a; } // CHECK-LABEL: define {{.*}}delete_A // CHECK: %[[a:.*]] = load -// CHECK: icmp eq %{{.*}} %[[a]], null -// CHECK: br i1 -// +// CHECK-NOT: icmp eq %{{.*}} %[[a]], null +// CHECK-NOT: br i1 // Ensure that we call the destroying delete and not the destructor. // CHECK-NOT: call // CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]]) @@ -60,8 +59,8 @@ // CHECK: %[[castbase:.*]] = bitcast {{.*}} %[[base]] // // CHECK: %[[a:.*]] = phi {{.*}} %[[castbase]] -// CHECK: icmp eq %{{.*}} %[[a]], null -// CHECK: br i1 +// CHECK-NOT: icmp eq %{{.*}} %[[a]], null +// CHECK-NOT: br i1 // // CHECK-NOT: call // CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]]) Index: test/CodeGenCXX/delete-two-arg.cpp =================================================================== --- test/CodeGenCXX/delete-two-arg.cpp +++ test/CodeGenCXX/delete-two-arg.cpp @@ -9,8 +9,8 @@ // CHECK-LABEL: define void @_ZN5test11aEPNS_1AE( void a(A *x) { // CHECK: load - // CHECK-NEXT: icmp eq {{.*}}, null - // CHECK-NEXT: br i1 + // CHECK-NOT: icmp eq {{.*}}, null + // CHECK-NOT: br i1 // CHECK: call void @_ZN5test11AdlEPvj(i8* %{{.*}}, i32 4) delete x; } Index: test/CodeGenCXX/delete.cpp =================================================================== --- test/CodeGenCXX/delete.cpp +++ test/CodeGenCXX/delete.cpp @@ -9,7 +9,12 @@ }; // POD types. +// CHECK-LABEL: define void @_Z2t3P1S void t3(S *s) { + // CHECK-NOT: icmp eq {{.*}}, null + // CHECK-NOT: br i1 + // CHECK: call void @_ZdlPv + delete s; } @@ -99,6 +104,8 @@ namespace test3 { void f(int a[10][20]) { + // CHECK-NOT: icmp eq {{.*}}, null + // CHECK-NOT: br i1 // CHECK: call void @_ZdaPv(i8* delete a; } @@ -113,6 +120,8 @@ // CHECK-LABEL: define void @_ZN5test421global_delete_virtualEPNS_1XE void global_delete_virtual(X *xp) { + // CHECK: icmp eq {{.*}}, null + // CHECK: br i1 // Load the offset-to-top from the vtable and apply it. // This has to be done first because the dtor can mess it up. // CHECK: [[T0:%.*]] = bitcast [[X:%.*]]* [[XP:%.*]] to i64**