Tested x86_64-pc-linux-gnu, applying to trunk.
-- 8< --
Here the internal guard variables that control whether to clean up the
structured binding variables were not living across the call to co_await
because they weren't promoted into the coroutine frame. The underlying
problem is using a TARGET_EXPR, which lives only for the full-expression, to
hold a value that needs to live as long as the variable itself. So
get_temp_regvar seems like a better fit. We also need to manually pushdecl
the guard variable so that it's visible to register_local_var_uses.
It might be better to use the wrap_temporary_cleanups mechanism for the main
variable, as we do for normal variables. But let's go with the simple fix
for now.
PR c++/124584
gcc/cp/ChangeLog:
* decl.cc (cp_finish_decl): Use get_temp_regvar for decomp guards.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/tuple-decomp-pr124584.C: New test.
---
gcc/cp/decl.cc | 15 +++---
.../torture/tuple-decomp-pr124584.C | 54 +++++++++++++++++++
2 files changed, 63 insertions(+), 6 deletions(-)
create mode 100644
gcc/testsuite/g++.dg/coroutines/torture/tuple-decomp-pr124584.C
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index dbe4fa44ce5..c2a75c669c7 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -10108,10 +10108,14 @@ cp_finish_decl (tree decl, tree init, bool
init_const_expr_p,
tree guard = NULL_TREE;
if (cleanups || cleanup)
{
- guard = get_internal_target_expr (boolean_false_node);
- add_stmt (guard);
- guard = TARGET_EXPR_SLOT (guard);
+ /* Since the CLEANUP_STMT will refer to the guard, we need it
+ to be a variable with the same lifetime. ??? It might be
+ better to use wrap_temporary_cleanups. */
+ guard = get_temp_regvar (boolean_type_node,
boolean_false_node);
+ /* And make sure register_local_var_uses sees it. */
+ pushdecl (guard);
}
+
tree sl = push_stmt_list ();
initialize_local_var (decl, init, true);
if (guard)
@@ -10137,9 +10141,8 @@ cp_finish_decl (tree decl, tree init, bool
init_const_expr_p,
popped that all, so push those extra cleanups around
the whole sequence with a guard variable. */
gcc_assert (TREE_CODE (sl) == STATEMENT_LIST);
- guard = get_internal_target_expr (integer_zero_node);
- add_stmt (guard);
- guard = TARGET_EXPR_SLOT (guard);
+ guard = get_temp_regvar (integer_type_node,
integer_zero_node);
+ pushdecl (guard);
for (unsigned i = 0; i < n_extra_cleanups; ++i)
{
tree_stmt_iterator tsi = tsi_last (sl);
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/tuple-decomp-pr124584.C
b/gcc/testsuite/g++.dg/coroutines/torture/tuple-decomp-pr124584.C
new file mode 100644
index 00000000000..8679d52bf09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/tuple-decomp-pr124584.C
@@ -0,0 +1,54 @@
+#include <coroutine>
+#include <tuple>
+
+static int g_dtor_count = 0;
+
+struct guard {
+ bool live_ = true;
+ ~guard() { if (live_) ++g_dtor_count; }
+ guard() = default;
+ guard(guard&& o) noexcept
+ : live_(o.live_) {o.live_ = false;}
+};
+
+static std::coroutine_handle<> g_pending;
+
+struct yield_aw {
+ bool await_ready() const noexcept { return false; }
+ void await_suspend(std::coroutine_handle<> h) noexcept
+ { g_pending = h; }
+ void await_resume() const noexcept {}
+};
+
+struct task {
+ struct promise_type {
+ task get_return_object() noexcept {
+ return {std::coroutine_handle<
+ promise_type>::from_promise(*this)};
+ }
+ std::suspend_never initial_suspend() noexcept { return {}; }
+ std::suspend_always final_suspend() noexcept { return {}; }
+ void return_void() noexcept {}
+ void unhandled_exception() { __builtin_abort(); }
+ };
+ std::coroutine_handle<promise_type> h_;
+ ~task() { if (h_) h_.destroy(); }
+};
+
+std::tuple<guard> make_guarded_tuple() { return {guard{}}; }
+
+task test_fn() {
+ auto [g] = make_guarded_tuple(); // not co_await
+ co_await yield_aw{}; // binding crosses suspend
+ (void)g;
+}
+
+int main() {
+ auto t = test_fn();
+ auto h = g_pending;
+ g_pending = nullptr;
+ h.resume();
+ __builtin_printf("dtor_count = %d %s\n",
+ g_dtor_count, g_dtor_count > 0 ? "OK" : "BUG");
+ return g_dtor_count > 0 ? 0 : 1;
+}
base-commit: 7b5a05667c8e40bec5e070b1638d3b3882f7c78e
--
2.54.0