diff --git a/src/interpret.c b/src/interpret.c index 5ed81b62ab..2ed40a75ad 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -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) { diff --git a/src/pending_changes/gh-521-string-init-local-array-loop.txt b/src/pending_changes/gh-521-string-init-local-array-loop.txt new file mode 100644 index 0000000000..f12ebf4a0a --- /dev/null +++ b/src/pending_changes/gh-521-string-init-local-array-loop.txt @@ -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. diff --git a/tests/tests/regressions/.gh-521.rto/default.1.1.txt b/tests/tests/regressions/.gh-521.rto/default.1.1.txt new file mode 100644 index 0000000000..b921d6c913 --- /dev/null +++ b/tests/tests/regressions/.gh-521.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 --c++14 Test_name.c diff --git a/tests/tests/regressions/.gh-521.rto/default.2.1.txt b/tests/tests/regressions/.gh-521.rto/default.2.1.txt new file mode 100644 index 0000000000..0038ee1203 --- /dev/null +++ b/tests/tests/regressions/.gh-521.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 --c++20 Test_name.c diff --git a/tests/tests/regressions/gh-521.sft.cpp b/tests/tests/regressions/gh-521.sft.cpp new file mode 100644 index 0000000000..867b1e7724 --- /dev/null +++ b/tests/tests/regressions/gh-521.sft.cpp @@ -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'), "");