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 --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 1ed3aba..60c0c9d 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8021,14 +8021,20 @@
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 0000000..96eab00
--- /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());