https://gcc.gnu.org/g:53c832282690ca1cd86e2eaf0128c70ba4edfc0f
commit r16-1916-g53c832282690ca1cd86e2eaf0128c70ba4edfc0f Author: Jason Merrill <ja...@redhat.com> Date: Wed Jul 2 18:03:57 2025 -0400 c++: uninitialized TARGET_EXPR and constexpr [PR120684] In r15-7532 for PR118856 I introduced a TARGET_EXPR with a TARGET_EXPR_INITIAL of void_node to express that no initialization is done. And indeed evaluating that doesn't store a value for the TARGET_EXPR_SLOT variable. But then at the end of the full-expression, destroy_value stores void_node to express that its lifetime has ended. If we evaluate the same full-expression again, global_ctx->values still holds the void_node, causing confusion when we try to destroy it again. So clear out any value before evaluating a TARGET_EXPR_INITIAL of void_type. PR c++/120684 PR c++/118856 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_constant_expression) [TARGET_EXPR]: Clear the value first if is_complex. gcc/testsuite/ChangeLog: * g++.dg/cpp23/range-for10.C: New test. Diff: --- gcc/cp/constexpr.cc | 10 ++++++++-- gcc/testsuite/g++.dg/cpp23/range-for10.C | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 704d936f2ec3..f9066bc79322 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -8114,14 +8114,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ctx->global->put_value (new_ctx.object, new_ctx.ctor); ctx = &new_ctx; } + + /* If the initializer is complex, evaluate it to initialize slot. */ + bool is_complex = target_expr_needs_replace (t); + if (is_complex) + /* In case no initialization actually happens, clear out any + void_node from a previous evaluation. */ + ctx->global->put_value (slot, NULL_TREE); + /* Pass vc_prvalue because this indicates initialization of a temporary. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) break; - /* If the initializer is complex, evaluate it to initialize slot. */ - bool is_complex = target_expr_needs_replace (t); if (!is_complex) { r = unshare_constructor (r); diff --git a/gcc/testsuite/g++.dg/cpp23/range-for10.C b/gcc/testsuite/g++.dg/cpp23/range-for10.C new file mode 100644 index 000000000000..96eab006c327 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for10.C @@ -0,0 +1,23 @@ +// PR c++/120684 +// { dg-do compile { target c++20 } } + +struct basic_string { + constexpr ~basic_string() {} +}; +template <typename _Vp> struct lazy_split_view { + _Vp _M_base; + constexpr int* begin() { return nullptr; } + constexpr int* end() { return nullptr; } +}; +constexpr void test_with_piping() { + basic_string input; + for (auto e : lazy_split_view(input)) + ; +} +constexpr bool main_test() { + test_with_piping(); + test_with_piping(); + return true; +} +//int main() { main_test(); } +static_assert(main_test());