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

Reply via email to