diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-13 01:55:36 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-13 01:55:36 +0000 |
commit | 5b34958b46dc14267d1b06099c3bd43e748716fc (patch) | |
tree | c3e9bded9164d23dfcc44b90914d040d087e18e5 /clang/lib/CodeGen/CGClass.cpp | |
parent | ad38fbffad842c3baf4589139271d16d14af0357 (diff) | |
download | llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.zip llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.tar.gz llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.tar.bz2 |
Support for destroying operator delete, per C++2a proposal P0722.
This feature is not (yet) approved by the C++ committee, so this is liable to
be reverted or significantly modified based on committee feedback.
No functionality change intended for existing code (a new type must be defined
in namespace std to take advantage of this feature).
llvm-svn: 315662
Diffstat (limited to 'clang/lib/CodeGen/CGClass.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index e86c8dc..60a9936 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1413,10 +1413,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // possible to delegate the destructor body to the complete // destructor. Do so. if (DtorType == Dtor_Deleting) { + RunCleanupsScope DtorEpilogue(*this); EnterDtorCleanups(Dtor, Dtor_Deleting); - EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, - /*Delegating=*/false, LoadCXXThisAddress()); - PopCleanupBlock(); + if (HaveInsertPoint()) + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + /*Delegating=*/false, LoadCXXThisAddress()); return; } @@ -1512,6 +1513,13 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) } namespace { + llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF, + const CXXDestructorDecl *DD) { + if (Expr *ThisArg = DD->getOperatorDeleteThisArg()) + return CGF.EmitScalarExpr(DD->getOperatorDeleteThisArg()); + return CGF.LoadCXXThis(); + } + /// Call the operator delete associated with the current destructor. struct CallDtorDelete final : EHScopeStack::Cleanup { CallDtorDelete() {} @@ -1519,11 +1527,38 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) override { const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); const CXXRecordDecl *ClassDecl = Dtor->getParent(); - CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), + CGF.EmitDeleteCall(Dtor->getOperatorDelete(), + LoadThisForDtorDelete(CGF, Dtor), CGF.getContext().getTagDeclType(ClassDecl)); } }; + void EmitConditionalDtorDeleteCall(CodeGenFunction &CGF, + llvm::Value *ShouldDeleteCondition, + bool ReturnAfterDelete) { + llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete"); + llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue"); + llvm::Value *ShouldCallDelete + = CGF.Builder.CreateIsNull(ShouldDeleteCondition); + CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB); + + CGF.EmitBlock(callDeleteBB); + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + CGF.EmitDeleteCall(Dtor->getOperatorDelete(), + LoadThisForDtorDelete(CGF, Dtor), + CGF.getContext().getTagDeclType(ClassDecl)); + assert(Dtor->getOperatorDelete()->isDestroyingOperatorDelete() == + ReturnAfterDelete && + "unexpected value for ReturnAfterDelete"); + if (ReturnAfterDelete) + CGF.EmitBranchThroughCleanup(CGF.ReturnBlock); + else + CGF.Builder.CreateBr(continueBB); + + CGF.EmitBlock(continueBB); + } + struct CallDtorDeleteConditional final : EHScopeStack::Cleanup { llvm::Value *ShouldDeleteCondition; @@ -1534,20 +1569,8 @@ namespace { } void Emit(CodeGenFunction &CGF, Flags flags) override { - llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete"); - llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue"); - llvm::Value *ShouldCallDelete - = CGF.Builder.CreateIsNull(ShouldDeleteCondition); - CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB); - - CGF.EmitBlock(callDeleteBB); - const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); - const CXXRecordDecl *ClassDecl = Dtor->getParent(); - CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), - CGF.getContext().getTagDeclType(ClassDecl)); - CGF.Builder.CreateBr(continueBB); - - CGF.EmitBlock(continueBB); + EmitConditionalDtorDeleteCall(CGF, ShouldDeleteCondition, + /*ReturnAfterDelete*/false); } }; @@ -1706,6 +1729,9 @@ namespace { /// \brief Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. +/// +/// For a deleting destructor, this also handles the case where a destroying +/// operator delete completely overrides the definition. void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, CXXDtorType DtorType) { assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) && @@ -1718,11 +1744,23 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, "operator delete missing - EnterDtorCleanups"); if (CXXStructorImplicitParamValue) { // If there is an implicit param to the deleting dtor, it's a boolean - // telling whether we should call delete at the end of the dtor. - EHStack.pushCleanup<CallDtorDeleteConditional>( - NormalAndEHCleanup, CXXStructorImplicitParamValue); + // telling whether this is a deleting destructor. + if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) + EmitConditionalDtorDeleteCall(*this, CXXStructorImplicitParamValue, + /*ReturnAfterDelete*/true); + else + EHStack.pushCleanup<CallDtorDeleteConditional>( + NormalAndEHCleanup, CXXStructorImplicitParamValue); } else { - EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup); + if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) { + const CXXRecordDecl *ClassDecl = DD->getParent(); + EmitDeleteCall(DD->getOperatorDelete(), + LoadThisForDtorDelete(*this, DD), + getContext().getTagDeclType(ClassDecl)); + EmitBranchThroughCleanup(ReturnBlock); + } else { + EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup); + } } return; } |