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/AST | |
| parent | ad38fbffad842c3baf4589139271d16d14af0357 (diff) | |
| download | bcm5719-llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.tar.gz bcm5719-llvm-5b34958b46dc14267d1b06099c3bd43e748716fc.zip | |
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/AST')
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 16 |
3 files changed, 41 insertions, 2 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4a9b9bea830..9b0d976ebb2 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2732,6 +2732,20 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const return Params == FPT->getNumParams(); } +bool FunctionDecl::isDestroyingOperatorDelete() const { + // C++ P0722: + // Within a class C, a single object deallocation function with signature + // (T, std::destroying_delete_t, <more params>) + // is a destroying operator delete. + if (!isa<CXXMethodDecl>(this) || getOverloadedOperator() != OO_Delete || + getNumParams() < 2) + return false; + + auto *RD = getParamDecl(1)->getType()->getAsCXXRecordDecl(); + return RD && RD->isInStdNamespace() && RD->getIdentifier() && + RD->getIdentifier()->isStr("destroying_delete_t"); +} + LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getDeclLanguageLinkage(*this); } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 26e5c4ffbed..bd8a150cf1e 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1788,6 +1788,14 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; unsigned UsualParams = 1; + // C++ P0722: + // A destroying operator delete is a usual deallocation function if + // removing the std::destroying_delete_t parameter and changing the + // first parameter type from T* to void* results in the signature of + // a usual deallocation function. + if (isDestroyingOperatorDelete()) + ++UsualParams; + // C++ <=14 [basic.stc.dynamic.deallocation]p2: // [...] If class T does not declare such an operator delete but does // declare a member deallocation function named operator delete with @@ -2187,12 +2195,13 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, isInline, isImplicitlyDeclared); } -void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) { +void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) { auto *First = cast<CXXDestructorDecl>(getFirstDecl()); if (OD && !First->OperatorDelete) { First->OperatorDelete = OD; + First->OperatorDeleteThisArg = ThisArg; if (auto *L = getASTMutationListener()) - L->ResolvedOperatorDelete(First, OD); + L->ResolvedOperatorDelete(First, OD, ThisArg); } } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index fe45b5e47f3..182a8b415a4 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -160,6 +160,22 @@ bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); + + // For a destroying operator delete, we may have implicitly converted the + // pointer type to the type of the parameter of the 'operator delete' + // function. + while (auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ICE->getCastKind() == CK_DerivedToBase || + ICE->getCastKind() == CK_UncheckedDerivedToBase || + ICE->getCastKind() == CK_NoOp) { + assert((ICE->getCastKind() == CK_NoOp || + getOperatorDelete()->isDestroyingOperatorDelete()) && + "only a destroying operator delete can have a converted arg"); + Arg = ICE->getSubExpr(); + } else + break; + } + // The type-to-delete may not be a pointer if it's a dependent type. const QualType ArgType = Arg->getType(); |

