Author: Harald van Dijk
Date: 2025-07-24T18:43:17+01:00
New Revision: 2228b4b46c3e45b5aab801a636041ed13ae47375

URL: 
https://github.com/llvm/llvm-project/commit/2228b4b46c3e45b5aab801a636041ed13ae47375
DIFF: 
https://github.com/llvm/llvm-project/commit/2228b4b46c3e45b5aab801a636041ed13ae47375.diff

LOG: clang: Handle deleting pointers to incomplete array types (#150359)

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.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/CodeGen/CGExprCXX.cpp
    clang/test/CodeGenCXX/delete.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 381d0ef42f433..ec51ffddce1af 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -134,6 +134,7 @@ Bug Fixes to C++ Support
 ^^^^^^^^^^^^^^^^^^^^^^^^
 - Diagnose binding a reference to ``*nullptr`` during constant evaluation. 
(#GH48665)
 - Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. 
(#GH147293)
+- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 359e30cb8f5cd..b8238a4702c4d 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2146,30 +2146,9 @@ 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");
-  }
-
-  assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType());
+  // We might be deleting a pointer to array.
+  DeleteTy = getContext().getBaseElementType(DeleteTy);
+  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 {


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

Reply via email to