Skip to content

Conversation

@Fznamznon
Copy link
Contributor

@Fznamznon Fznamznon commented Dec 16, 2025

Due to missing parameters to EmitDeleteCall only size of a single array element was passed to delete[].

Reported by #170337 (comment)

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:modules C++20 modules and Clang Header Modules clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 16, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 16, 2025

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

Changes

Due to missing parameters only size of a single array element was passed.

Reported by #170337 (comment)


Full diff: https://github.com/llvm/llvm-project/pull/172513.diff

6 Files Affected:

  • (modified) clang/lib/CodeGen/CGClass.cpp (+6-3)
  • (modified) clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp (+24-12)
  • (modified) clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp (+4-4)
  • (added) clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp (+54)
  • (modified) clang/test/Modules/msvc-vector-deleting-destructors.cpp (+6-2)
  • (modified) clang/test/PCH/msvc-vector-deleting-destructors.cpp (+6-2)
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 826f5799bae3c..a5096506f0ab1 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1502,7 +1502,8 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
   if (Dtor->getArrayOperatorDelete()) {
     if (!Dtor->getGlobalArrayOperatorDelete()) {
       CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
     } else {
       // If global operator[] is set, the class had its own operator delete[].
       // In that case, check the 4th bit. If it is set, we need to call
@@ -1519,12 +1520,14 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
       CGF.Builder.CreateCondBr(ShouldCallGlobDelete, ClassDelete, GlobDelete);
       CGF.EmitBlock(ClassDelete);
       CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
       CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
 
       CGF.EmitBlock(GlobDelete);
       CGF.EmitDeleteCall(Dtor->getGlobalArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
     }
   } else {
     // No operators delete[] were found, so emit a trap.
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
index e8012abb79aee..cbce869fb21b6 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
@@ -217,9 +217,13 @@ void bar() {
 // CHECK-NEXT:   %[[ISFIRSTBITZERO:.*]] = icmp eq i32 %[[FIRSTBIT]], 0
 // CHECK-NEXT:   br i1 %[[ISFIRSTBITZERO]], label %dtor.continue, label %dtor.call_delete_after_array_destroy
 // CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT:     call void @"??_V@YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef 8)
-// X86-NEXT:     call void @"??_V@YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef 4)
-// CHECK-NEXT:   br label %dtor.continue
+// X64-NEXT:  %[[ARRSZ:.*]] = mul i64 8, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ:.*]] = mul i32 4, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT:  %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef %[[TOTALSZ]])
+// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef %[[TOTALSZ]])
+// CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.scalar:
 // X64-NEXT:   call void @"??1Parrot@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %[[LTHIS]])
 // X86-NEXT:   call x86_thiscallcc void @"??1Parrot@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %[[LTHIS]])
@@ -252,8 +256,12 @@ void bar() {
 // X86-NEXT: call void @"??_VHasOperatorDelete@@SAXPAX@Z"
 // CHECK-NEXT:   br label %dtor.continue
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// X64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
-// X86-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 8, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 4, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
 // CHECK-NEXT:   br label %dtor.continue
 
 
@@ -314,22 +322,26 @@ void foobartest() {
 // CHECK-NEXT:  %5 = icmp eq i32 %4, 0
 // CHECK-NEXT:  br i1 %5, label %dtor.continue, label %dtor.call_delete_after_array_destroy
 // CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
-// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
 // CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.scalar:
 // X64-NEXT:  call void @"??1Derived@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(16) %this1)
 // X86-NEXT:  call x86_thiscallcc void @"??1Derived@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(8) %this1)
-// CHECK-NEXT:  %6 = and i32 %should_call_delete2, 1
-// CHECK-NEXT:  %7 = icmp eq i32 %6, 0
-// CHECK-NEXT:  br i1 %7, label %dtor.continue, label %dtor.call_delete
+// CHECK-NEXT:  %8 = and i32 %should_call_delete2, 1
+// CHECK-NEXT:  %9 = icmp eq i32 %8, 0
+// CHECK-NEXT:  br i1 %9, label %dtor.continue, label %dtor.call_delete
 // CHECK: dtor.call_delete:
 // X64-NEXT:  call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
 // X86-NEXT:  call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.continue:
-// CHECK-NEXT:  %8 = load ptr, ptr %retval
-// CHECK-NEXT:  ret ptr %8
+// CHECK-NEXT:  %10 = load ptr, ptr %retval
+// CHECK-NEXT:  ret ptr %10
 
 // X64: define weak dso_local noundef ptr @"??_EAllocatedAsArray@@UEAAPEAXI@Z"
 // X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EAllocatedAsArray@@UAEPAXI@Z"
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
index 1b1564227c40f..b16cb30d7133f 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
@@ -59,9 +59,9 @@ void TesttheTest() {
 // X64: define weak dso_local noundef ptr @"??_EDrawingBuffer@@UEAAPEAXI@Z"
 // X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
 // X64: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPEAX@Z"(ptr noundef %2)
-// X64: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
+// X64: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %{{.*}})
 // X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
-// X64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 8)
+// X64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef {{.*}})
 
 
 // X86: define dso_local void @"??3@YAXPAXI@Z"(ptr noundef %0, i32 noundef %1)
@@ -70,9 +70,9 @@ void TesttheTest() {
 // X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EDrawingBuffer@@UAEPAXI@Z"
 // X86: call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %arraydestroy.element)
 // X86: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPAX@Z"(ptr noundef %2)
-// X86: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X86: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef {{.*}})
 // X86  call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this1)
-// X86: call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 4)
+// X86: call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef {{.*}})
 
 
 // X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI@Z"(ptr noundef nonnull align 8 dereferenceable(8) %this, i32 noundef %should_call_delete)
diff --git a/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
new file mode 100644
index 0000000000000..6c9faa88e08e9
--- /dev/null
+++ b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=x86_64-pc-windows-msvc -o - | FileCheck --check-prefixes=X64,CHECK %s
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=i386-pc-windows-msvc -o - | FileCheck --check-prefixes=X86,CHECK %s
+
+using size_t = __SIZE_TYPE__;
+void operator delete[](void *ptr, size_t sz) { }
+
+struct Test {
+  virtual ~Test() {}
+  void operator delete[](void *ptr, size_t sz) {  }
+  int x;
+  int y;
+};
+
+void test() {
+  Test* a = new Test[10];
+  delete[] a;
+}
+
+// X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI@Z"(
+// X64-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_ETest@@UAEPAXI@Z"(
+// X86-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// CHECK: entry:
+// CHECK-NEXT:   %[[RET:.*]] = alloca ptr
+// CHECK-NEXT:   %[[IPADDR:.*]] = alloca i32
+// CHECK-NEXT:   %[[THISADDR:.*]] = alloca ptr
+// CHECK-NEXT:   store i32 %[[IMPLICIT_PARAM]], ptr %[[IPADDR]]
+// CHECK-NEXT:   store ptr %[[THIS]], ptr %[[THISADDR]]
+// CHECK-NEXT:   %[[LTHIS:.*]] = load ptr, ptr %[[THISADDR]]
+// CHECK-NEXT:   store ptr %[[LTHIS]], ptr %[[RET]]
+// CHECK-NEXT:   %[[LIP:.*]] = load i32, ptr %[[IPADDR]]
+// CHECK-NEXT:   %[[SECONDBIT:.*]] = and i32 %[[LIP]], 2
+// CHECK-NEXT:   %[[ISSECONDBITZERO:.*]] = icmp eq i32 %[[SECONDBIT]], 0
+// CHECK-NEXT:   br i1 %[[ISSECONDBITZERO:.*]], label %dtor.scalar, label %dtor.vector
+// CHECK: dtor.vector:
+// X64-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i64 -8
+// X86-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i32 -4
+// X64-NEXT:   %[[HOWMANY:.*]] = load i64, ptr %[[COOKIEGEP]]
+// X86-NEXT:   %[[HOWMANY:.*]] = load i32, ptr %[[COOKIEGEP]]
+// CHECK: dtor.call_class_delete_after_array_destroy:
+// X64-NEXT:  %[[ARRSZ:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT:  %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:   call void @"??_VTest@@SAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT:   call void @"??_VTest@@SAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+
+// CHECK: dtor.call_glob_delete_after_array_destroy:
+// X64-NEXT:  %[[ARRSZ1:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ1:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ1:.*]] = add i64 %[[ARRSZ1]], 8
+// X86-NEXT:  %[[TOTALSZ1:.*]] = add i32 %[[ARRSZ1]], 4
+// X64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ1]])
+// X86-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ1]])
diff --git a/clang/test/Modules/msvc-vector-deleting-destructors.cpp b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
index a0806054355db..68faa687251d7 100644
--- a/clang/test/Modules/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
@@ -20,8 +20,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
 // CHECK32-NEXT:  call void @"??_VBase1@@SAXPAX@Z"(ptr noundef %2)
 // CHECK64-NEXT:  call void @"??_VBase1@@SAXPEAX@Z"(ptr noundef %2)
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
 // CHECK: dtor.call_glob_delete:
 // CHECK32-NEXT:   call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK64-NEXT:   call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
diff --git a/clang/test/PCH/msvc-vector-deleting-destructors.cpp b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
index f548dba8efd20..1409b41d2df82 100644
--- a/clang/test/PCH/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
@@ -24,8 +24,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
 // CHECK32-NEXT:  call void @"??_VBase1@@SAXPAX@Z"(ptr noundef %2)
 // CHECK64-NEXT:  call void @"??_VBase1@@SAXPEAX@Z"(ptr noundef %2)
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
 // CHECK: dtor.call_glob_delete:
 // CHECK32-NEXT:   call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK64-NEXT:   call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)

@llvmbot
Copy link
Member

llvmbot commented Dec 16, 2025

@llvm/pr-subscribers-clang-codegen

Author: Mariya Podchishchaeva (Fznamznon)

Changes

Due to missing parameters only size of a single array element was passed.

Reported by #170337 (comment)


Full diff: https://github.com/llvm/llvm-project/pull/172513.diff

6 Files Affected:

  • (modified) clang/lib/CodeGen/CGClass.cpp (+6-3)
  • (modified) clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp (+24-12)
  • (modified) clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp (+4-4)
  • (added) clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp (+54)
  • (modified) clang/test/Modules/msvc-vector-deleting-destructors.cpp (+6-2)
  • (modified) clang/test/PCH/msvc-vector-deleting-destructors.cpp (+6-2)
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 826f5799bae3c..a5096506f0ab1 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1502,7 +1502,8 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
   if (Dtor->getArrayOperatorDelete()) {
     if (!Dtor->getGlobalArrayOperatorDelete()) {
       CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
     } else {
       // If global operator[] is set, the class had its own operator delete[].
       // In that case, check the 4th bit. If it is set, we need to call
@@ -1519,12 +1520,14 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
       CGF.Builder.CreateCondBr(ShouldCallGlobDelete, ClassDelete, GlobDelete);
       CGF.EmitBlock(ClassDelete);
       CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
       CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
 
       CGF.EmitBlock(GlobDelete);
       CGF.EmitDeleteCall(Dtor->getGlobalArrayOperatorDelete(), allocatedPtr,
-                         CGF.getContext().getCanonicalTagType(ClassDecl));
+                         CGF.getContext().getCanonicalTagType(ClassDecl),
+                         numElements, cookieSize);
     }
   } else {
     // No operators delete[] were found, so emit a trap.
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
index e8012abb79aee..cbce869fb21b6 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
@@ -217,9 +217,13 @@ void bar() {
 // CHECK-NEXT:   %[[ISFIRSTBITZERO:.*]] = icmp eq i32 %[[FIRSTBIT]], 0
 // CHECK-NEXT:   br i1 %[[ISFIRSTBITZERO]], label %dtor.continue, label %dtor.call_delete_after_array_destroy
 // CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT:     call void @"??_V@YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef 8)
-// X86-NEXT:     call void @"??_V@YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef 4)
-// CHECK-NEXT:   br label %dtor.continue
+// X64-NEXT:  %[[ARRSZ:.*]] = mul i64 8, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ:.*]] = mul i32 4, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT:  %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef %[[TOTALSZ]])
+// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef %[[TOTALSZ]])
+// CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.scalar:
 // X64-NEXT:   call void @"??1Parrot@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %[[LTHIS]])
 // X86-NEXT:   call x86_thiscallcc void @"??1Parrot@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %[[LTHIS]])
@@ -252,8 +256,12 @@ void bar() {
 // X86-NEXT: call void @"??_VHasOperatorDelete@@SAXPAX@Z"
 // CHECK-NEXT:   br label %dtor.continue
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// X64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
-// X86-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 8, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 4, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
 // CHECK-NEXT:   br label %dtor.continue
 
 
@@ -314,22 +322,26 @@ void foobartest() {
 // CHECK-NEXT:  %5 = icmp eq i32 %4, 0
 // CHECK-NEXT:  br i1 %5, label %dtor.continue, label %dtor.call_delete_after_array_destroy
 // CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
-// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:  call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT:  call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
 // CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.scalar:
 // X64-NEXT:  call void @"??1Derived@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(16) %this1)
 // X86-NEXT:  call x86_thiscallcc void @"??1Derived@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(8) %this1)
-// CHECK-NEXT:  %6 = and i32 %should_call_delete2, 1
-// CHECK-NEXT:  %7 = icmp eq i32 %6, 0
-// CHECK-NEXT:  br i1 %7, label %dtor.continue, label %dtor.call_delete
+// CHECK-NEXT:  %8 = and i32 %should_call_delete2, 1
+// CHECK-NEXT:  %9 = icmp eq i32 %8, 0
+// CHECK-NEXT:  br i1 %9, label %dtor.continue, label %dtor.call_delete
 // CHECK: dtor.call_delete:
 // X64-NEXT:  call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
 // X86-NEXT:  call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK-NEXT:  br label %dtor.continue
 // CHECK: dtor.continue:
-// CHECK-NEXT:  %8 = load ptr, ptr %retval
-// CHECK-NEXT:  ret ptr %8
+// CHECK-NEXT:  %10 = load ptr, ptr %retval
+// CHECK-NEXT:  ret ptr %10
 
 // X64: define weak dso_local noundef ptr @"??_EAllocatedAsArray@@UEAAPEAXI@Z"
 // X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EAllocatedAsArray@@UAEPAXI@Z"
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
index 1b1564227c40f..b16cb30d7133f 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
@@ -59,9 +59,9 @@ void TesttheTest() {
 // X64: define weak dso_local noundef ptr @"??_EDrawingBuffer@@UEAAPEAXI@Z"
 // X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
 // X64: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPEAX@Z"(ptr noundef %2)
-// X64: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
+// X64: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %{{.*}})
 // X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
-// X64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 8)
+// X64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef {{.*}})
 
 
 // X86: define dso_local void @"??3@YAXPAXI@Z"(ptr noundef %0, i32 noundef %1)
@@ -70,9 +70,9 @@ void TesttheTest() {
 // X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EDrawingBuffer@@UAEPAXI@Z"
 // X86: call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %arraydestroy.element)
 // X86: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPAX@Z"(ptr noundef %2)
-// X86: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X86: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef {{.*}})
 // X86  call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this1)
-// X86: call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 4)
+// X86: call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef {{.*}})
 
 
 // X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI@Z"(ptr noundef nonnull align 8 dereferenceable(8) %this, i32 noundef %should_call_delete)
diff --git a/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
new file mode 100644
index 0000000000000..6c9faa88e08e9
--- /dev/null
+++ b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=x86_64-pc-windows-msvc -o - | FileCheck --check-prefixes=X64,CHECK %s
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=i386-pc-windows-msvc -o - | FileCheck --check-prefixes=X86,CHECK %s
+
+using size_t = __SIZE_TYPE__;
+void operator delete[](void *ptr, size_t sz) { }
+
+struct Test {
+  virtual ~Test() {}
+  void operator delete[](void *ptr, size_t sz) {  }
+  int x;
+  int y;
+};
+
+void test() {
+  Test* a = new Test[10];
+  delete[] a;
+}
+
+// X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI@Z"(
+// X64-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_ETest@@UAEPAXI@Z"(
+// X86-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// CHECK: entry:
+// CHECK-NEXT:   %[[RET:.*]] = alloca ptr
+// CHECK-NEXT:   %[[IPADDR:.*]] = alloca i32
+// CHECK-NEXT:   %[[THISADDR:.*]] = alloca ptr
+// CHECK-NEXT:   store i32 %[[IMPLICIT_PARAM]], ptr %[[IPADDR]]
+// CHECK-NEXT:   store ptr %[[THIS]], ptr %[[THISADDR]]
+// CHECK-NEXT:   %[[LTHIS:.*]] = load ptr, ptr %[[THISADDR]]
+// CHECK-NEXT:   store ptr %[[LTHIS]], ptr %[[RET]]
+// CHECK-NEXT:   %[[LIP:.*]] = load i32, ptr %[[IPADDR]]
+// CHECK-NEXT:   %[[SECONDBIT:.*]] = and i32 %[[LIP]], 2
+// CHECK-NEXT:   %[[ISSECONDBITZERO:.*]] = icmp eq i32 %[[SECONDBIT]], 0
+// CHECK-NEXT:   br i1 %[[ISSECONDBITZERO:.*]], label %dtor.scalar, label %dtor.vector
+// CHECK: dtor.vector:
+// X64-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i64 -8
+// X86-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i32 -4
+// X64-NEXT:   %[[HOWMANY:.*]] = load i64, ptr %[[COOKIEGEP]]
+// X86-NEXT:   %[[HOWMANY:.*]] = load i32, ptr %[[COOKIEGEP]]
+// CHECK: dtor.call_class_delete_after_array_destroy:
+// X64-NEXT:  %[[ARRSZ:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT:  %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT:   call void @"??_VTest@@SAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT:   call void @"??_VTest@@SAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+
+// CHECK: dtor.call_glob_delete_after_array_destroy:
+// X64-NEXT:  %[[ARRSZ1:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT:  %[[ARRSZ1:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT:  %[[TOTALSZ1:.*]] = add i64 %[[ARRSZ1]], 8
+// X86-NEXT:  %[[TOTALSZ1:.*]] = add i32 %[[ARRSZ1]], 4
+// X64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ1]])
+// X86-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ1]])
diff --git a/clang/test/Modules/msvc-vector-deleting-destructors.cpp b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
index a0806054355db..68faa687251d7 100644
--- a/clang/test/Modules/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
@@ -20,8 +20,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
 // CHECK32-NEXT:  call void @"??_VBase1@@SAXPAX@Z"(ptr noundef %2)
 // CHECK64-NEXT:  call void @"??_VBase1@@SAXPEAX@Z"(ptr noundef %2)
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
 // CHECK: dtor.call_glob_delete:
 // CHECK32-NEXT:   call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK64-NEXT:   call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
diff --git a/clang/test/PCH/msvc-vector-deleting-destructors.cpp b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
index f548dba8efd20..1409b41d2df82 100644
--- a/clang/test/PCH/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
@@ -24,8 +24,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
 // CHECK32-NEXT:  call void @"??_VBase1@@SAXPAX@Z"(ptr noundef %2)
 // CHECK64-NEXT:  call void @"??_VBase1@@SAXPEAX@Z"(ptr noundef %2)
 // CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT:   call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT:   call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
 // CHECK: dtor.call_glob_delete:
 // CHECK32-NEXT:   call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
 // CHECK64-NEXT:   call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@zmodem zmodem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the quick fix!

@Fznamznon Fznamznon merged commit b512c19 into llvm:main Dec 17, 2025
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:codegen IR generation bugs: mangling, exceptions, etc. clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants