Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
27 changes: 3 additions & 24 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
32 changes: 25 additions & 7 deletions clang/test/CodeGenCXX/delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down