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
22 changes: 13 additions & 9 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -6005,9 +6005,11 @@ Perform the destructions for the current storage stack.
check_assertion(result);
nonvirtual = TRUE;
} /* if */
for (int k = 0; k<n; ++k, sub_obj += size) {
if (!do_constexpr_dtor(ips, dtor, pos, sub_obj, complete_obj,
nonvirtual)) {
/* The elements of an array are destroyed in reverse order. */
for (int k = n; k > 0; --k) {
if (!do_constexpr_dtor(ips, dtor, pos,
sub_obj + (a_byte_count)(k-1)*size,
complete_obj, nonvirtual)) {
result = FALSE;
goto done;
} /* if */
Expand Down Expand Up @@ -24147,8 +24149,9 @@ the iwp_1st_resume visit destroys the subobjects and undoes that mapping.
get_mapped_byte_count(&persistent_map, bcp, offset);
sub_dip = dtor_init->initializer;
} /* if */
sub_bytes = result_storage+offset;
for (int k = 0; k<n; ++k) {
/* The elements of an array are destroyed in reverse order. */
for (int k = n; k > 0; --k) {
sub_bytes = result_storage+offset+(a_byte_count)(k-1)*elem_size;
/* Clear the derivation/active-field state. */
*(void**)sub_bytes = NULL;
if (!do_constexpr_dtor(ips, sub_dip->destructor, pos, sub_bytes,
Expand All @@ -24158,7 +24161,6 @@ the iwp_1st_resume visit destroys the subobjects and undoes that mapping.
} else {
mark_subobject_uninitialized(sub_bytes, complete_object);
} /* if */
sub_bytes += elem_size;
} /* for */
} /* for */
if (!mark_whole_subobject_uninitialized(ips, result_storage, class_type,
Expand Down Expand Up @@ -26655,14 +26657,16 @@ Evaluate the given delete-expression.
} else {
/* Perform necessary destructions and mark subobject uninitialized. */
a_dynamic_init_ptr dip = ndsp->dynamic_init;
a_byte_count k = 0, length = allocation->length, elem_size;
a_byte_count k, length = allocation->length, elem_size;
a_byte *arr = (a_byte*)allocation+allocation->prefix_size,
*elem = arr;
*elem;
a_type_ptr elem_type = skip_typerefs(allocation->elem_type);
elem_size = value_bytes_for_type(ips, elem_type, &result);
if (!result) goto done;
unmark_complete_object_initialized(arr);
for (; k<length; ++k, elem += elem_size) {
/* The elements of an array are destroyed in reverse order. */
for (k = length; k > 0; --k) {
elem = arr + (k-1)*elem_size;
if (dip != NULL) {
/* Run the destructor. For the non-array case, this might be a virtual
call: Make sure we start from the original address since
Expand Down
23 changes: 23 additions & 0 deletions src/pending_changes/gh-400-array-destruction-order.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[GH #400]
Order of destruction of array elements in constant evaluation

During constant evaluation, the elements of an array (including an array
member and an array destroyed by a delete[] expression) were destroyed in
increasing order of their index instead of in decreasing order. For
example, with --c++20:

struct S {
int* log;
int id;
constexpr ~S() { *log = *log * 10 + id; }
};
constexpr int f() {
int log = 0;
{
S a[3] = {{&log, 1}, {&log, 2}, {&log, 3}};
}
return log;
}
static_assert(f() == 321); // Previously failed.

This is now fixed.
1 change: 1 addition & 0 deletions tests/tests/changes/.gh-400.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c
68 changes: 68 additions & 0 deletions tests/tests/changes/gh-400.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//type:fp
//options:--c++20
//remark:[GH #400] Constant evaluation destroys array elements in decreasing
//remark:order of their index

struct S {
int* log;
int id;
constexpr ~S() { *log = *log * 10 + id; }
};

constexpr int local_array() {
int log = 0;
{
S a[3] = {{&log, 1}, {&log, 2}, {&log, 3}};
}
return log;
}
static_assert(local_array() == 321); // Previously failed.

constexpr int multidim_array() {
int log = 0;
{
S a[2][2] = {{{&log, 1}, {&log, 2}}, {{&log, 3}, {&log, 4}}};
}
return log;
}
static_assert(multidim_array() == 4321); // Previously failed.

struct M { S m[3]; };
constexpr int member_array() {
int log = 0;
{
M x = {{{&log, 1}, {&log, 2}, {&log, 3}}};
}
return log;
}
static_assert(member_array() == 321); // Previously failed.

struct N {
S m[2];
constexpr N(int* log) : m{{log, 1}, {log, 2}} {}
constexpr ~N() { *m[0].log = *m[0].log * 10 + 9; }
};
constexpr int member_array_user_dtor() {
int log = 0;
{
N x(&log);
}
return log;
}
static_assert(member_array_user_dtor() == 921); // Previously failed.

constexpr int array_delete() {
int log = 0;
S* p = new S[3]{{&log, 1}, {&log, 2}, {&log, 3}};
delete[] p;
return log;
}
static_assert(array_delete() == 321); // Previously failed.

constexpr int single_delete() {
int log = 0;
S* p = new S{&log, 5};
delete p;
return log;
}
static_assert(single_delete() == 5);
Loading