Tested x86_64-pc-linux-gnu, applying to trunk. -- 8< --
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. --- gcc/cp/constexpr.cc | 10 ++++++++-- gcc/testsuite/g++.dg/cpp23/range-for10.C | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/range-for10.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 704d936f2ec..f9066bc7932 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 00000000000..96eab006c32 --- /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()); base-commit: dc2797bb44333d5588c14d51c918df51c664d46c -- 2.49.0