Skip to content

Commit e01efdd

Browse files
authored
[clang][Interp] Correctly emit destructors for multi-dimensional arrays (#69140)
We were not taking those into account correctly when emitting destructors. Fix that and add tests for it. Fixes #69115
1 parent e27ff89 commit e01efdd

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,19 +2732,28 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Descriptor *Desc) {
27322732
// Arrays.
27332733
if (Desc->isArray()) {
27342734
const Descriptor *ElemDesc = Desc->ElemDesc;
2735-
const Record *ElemRecord = ElemDesc->ElemRecord;
2736-
assert(ElemRecord); // This is not a primitive array.
2735+
assert(ElemDesc);
2736+
2737+
// Don't need to do anything for these.
2738+
if (ElemDesc->isPrimitiveArray())
2739+
return this->emitPopPtr(SourceInfo{});
2740+
2741+
// If this is an array of record types, check if we need
2742+
// to call the element destructors at all. If not, try
2743+
// to save the work.
2744+
if (const Record *ElemRecord = ElemDesc->ElemRecord) {
2745+
if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
2746+
!Dtor || Dtor->isTrivial())
2747+
return this->emitPopPtr(SourceInfo{});
2748+
}
27372749

2738-
if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
2739-
Dtor && !Dtor->isTrivial()) {
2740-
for (ssize_t I = Desc->getNumElems() - 1; I >= 0; --I) {
2741-
if (!this->emitConstUint64(I, SourceInfo{}))
2742-
return false;
2743-
if (!this->emitArrayElemPtrUint64(SourceInfo{}))
2744-
return false;
2745-
if (!this->emitRecordDestruction(Desc->ElemDesc))
2746-
return false;
2747-
}
2750+
for (ssize_t I = Desc->getNumElems() - 1; I >= 0; --I) {
2751+
if (!this->emitConstUint64(I, SourceInfo{}))
2752+
return false;
2753+
if (!this->emitArrayElemPtrUint64(SourceInfo{}))
2754+
return false;
2755+
if (!this->emitRecordDestruction(ElemDesc))
2756+
return false;
27482757
}
27492758
return this->emitPopPtr(SourceInfo{});
27502759
}

clang/test/AST/Interp/arrays.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
2+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
23
// RUN: %clang_cc1 -verify=ref %s
4+
// RUN: %clang_cc1 -verify=ref -std=c++20 %s
35

46
constexpr int m = 3;
57
constexpr const int *foo[][5] = {
@@ -497,3 +499,58 @@ namespace Incomplete {
497499
// expected-error {{must be initialized by a constant expression}} \
498500
// expected-note {{read of non-constexpr variable 'arr'}}
499501
}
502+
503+
namespace GH69115 {
504+
/// This used to crash because we were trying to emit destructors for the
505+
/// array.
506+
constexpr int foo() {
507+
int arr[2][2] = {1, 2, 3, 4};
508+
return 0;
509+
}
510+
static_assert(foo() == 0, "");
511+
512+
/// Test that we still emit the destructors for multi-dimensional
513+
/// composite arrays.
514+
#if __cplusplus >= 202002L
515+
constexpr void assert(bool C) {
516+
if (C)
517+
return;
518+
// Invalid in constexpr.
519+
(void)(1 / 0); // expected-warning {{undefined}} \
520+
// ref-warning {{undefined}}
521+
}
522+
523+
class F {
524+
public:
525+
int a;
526+
int *dtor;
527+
int &idx;
528+
constexpr F(int a, int *dtor, int &idx) : a(a), dtor(dtor), idx(idx) {}
529+
constexpr ~F() noexcept(false){
530+
dtor[idx] = a;
531+
++idx;
532+
}
533+
};
534+
constexpr int foo2() {
535+
int dtorIndices[] = {0, 0, 0, 0};
536+
int idx = 0;
537+
538+
{
539+
F arr[2][2] = {F(1, dtorIndices, idx),
540+
F(2, dtorIndices, idx),
541+
F(3, dtorIndices, idx),
542+
F(4, dtorIndices, idx)};
543+
}
544+
545+
/// Reverse-reverse order.
546+
assert(idx == 4);
547+
assert(dtorIndices[0] == 4);
548+
assert(dtorIndices[1] == 3);
549+
assert(dtorIndices[2] == 2);
550+
assert(dtorIndices[3] == 1);
551+
552+
return 0;
553+
}
554+
static_assert(foo2() == 0, "");
555+
#endif
556+
}

0 commit comments

Comments
 (0)