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());

Reply via email to