]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: uninitialized TARGET_EXPR and constexpr [PR120684]
authorJason Merrill <jason@redhat.com>
Wed, 2 Jul 2025 22:03:57 +0000 (18:03 -0400)
committerJason Merrill <jason@redhat.com>
Thu, 3 Jul 2025 03:55:51 +0000 (23:55 -0400)
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
gcc/testsuite/g++.dg/cpp23/range-for10.C [new file with mode: 0644]

index 704d936f2ec318eeff8b93943a90e4e733fdadb3..f9066bc79322e1210894ae26d6ddca2b4536ef88 100644 (file)
@@ -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 (file)
index 0000000..96eab00
--- /dev/null
@@ -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());