https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/69140
>From 8476b0b2b2666310048fe58dbd2e1ffc7a0fb21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 16 Oct 2023 06:09:36 +0200 Subject: [PATCH] [clang][Interp] Correctly emit destructors for multi-dimensional arrays We were not taking those into account correctly when emitting destructors. Fix that and add tests for it. Fixes #69115 --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 33 +++++++++----- clang/test/AST/Interp/arrays.cpp | 57 ++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 1b33c69b93aa4b9..93156a9794cb6a4 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2720,19 +2720,28 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Descriptor *Desc) { // Arrays. if (Desc->isArray()) { const Descriptor *ElemDesc = Desc->ElemDesc; - const Record *ElemRecord = ElemDesc->ElemRecord; - assert(ElemRecord); // This is not a primitive array. + assert(ElemDesc); + + // Don't need to do anything for these. + if (ElemDesc->isPrimitiveArray()) + return this->emitPopPtr(SourceInfo{}); + + // If this is an array of record types, check if we need + // to call the element destructors at all. If not, try + // to save the work. + if (const Record *ElemRecord = ElemDesc->ElemRecord) { + if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor(); + !Dtor || Dtor->isTrivial()) + return this->emitPopPtr(SourceInfo{}); + } - if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor(); - Dtor && !Dtor->isTrivial()) { - for (ssize_t I = Desc->getNumElems() - 1; I >= 0; --I) { - if (!this->emitConstUint64(I, SourceInfo{})) - return false; - if (!this->emitArrayElemPtrUint64(SourceInfo{})) - return false; - if (!this->emitRecordDestruction(Desc->ElemDesc)) - return false; - } + for (ssize_t I = Desc->getNumElems() - 1; I >= 0; --I) { + if (!this->emitConstUint64(I, SourceInfo{})) + return false; + if (!this->emitArrayElemPtrUint64(SourceInfo{})) + return false; + if (!this->emitRecordDestruction(ElemDesc)) + return false; } return this->emitPopPtr(SourceInfo{}); } diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 7110785ea4c662a..ed92609d812729e 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s // RUN: %clang_cc1 -verify=ref %s +// RUN: %clang_cc1 -verify=ref -std=c++20 %s constexpr int m = 3; constexpr const int *foo[][5] = { @@ -455,3 +457,58 @@ namespace NoInitMapLeak { // ref-error {{not an integral constant expression}} \ // ref-note {{in call to}} } + +namespace GH69115 { + /// This used to crash because we were trying to emit destructors for the + /// array. + constexpr int foo() { + int arr[2][2] = {1, 2, 3, 4}; + return 0; + } + static_assert(foo() == 0, ""); + + /// Test that we still emit the destructors for multi-dimensional + /// composite arrays. +#if __cplusplus >= 202002L + constexpr void assert(bool C) { + if (C) + return; + // Invalid in constexpr. + (void)(1 / 0); // expected-warning {{undefined}} \ + // ref-warning {{undefined}} + } + + class F { + public: + int a; + int *dtor; + int &idx; + constexpr F(int a, int *dtor, int &idx) : a(a), dtor(dtor), idx(idx) {} + constexpr ~F() noexcept(false){ + dtor[idx] = a; + ++idx; + } + }; + constexpr int foo2() { + int dtorIndices[] = {0, 0, 0, 0}; + int idx = 0; + + { + F arr[2][2] = {F(1, dtorIndices, idx), + F(2, dtorIndices, idx), + F(3, dtorIndices, idx), + F(4, dtorIndices, idx)}; + } + + /// Reverse-reverse order. + assert(idx == 4); + assert(dtorIndices[0] == 4); + assert(dtorIndices[1] == 3); + assert(dtorIndices[2] == 2); + assert(dtorIndices[3] == 1); + + return 0; + } + static_assert(foo2() == 0, ""); +#endif +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits