https://github.com/hvdijk updated 
https://github.com/llvm/llvm-project/pull/150359

>From 0f98715c538b32268ff3061c27221384ffee1eb3 Mon Sep 17 00:00:00 2001
From: Harald van Dijk <har...@gigawatt.nl>
Date: Thu, 24 Jul 2025 03:04:09 +0100
Subject: [PATCH 1/3] clang: Handle deleting pointers to incomplete array types

CodeGenFunction::EmitCXXDeleteExpr contains logic to go from a pointer
to an array to a pointer to the first element of the array using a
getelementptr LLVM IR instruction. This was done for pointers that were
not variable length arrays, as pointers to variable length arrays never
existed in LLVM IR, but rather than checking for arrays that were not
variable length arrays, it checked for arrays that had a constant bound.
This caused incomplete arrays to be inadvertently omitted.

This getelementptr was necessary back when LLVM IR used typed pointers,
but they have been gone for a while, a gep with a constant zero offset
does nothing now, so we can simplify the code by removing that.
---
 clang/docs/ReleaseNotes.rst      |  1 +
 clang/lib/CodeGen/CGExprCXX.cpp  | 28 +++++-----------------------
 clang/test/CodeGenCXX/delete.cpp | 32 +++++++++++++++++++++++++-------
 3 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index dd6b44dd0c657..af68fa099c917 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -819,6 +819,7 @@ Bug Fixes in This Version
   in different locations (#GH134404, #GH146976).
 - Fix a crash when marco name is empty in ``#pragma push_macro("")`` or
   ``#pragma pop_macro("")``. (GH149762).
+- Fix a crash when deleting a pointer to an incomplete array.
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 359e30cb8f5cd..888be7e468bb3 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2146,30 +2146,12 @@ void CodeGenFunction::EmitCXXDeleteExpr(const 
CXXDeleteExpr *E) {
     return;
   }
 
-  // We might be deleting a pointer to array.  If so, GEP down to the
-  // first non-array element.
-  // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*)
-  if (DeleteTy->isConstantArrayType()) {
-    llvm::Value *Zero = Builder.getInt32(0);
-    SmallVector<llvm::Value*,8> GEP;
-
-    GEP.push_back(Zero); // point at the outermost array
-
-    // For each layer of array type we're pointing at:
-    while (const ConstantArrayType *Arr
-             = getContext().getAsConstantArrayType(DeleteTy)) {
-      // 1. Unpeel the array type.
-      DeleteTy = Arr->getElementType();
-
-      // 2. GEP to the first element of the array.
-      GEP.push_back(Zero);
-    }
-
-    Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, ConvertTypeForMem(DeleteTy),
-                                    Ptr.getAlignment(), "del.first");
+  // We might be deleting a pointer to array.
+  while (const ArrayType *Arr = getContext().getAsArrayType(DeleteTy)) {
+    // Unpeel the array type.
+    DeleteTy = Arr->getElementType();
   }
-
-  assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType());
+  Ptr = Ptr.withElementType(ConvertTypeForMem(DeleteTy));
 
   if (E->isArrayForm()) {
     EmitArrayDelete(*this, E, Ptr, DeleteTy);
diff --git a/clang/test/CodeGenCXX/delete.cpp b/clang/test/CodeGenCXX/delete.cpp
index d5b0dc6712910..21b9f8c2fcc2c 100644
--- a/clang/test/CodeGenCXX/delete.cpp
+++ b/clang/test/CodeGenCXX/delete.cpp
@@ -76,27 +76,45 @@ namespace test1 {
     ~A();
   };
 
-  // CHECK-LABEL: define{{.*}} void @_ZN5test14testEPA10_A20_NS_1AE(
-  void test(A (*arr)[10][20]) {
+  // CHECK-LABEL: define{{.*}} void @_ZN5test11fEPA10_A20_NS_1AE(
+  void f(A (*arr)[10][20]) {
     delete [] arr;
     // CHECK:      icmp eq ptr [[PTR:%.*]], null
     // CHECK-NEXT: br i1
 
-    // CHECK:      [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x 
[[A:%.*]]]], ptr [[PTR]], i32 0, i32 0, i32 0
-    // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[BEGIN]], 
i64 -8
+    // CHECK:      [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 
-8
     // CHECK-NEXT: [[COUNT:%.*]] = load i64, ptr [[ALLOC]]
-    // CHECK:      [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], 
i64 [[COUNT]]
-    // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[BEGIN]], [[END]]
+    // CHECK:      [[END:%.*]] = getelementptr inbounds [[A:%.*]], ptr 
[[PTR]], i64 [[COUNT]]
+    // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[PTR]], [[END]]
     // CHECK-NEXT: br i1 [[ISEMPTY]],
     // CHECK:      [[PAST:%.*]] = phi ptr [ [[END]], {{%.*}} ], [ [[CUR:%.*]], 
{{%.*}} ]
     // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[PAST]], 
