[clang] 91354fb - [C++20] Destroying delete can cause a type to be noexcept when deleting (#118687)

via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 5 11:26:37 PST 2024


Author: Aaron Ballman
Date: 2024-12-05T14:26:33-05:00
New Revision: 91354fb1469620cc92c4bf1a11444b2e7f13d54d

URL: https://github.com/llvm/llvm-project/commit/91354fb1469620cc92c4bf1a11444b2e7f13d54d
DIFF: https://github.com/llvm/llvm-project/commit/91354fb1469620cc92c4bf1a11444b2e7f13d54d.diff

LOG: [C++20] Destroying delete can cause a type to be noexcept when deleting (#118687)

Given a `noexcept` operator with an operand that calls `delete`, Clang
was not considering whether the selected `operator delete` function was
a destroying delete or not when inspecting whether the deleted object
type has a throwing destructor. Thus, the operator would return `false`
for a type with a potentially throwing destructor even though that
destructor would not be called due to the destroying delete. Clang now
takes the kind of delete operator into consideration.

Fixes #118660

Added: 
    clang/test/SemaCXX/noexcept-destroying-delete.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaExceptionSpec.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ad5ef2119d3654..3f58e64cf0ccbc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -677,6 +677,9 @@ Bug Fixes in This Version
 - Fixed a crash when GNU statement expression contains invalid statement (#GH113468).
 - Fixed a failed assertion when using ``__attribute__((noderef))`` on an
   ``_Atomic``-qualified type (#GH116124).
+- No longer return ``false`` for ``noexcept`` expressions involving a
+  ``delete`` which resolves to a destroying delete but the type of the object
+  being deleted has a potentially throwing destructor (#GH118660).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index ecfd79a50542c4..6a9f43d6f5215e 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1205,15 +1205,16 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
     if (DTy.isNull() || DTy->isDependentType()) {
       CT = CT_Dependent;
     } else {
-      CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
-      if (const RecordType *RT = DTy->getAs<RecordType>()) {
-        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-        const CXXDestructorDecl *DD = RD->getDestructor();
-        if (DD)
-          CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
+      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 (CT == CT_Can)
-        return CT;
     }
     return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
   }

diff  --git a/clang/test/SemaCXX/noexcept-destroying-delete.cpp b/clang/test/SemaCXX/noexcept-destroying-delete.cpp
new file mode 100644
index 00000000000000..92ccbc1fb3f96b
--- /dev/null
+++ b/clang/test/SemaCXX/noexcept-destroying-delete.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions -Wno-unevaluated-expression -std=c++20 %s
+// expected-no-diagnostics
+
+namespace std {
+  struct destroying_delete_t {
+    explicit destroying_delete_t() = default;
+  };
+
+  inline constexpr destroying_delete_t destroying_delete{};
+}
+
+struct Explicit {
+    ~Explicit() noexcept(false) {}
+
+    void operator delete(Explicit*, std::destroying_delete_t) noexcept {
+    }
+};
+
+Explicit *qn = nullptr;
+// This assertion used to fail, see GH118660
+static_assert(noexcept(delete(qn)));
+
+struct ThrowingDestroyingDelete {
+    ~ThrowingDestroyingDelete() noexcept(false) {}
+
+    void operator delete(ThrowingDestroyingDelete*, std::destroying_delete_t) noexcept(false) {
+    }
+};
+
+ThrowingDestroyingDelete *pn = nullptr;
+// noexcept should return false here because the destroying delete itself is a
+// potentially throwing function.
+static_assert(!noexcept(delete(pn)));


        


More information about the cfe-commits mailing list