https://gcc.gnu.org/g:960e68941db7412cfdfb429161d77db206a06acc
commit r17-650-g960e68941db7412cfdfb429161d77db206a06acc Author: Jakub Jelinek <[email protected]> Date: Thu May 21 16:26:22 2026 +0200 c++: Fix up handling of name independent decls in coroutine lowering [PR125376] For variables which do have non-NULL DECL_NAME, register_local_var_uses uses either that name or name_depth_idx (that itself is a bug as it can clash with user variables named that way) for the fields. In C++26 we can have multiple _ variables in the same scope, so the following testcase is miscompiled by using the same FIELD_DECL multiple times (once for the first _ variable, once for the second one). The following patch fixes it by pretending such variables don't have a name, so it uses a serial number then instead. 2026-05-21 Jakub Jelinek <[email protected]> PR c++/125376 * coroutines.cc (register_local_var_uses): Ignore DECL_NAME for name independent decls. * g++.dg/coroutines/pr125376.C: New test. Diff: --- gcc/cp/coroutines.cc | 2 ++ gcc/testsuite/g++.dg/coroutines/pr125376.C | 40 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 6bc58a4f2e68..de0de7a83e04 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4403,6 +4403,8 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) identify them in the coroutine frame. */ tree lvname = DECL_NAME (lvar); char *buf = NULL; + if (name_independent_decl_p (lvar)) + lvname = NULL_TREE; /* The outermost bind scope contains the artificial variables that we inject to implement the coro state machine. We want to be able diff --git a/gcc/testsuite/g++.dg/coroutines/pr125376.C b/gcc/testsuite/g++.dg/coroutines/pr125376.C new file mode 100644 index 000000000000..432bf04cea5e --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr125376.C @@ -0,0 +1,40 @@ +// PR c++/125376 +// { dg-do run { target c++26 } } + +#include <coroutine> + +struct task { + struct promise_type { + task get_return_object () noexcept { return {}; } + std::suspend_never initial_suspend () noexcept { return {}; } + std::suspend_never final_suspend () noexcept { return {}; } + void return_void () noexcept {} + void unhandled_exception () {} + }; +}; + +struct A { + unsigned value = 42; + A () {} + ~A () { if (value != 42) __builtin_abort (); } +}; + +struct B { + unsigned value = 43; + B () {} + ~B () { if (value != 43) __builtin_abort (); } +}; + +task +foo () +{ + auto _ = A {}; + auto _ = B {}; + co_return; +} + +int +main () +{ + foo (); +}
