aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaExceptionSpec.cpp
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2025-01-09 08:29:19 -0500
committerGitHub <noreply@github.com>2025-01-09 08:29:19 -0500
commit5ff7f479a1f30d9c5393e4f94df6178a63cc2236 (patch)
tree3c759bf1e1d0cf56f22eea76bea06c81db819a30 /clang/lib/Sema/SemaExceptionSpec.cpp
parentb4e17d4a314ed87ff6b40b4b05397d4b25b6636a (diff)
downloadllvm-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.cpp26
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));
}