i64 -1
     // CHECK-NEXT: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[CUR]])
-    // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[BEGIN]]
+    // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[PTR]]
     // CHECK-NEXT: br i1 [[ISDONE]]
     // CHECK:      [[MUL:%.*]] = mul i64 4, [[COUNT]]
     // CHECK-NEXT: [[SIZE:%.*]] = add i64 [[MUL]], 8
     // CHECK-NEXT: call void @_ZdaPvm(ptr noundef [[ALLOC]], i64 noundef 
[[SIZE]])
   }
+
+  // CHECK-LABEL: define{{.*}} void @_ZN5test11gEPA_NS_1AE(
+  void g(A (*arr)[]) {
+    delete [] arr;
+    // CHECK:      icmp eq ptr [[PTR:%.*]], null
+    // CHECK-NEXT: br i1
+
+    // CHECK:      [[ALLOC:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 
-8
+    // CHECK-NEXT: [[COUNT:%.*]] = load i64, ptr [[ALLOC]]
+    // CHECK:      [[END:%.*]] = getelementptr inbounds [[A:%.*]], ptr 
[[PTR]], i64 [[COUNT]]
+    // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq ptr [[PTR]], [[END]]
+    // CHECK-NEXT: br i1 [[ISEMPTY]],
+    // CHECK:      [[PAST:%.*]] = phi ptr [ [[END]], {{%.*}} ], [ [[CUR:%.*]], 
{{%.*}} ]
+    // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[PAST]], 
i64 -1
+    // CHECK-NEXT: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[CUR]])
+    // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq ptr [[CUR]], [[PTR]]
+    // CHECK-NEXT: br i1 [[ISDONE]]
+    // CHECK:      call void @_ZdaPv(ptr noundef [[ALLOC]])
+  }
 }
 
 namespace test2 {

>From 345f149874f1777b3df6f1eb73d7c603ce46ff3d Mon Sep 17 00:00:00 2001
From: Harald van Dijk <har...@gigawatt.nl>
Date: Thu, 24 Jul 2025 03:07:00 +0100
Subject: [PATCH 2/3] Include PR number.

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index af68fa099c917..af409d9b43473 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -819,7 +819,7 @@ Bug Fixes in This Version
   in different locations (#GH134404, #GH146976).
 - Fix a crash when marco name is empty in ``#pragma push_macro("")`` or
   ``#pragma pop_macro("")``. (GH149762).
-- Fix a crash when deleting a pointer to an incomplete array.
+- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>From a2abd1eb8d002cf5b1080e4cbc60e2d6cf0c75be Mon Sep 17 00:00:00 2001
From: Harald van Dijk <har...@gigawatt.nl>
Date: Thu, 24 Jul 2025 18:10:35 +0100
Subject: [PATCH 3/3] Use getContext().getBaseElementType(DeleteTy).

---
 clang/lib/CodeGen/CGExprCXX.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 888be7e468bb3..b8238a4702c4d 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2147,10 +2147,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const 
CXXDeleteExpr *E) {
   }
 
   // We might be deleting a pointer to array.
-  while (const ArrayType *Arr = getContext().getAsArrayType(DeleteTy)) {
-    // Unpeel the array type.
-    DeleteTy = Arr->getElementType();
-  }
+  DeleteTy = getContext().getBaseElementType(DeleteTy);
   Ptr = Ptr.withElementType(ConvertTypeForMem(DeleteTy));
 
   if (E->isArrayForm()) {

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

Reply via email to