diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2025-01-09 08:29:19 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-09 08:29:19 -0500 |
commit | 5ff7f479a1f30d9c5393e4f94df6178a63cc2236 (patch) | |
tree | 3c759bf1e1d0cf56f22eea76bea06c81db819a30 /clang/lib/Sema/SemaExceptionSpec.cpp | |
parent | b4e17d4a314ed87ff6b40b4b05397d4b25b6636a (diff) | |
download | llvm-5ff7f479a1f30d9c5393e4f94df6178a63cc2236.zip llvm-5ff7f479a1f30d9c5393e4f94df6178a63cc2236.tar.gz llvm-5ff7f479a1f30d9c5393e4f94df6178a63cc2236.tar.bz2 |
[C++20] Destroying delete and deleted destructors (#118800)
When a destroying delete overload is selected, the destructor is not
automatically called. Therefore, the destructor can be deleted without
causing the program to be ill-formed.
Fixes #46818
Diffstat (limited to 'clang/lib/Sema/SemaExceptionSpec.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index ac5d51a1..254ad05 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1200,21 +1200,29 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::CXXDeleteExprClass: { auto *DE = cast<CXXDeleteExpr>(S); - CanThrowResult CT; + CanThrowResult CT = CT_Cannot; QualType DTy = DE->getDestroyedType(); if (DTy.isNull() || DTy->isDependentType()) { CT = CT_Dependent; } else { + // C++20 [expr.delete]p6: If the value of the operand of the delete- + // expression is not a null pointer value and the selected deallocation + // function (see below) is not a destroying operator delete, the delete- + // expression will invoke the destructor (if any) for the object or the + // elements of the array being deleted. const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); - CT = canCalleeThrow(*this, DE, OperatorDelete); - if (!OperatorDelete->isDestroyingOperatorDelete()) { - if (const auto *RD = DTy->getAsCXXRecordDecl()) { - if (const CXXDestructorDecl *DD = RD->getDestructor()) - CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD)); - } - if (CT == CT_Can) - return CT; + if (const auto *RD = DTy->getAsCXXRecordDecl()) { + if (const CXXDestructorDecl *DD = RD->getDestructor(); + DD && DD->isCalledByDelete(OperatorDelete)) + CT = canCalleeThrow(*this, DE, DD); } + + // We always look at the exception specification of the operator delete. + CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, OperatorDelete)); + + // If we know we can throw, we're done. + if (CT == CT_Can) + return CT; } return mergeCanThrow(CT, canSubStmtsThrow(*this, DE)); } |