Skip to content

Commit 2f08b84

Browse files
daveedvdv-nvidiawchilders-nvidia
authored andcommitted
Destroy array elements in decreasing order in constant evaluation [GH #400]
During constant evaluation, the elements of arrays (complete objects, array members, and arrays destroyed by a delete[] expression) are now destroyed in decreasing order of their index, instead of in increasing order.
1 parent bc7c97b commit 2f08b84

4 files changed

Lines changed: 105 additions & 9 deletions

File tree

‎src/interpret.c‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6005,9 +6005,11 @@ Perform the destructions for the current storage stack.
60056005
check_assertion(result);
60066006
nonvirtual = TRUE;
60076007
} /* if */
6008-
for (int k = 0; k<n; ++k, sub_obj += size) {
6009-
if (!do_constexpr_dtor(ips, dtor, pos, sub_obj, complete_obj,
6010-
nonvirtual)) {
6008+
/* The elements of an array are destroyed in reverse order. */
6009+
for (int k = n; k > 0; --k) {
6010+
if (!do_constexpr_dtor(ips, dtor, pos,
6011+
sub_obj + (a_byte_count)(k-1)*size,
6012+
complete_obj, nonvirtual)) {
60116013
result = FALSE;
60126014
goto done;
60136015
} /* if */
@@ -24147,8 +24149,9 @@ the iwp_1st_resume visit destroys the subobjects and undoes that mapping.
2414724149
get_mapped_byte_count(&persistent_map, bcp, offset);
2414824150
sub_dip = dtor_init->initializer;
2414924151
} /* if */
24150-
sub_bytes = result_storage+offset;
24151-
for (int k = 0; k<n; ++k) {
24152+
/* The elements of an array are destroyed in reverse order. */
24153+
for (int k = n; k > 0; --k) {
24154+
sub_bytes = result_storage+offset+(a_byte_count)(k-1)*elem_size;
2415224155
/* Clear the derivation/active-field state. */
2415324156
*(void**)sub_bytes = NULL;
2415424157
if (!do_constexpr_dtor(ips, sub_dip->destructor, pos, sub_bytes,
@@ -24158,7 +24161,6 @@ the iwp_1st_resume visit destroys the subobjects and undoes that mapping.
2415824161
} else {
2415924162
mark_subobject_uninitialized(sub_bytes, complete_object);
2416024163
} /* if */
24161-
sub_bytes += elem_size;
2416224164
} /* for */
2416324165
} /* for */
2416424166
if (!mark_whole_subobject_uninitialized(ips, result_storage, class_type,
@@ -26655,14 +26657,16 @@ Evaluate the given delete-expression.
2665526657
} else {
2665626658
/* Perform necessary destructions and mark subobject uninitialized. */
2665726659
a_dynamic_init_ptr dip = ndsp->dynamic_init;
26658-
a_byte_count k = 0, length = allocation->length, elem_size;
26660+
a_byte_count k, length = allocation->length, elem_size;
2665926661
a_byte *arr = (a_byte*)allocation+allocation->prefix_size,
26660-
*elem = arr;
26662+
*elem;
2666126663
a_type_ptr elem_type = skip_typerefs(allocation->elem_type);
2666226664
elem_size = value_bytes_for_type(ips, elem_type, &result);
2666326665
if (!result) goto done;
2666426666
unmark_complete_object_initialized(arr);
26665-
for (; k<length; ++k, elem += elem_size) {
26667+
/* The elements of an array are destroyed in reverse order. */
26668+
for (k = length; k > 0; --k) {
26669+
elem = arr + (k-1)*elem_size;
2666626670
if (dip != NULL) {
2666726671
/* Run the destructor. For the non-array case, this might be a virtual
2666826672
call: Make sure we start from the original address since
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[GH #400]
2+
Order of destruction of array elements in constant evaluation
3+
4+
During constant evaluation, the elements of an array (including an array
5+
member and an array destroyed by a delete[] expression) were destroyed in
6+
increasing order of their index instead of in decreasing order. For
7+
example, with --c++20:
8+
9+
struct S {
10+
int* log;
11+
int id;
12+
constexpr ~S() { *log = *log * 10 + id; }
13+
};
14+
constexpr int f() {
15+
int log = 0;
16+
{
17+
S a[3] = {{&log, 1}, {&log, 2}, {&log, 3}};
18+
}
19+
return log;
20+
}
21+
static_assert(f() == 321); // Previously failed.
22+
23+
This is now fixed.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c

‎tests/tests/changes/gh-400.sft.cpp‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//type:fp
2+
//options:--c++20
3+
//remark:[GH #400] Constant evaluation destroys array elements in decreasing
4+
//remark:order of their index
5+
6+
struct S {
7+
int* log;
8+
int id;
9+
constexpr ~S() { *log = *log * 10 + id; }
10+
};
11+
12+
constexpr int local_array() {
13+
int log = 0;
14+
{
15+
S a[3] = {{&log, 1}, {&log, 2}, {&log, 3}};
16+
}
17+
return log;
18+
}
19+
static_assert(local_array() == 321); // Previously failed.
20+
21+
constexpr int multidim_array() {
22+
int log = 0;
23+
{
24+
S a[2][2] = {{{&log, 1}, {&log, 2}}, {{&log, 3}, {&log, 4}}};
25+
}
26+
return log;
27+
}
28+
static_assert(multidim_array() == 4321); // Previously failed.
29+
30+
struct M { S m[3]; };
31+
constexpr int member_array() {
32+
int log = 0;
33+
{
34+
M x = {{{&log, 1}, {&log, 2}, {&log, 3}}};
35+
}
36+
return log;
37+
}
38+
static_assert(member_array() == 321); // Previously failed.
39+
40+
struct N {
41+
S m[2];
42+
constexpr N(int* log) : m{{log, 1}, {log, 2}} {}
43+
constexpr ~N() { *m[0].log = *m[0].log * 10 + 9; }
44+
};
45+
constexpr int member_array_user_dtor() {
46+
int log = 0;
47+
{
48+
N x(&log);
49+
}
50+
return log;
51+
}
52+
static_assert(member_array_user_dtor() == 921); // Previously failed.
53+
54+
constexpr int array_delete() {
55+
int log = 0;
56+
S* p = new S[3]{{&log, 1}, {&log, 2}, {&log, 3}};
57+
delete[] p;
58+
return log;
59+
}
60+
static_assert(array_delete() == 321); // Previously failed.
61+
62+
constexpr int single_delete() {
63+
int log = 0;
64+
S* p = new S{&log, 5};
65+
delete p;
66+
return log;
67+
}
68+
static_assert(single_delete() == 5);

0 commit comments

Comments
 (0)