Author: Timm Baeder
Date: 2025-07-10T07:33:33+02:00
New Revision: 36cbd43ae8d5a5274ae3193b6383fff2ba9671f4

URL: 
https://github.com/llvm/llvm-project/commit/36cbd43ae8d5a5274ae3193b6383fff2ba9671f4
DIFF: 
https://github.com/llvm/llvm-project/commit/36cbd43ae8d5a5274ae3193b6383fff2ba9671f4.diff

LOG: [clang][bytecode] Check new/delete mismatch earlier (#147732)

This fixes a mismatch in diagnostic output with the current intepreter.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Interp.cpp
    clang/test/AST/ByteCode/new-delete.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 51cf0c59f0b50..be77657acabcc 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1196,6 +1196,8 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
   if (!CheckDynamicMemoryAllocation(S, OpPC))
     return false;
 
+  DynamicAllocator &Allocator = S.getAllocator();
+
   const Expr *Source = nullptr;
   const Block *BlockToDelete = nullptr;
   {
@@ -1212,6 +1214,21 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
     while (Ptr.isBaseClass())
       Ptr = Ptr.getBase();
 
+    Source = Ptr.getDeclDesc()->asExpr();
+    BlockToDelete = Ptr.block();
+
+    // Check that new[]/delete[] or new/delete were used, not a mixture.
+    const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
+    if (std::optional<DynamicAllocator::Form> AllocForm =
+            Allocator.getAllocationForm(Source)) {
+      DynamicAllocator::Form DeleteForm =
+          DeleteIsArrayForm ? DynamicAllocator::Form::Array
+                            : DynamicAllocator::Form::NonArray;
+      if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
+                               Source))
+        return false;
+    }
+
     // For the non-array case, the types must match if the static type
     // does not have a virtual destructor.
     if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
@@ -1230,9 +1247,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
       return false;
     }
 
-    Source = Ptr.getDeclDesc()->asExpr();
-    BlockToDelete = Ptr.block();
-
     if (!CheckDeleteSource(S, OpPC, Source, Ptr))
       return false;
 
@@ -1266,11 +1280,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
   if (!RunDestructors(S, OpPC, BlockToDelete))
     return false;
 
-  DynamicAllocator &Allocator = S.getAllocator();
-  const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
-  std::optional<DynamicAllocator::Form> AllocForm =
-      Allocator.getAllocationForm(Source);
-
   if (!Allocator.deallocate(Source, BlockToDelete, S)) {
     // Nothing has been deallocated, this must be a double-delete.
     const SourceInfo &Loc = S.Current->getSource(OpPC);
@@ -1278,12 +1287,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
     return false;
   }
 
-  assert(AllocForm);
-  DynamicAllocator::Form DeleteForm = DeleteIsArrayForm
-                                          ? DynamicAllocator::Form::Array
-                                          : DynamicAllocator::Form::NonArray;
-  return CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
-                             Source);
+  return true;
 }
 
 void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,

diff  --git a/clang/test/AST/ByteCode/new-delete.cpp 
b/clang/test/AST/ByteCode/new-delete.cpp
index 840736f332250..3c0bdbc8c99fe 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -171,6 +171,20 @@ namespace Arrays {
   }
   static_assert(mismatch2() == 6); // both-error {{not an integral constant 
expression}} \
                                    // both-note {{in call to 'mismatch2()'}}
+
+  constexpr int mismatch3() { // both-error {{never produces a constant 
expression}}
+    int a = 0;
+    struct S {};
+    struct T : S {};
+    T *p = new T[3]{}; // both-note 2{{heap allocation performed here}}
+    delete (S*)p; // both-note 2{{non-array delete used to delete pointer to 
array object of type 'T[3]'}}
+
+    return 0;
+
+  }
+  static_assert(mismatch3() == 0); // both-error {{not an integral constant 
expression}} \
+                                   // both-note {{in call to}}
+
   /// Array of composite elements.
   constexpr int foo() {
     S *ss = new S[12];


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to