Skip to content
Open
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
16 changes: 14 additions & 2 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -27437,8 +27437,20 @@ a reused value, if any, in the iwp_1st_resume visit.
switch (dip->kind) {
case dik_constant:
case dik_nonconstant_aggregate:
result = extract_value_from_constant(ips, dip->variant.constant.ptr,
dst_addr, implied_src);
{ a_constant_ptr cp = dip->variant.constant.ptr;
result = extract_value_from_constant(ips, cp, dst_addr, implied_src);
if (constant_is(cp, ck_string)) {
/* The ck_string contents were copied to the array being initialized.
Undo the mapping of the array storage to the ck_string entry
since it is not a persistent association (the storage may be
initialized again, e.g., in the next iteration of a loop). */
a_byte *mapped;
get_stack_bytes(ips, dst_addr.address, mapped);
if (mapped == (a_byte*)cp) {
unmap_stack_bytes(ips, dst_addr.address);
} /* if */
} /* if */
}
break;
case dik_lambda:
if (constexpr_lambdas_enabled) {
Expand Down
18 changes: 18 additions & 0 deletions src/pending_changes/gh-521-string-init-local-array-loop.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[GH #521]
Constant evaluation of repeated initializations of an array from a string

When constant evaluation initialized a local array from a string literal, it
left the storage of the array associated with the string literal. If the same
storage was initialized again (e.g., in the next iteration of a loop), the
front end could fail with the internal error "duplicate map key in
interpreter". For example:

constexpr int f() {
int r = 0;
for (int i = 0; i < 2; ++i) {
char a[2] = "a";
r += a[0];
}
return r;
}
static_assert(f() == 2*'a'); // Previously an internal error.
1 change: 1 addition & 0 deletions tests/tests/regressions/.gh-521.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c++14 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/regressions/.gh-521.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=2 --c++20 Test_name.c
40 changes: 40 additions & 0 deletions tests/tests/regressions/gh-521.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//type:fp
//options:--c++14:--c++20
//remark:Repeated constexpr initialization of a local array from a string

// Initializing a local array from a string literal must not leave its storage
// associated with the string literal: The same storage is initialized again
// in the next iteration of a loop.

constexpr int f() {
int r = 0;
for (int i = 0; i < 2; ++i) {
char a[2] = "a";
r += a[0];
}
return r;
}
static_assert(f() == 2*'a', "");

constexpr int g() {
int r = 0;
for (int i = 0; i < 3; ++i) {
char a[4] = "abc";
a[i] = 'x';
r = r*256 + a[0];
}
return r;
}
static_assert(g() == ('x'*256 + 'a')*256 + 'a', "");

constexpr long h() {
long r = 0;
for (int i = 0; i < 2; ++i) {
const char a[] = "ab";
char16_t b[3] = u"cd";
wchar_t c[4] = L"ef";
r += a[1] + b[1] + c[1];
}
return r;
}
static_assert(h() == 2*('b' + u'd' + L'f'), "");
Loading