[clang] cc615d1 - [clang][Sema] Function effect analysis was missing the implicit call to the destructor in a CXXDeleteExpr. (#184460)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 13 11:52:36 PDT 2026
Author: Doug Wyatt
Date: 2026-07-13T11:52:31-07:00
New Revision: cc615d117c7f942a508ceecedd519f2fe9921493
URL: https://github.com/llvm/llvm-project/commit/cc615d117c7f942a508ceecedd519f2fe9921493
DIFF: https://github.com/llvm/llvm-project/commit/cc615d117c7f942a508ceecedd519f2fe9921493.diff
LOG: [clang][Sema] Function effect analysis was missing the implicit call to the destructor in a CXXDeleteExpr. (#184460)
Co-authored-by: Doug Wyatt <dwyatt at apple.com>
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Sema/SemaFunctionEffects.cpp
clang/test/Sema/attr-nonblocking-constraints.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 538c67e7e5d09..12fb2a1eb80b7 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -827,6 +827,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
would only use the first one). A new warning that diagnoses such declarations has been added to `-Wignored-attributes`.
(#GH191829)
- Fixed a crash in the constant evaluator when an ill-formed array new-expression whose bound could not be determined (e.g. `new int[]()`) was used in a constant expression. (#GH200139)
+- Fixed a case where function effect analysis (`nonblocking` etc.) did not visit a destructor invoked from a `delete` expression. (#GH184460)
- Clang now defines the GCC-compatible predefined macros `__WCHAR_MIN__`, `__WINT_MIN__`, and `__SIG_ATOMIC_MIN__`. (#GH199678)
- Fix a crash in addUnsizedArray due assert not verifying we have a Base before doing checks on it. (#GH44212)
diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp
index 124e23cc97556..975281175aebb 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -1255,15 +1255,23 @@ class Analyzer {
}
bool VisitCXXDeleteExpr(CXXDeleteExpr *Delete) override {
+ FunctionDecl *OpDelete = Delete->getOperatorDelete();
+
+ // RecursiveASTVisitor does not visit the called destructor.
+ // But a destroying operator delete means that no destructor is called.
+ if (OpDelete == nullptr || !OpDelete->isDestroyingOperatorDelete()) {
+ if (QualType QT = Delete->getDestroyedType(); !QT.isNull()) {
+ followTypeDtor(QT, Delete->getBeginLoc());
+ }
+ }
+
// RecursiveASTVisitor does not visit the implicit call to operator
// delete.
- if (FunctionDecl *FD = Delete->getOperatorDelete()) {
- CallableInfo CI(*FD, SpecialFuncType::OperatorDelete);
+ if (OpDelete != nullptr) {
+ CallableInfo CI(*OpDelete, SpecialFuncType::OperatorDelete);
followCall(CI, Delete->getBeginLoc());
}
- // It DOES however visit the called destructor
-
return true;
}
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp
index 012c017798a1f..400057768523c 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -5,6 +5,8 @@
// This diagnostic is re-enabled and exercised in isolation later in this file.
#pragma clang diagnostic ignored "-Wperf-constraint-implies-noexcept"
+typedef __SIZE_TYPE__ size_t;
+
// --- CONSTRAINTS ---
void nb1() [[clang::nonblocking]]
@@ -430,6 +432,44 @@ struct HasDtor {
~HasDtor() {}
};
+struct SafeDeleteUnsafeDestroy {
+ static unsigned char storage[256];
+
+ void* operator new(size_t) { return storage; }
+ void operator delete(void* ptr) {}
+
+ void* operator new[](size_t sz) { return storage; }
+ void operator delete[](void* ptr) {}
+
+ SafeDeleteUnsafeDestroy(); // expected-note 2 {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
+ ~SafeDeleteUnsafeDestroy(); // expected-note 2 {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
+};
+
+void testSafeDeleteUnsafeDestroy() [[clang::nonblocking]]
+{
+ auto *ptr = new SafeDeleteUnsafeDestroy; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'SafeDeleteUnsafeDestroy::SafeDeleteUnsafeDestroy'}}
+ delete ptr; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' destructor 'SafeDeleteUnsafeDestroy::~SafeDeleteUnsafeDestroy'}}
+
+ auto *arr = new SafeDeleteUnsafeDestroy[2]; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'SafeDeleteUnsafeDestroy::SafeDeleteUnsafeDestroy'}}
+ delete[] arr; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' destructor 'SafeDeleteUnsafeDestroy::~SafeDeleteUnsafeDestroy'}}
+}
+
+namespace std {
+struct destroying_delete_t { explicit destroying_delete_t() = default; };
+inline constexpr destroying_delete_t destroying_delete{};
+}
+
+struct DestroyingDelete {
+ ~DestroyingDelete();
+ void operator delete(DestroyingDelete*, std::destroying_delete_t) {
+ // do nothing
+ }
+};
+
+void testDestroyingDelete(DestroyingDelete* d) [[clang::nonblocking]] {
+ delete d;
+}
+
template <typename T>
struct Optional {
union {
More information about the cfe-commits
mailing list