[clang] [clang][Interp] Correctly emit destructors for multi-dimensional arrays (PR #69140)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 26 05:12:57 PDT 2023
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?= <tbaeder at 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
+}
More information about the cfe-commits
mailing list