[clang] [clang][Interp] Check for 'delete this' in dtors (PR #101792)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 21:47:32 PDT 2024


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/101792

None

>From 08aaea88863ad000d68316391a8702cd777496af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 3 Aug 2024 06:37:24 +0200
Subject: [PATCH] [clang][Interp] Check for 'delete this' in dtors

---
 clang/lib/AST/Interp/Interp.cpp      |  6 ++++++
 clang/lib/AST/Interp/Pointer.cpp     |  6 ++++++
 clang/lib/AST/Interp/Pointer.h       |  2 ++
 clang/test/AST/Interp/new-delete.cpp | 13 +++++++++++++
 4 files changed, 27 insertions(+)

diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 9009cf820244d..0252dd0d32699 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -836,6 +836,12 @@ static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
   const Record *R = Desc->ElemRecord;
   assert(R);
 
+  if (Pointer::pointToSameBlock(BasePtr, S.Current->getThis())) {
+    const SourceInfo &Loc = S.Current->getSource(OpPC);
+    S.FFDiag(Loc, diag::note_constexpr_double_destroy);
+    return false;
+  }
+
   // Fields.
   for (const Record::Field &Field : llvm::reverse(R->fields())) {
     const Descriptor *D = Field.Desc;
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index 79fe317a61dff..f86be1214826d 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -398,6 +398,12 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
   return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
 }
 
+bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
+  if (!A.isBlockPointer() || !B.isBlockPointer())
+    return false;
+  return A.block() == B.block();
+}
+
 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
   return hasSameBase(A, B) &&
          A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 6b0c31358159c..6f6983458ab60 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -665,6 +665,8 @@ class Pointer {
   static bool hasSameBase(const Pointer &A, const Pointer &B);
   /// Checks if two pointers can be subtracted.
   static bool hasSameArray(const Pointer &A, const Pointer &B);
+  /// Checks if both given pointers point to the same block.
+  static bool pointToSameBlock(const Pointer &A, const Pointer &B);
 
   /// Prints the pointer.
   void print(llvm::raw_ostream &OS) const;
diff --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp
index 7a85def784920..ae76950f13731 100644
--- a/clang/test/AST/Interp/new-delete.cpp
+++ b/clang/test/AST/Interp/new-delete.cpp
@@ -551,6 +551,19 @@ namespace FaultyDtorCalledByDelete {
                               // both-note {{in call to 'abc()'}}
 }
 
+namespace DeleteThis {
+  constexpr bool super_secret_double_delete() {
+    struct A {
+      constexpr ~A() { delete this; } // both-note {{destruction of object that is already being destroyed}} \
+                                      // ref-note {{in call to}}
+    };
+    delete new A; // both-note {{in call to}}
+    return true;
+  }
+  static_assert(super_secret_double_delete()); // both-error {{not an integral constant expression}} \
+                                               // both-note {{in call to 'super_secret_double_delete()'}}
+}
+
 
 #else
 /// Make sure we reject this prior to C++20



More information about the cfe-commits mailing list