https://gcc.gnu.org/g:a1855a3e0bcf0f94bc9fa421ccc9ebd0565c62cd
commit r15-7503-ga1855a3e0bcf0f94bc9fa421ccc9ebd0565c62cd Author: Jakub Jelinek <ja...@redhat.com> Date: Thu Feb 13 11:53:04 2025 +0100 testsuite: Add another range for coroutines testcase [PR118574] This patch adds another range for coroutine testcase, which doesn't extend (across co_await) just the __for_range var and what it binds to (so passes even without -frange-for-ext-temps), but also some other temporaries and verifies they are destructed in the right order. 2025-02-13 Jakub Jelinek <ja...@redhat.com> PR c++/118574 * g++.dg/coroutines/range-for2.C: New test. Diff: --- gcc/testsuite/g++.dg/coroutines/range-for2.C | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/gcc/testsuite/g++.dg/coroutines/range-for2.C b/gcc/testsuite/g++.dg/coroutines/range-for2.C new file mode 100644 index 000000000000..14372f39855a --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/range-for2.C @@ -0,0 +1,92 @@ +// PR c++/118574 +// { dg-do run } +// { dg-additional-options "-std=c++23 -O2" } + +#include <coroutine> + +[[gnu::noipa]] void +baz (int *) +{ +} + +struct D { + D () : d (new int (42)) {} + ~D () { if (*d != 42) __builtin_abort (); *d = 0; baz (d); delete d; } + int *d; +}; + +struct E { + E (const D &x) : e (x) {} + void test () const { if (*e.d != 42) __builtin_abort (); } + ~E () { test (); } + const D &e; +}; + +struct A { + const char **a = nullptr; + int n = 0; + const E *e1 = nullptr; + const E *e2 = nullptr; + void test () const { if (e1) e1->test (); if (e2) e2->test (); } + void push_back (const char *x) { test (); if (!a) a = new const char *[2]; a[n++] = x; } + const char **begin () const { test (); return a; } + const char **end () const { test (); return a + n; } + ~A () { test (); delete[] a; } +}; + +struct B { + long ns; + bool await_ready () const noexcept { return false; } + void await_suspend (std::coroutine_handle<> h) const noexcept { + volatile int v = 0; + while (v < ns) + v = v + 1; + h.resume (); + } + void await_resume () const noexcept {} +}; + +struct C { + struct promise_type { + const char *value; + std::suspend_never initial_suspend () { return {}; } + std::suspend_always final_suspend () noexcept { return {}; } + void return_value (const char *v) { value = v; } + void unhandled_exception () { __builtin_abort (); } + C get_return_object () { return C{this}; } + }; + promise_type *p; + explicit C (promise_type *p) : p(p) {} + const char *get () { return p->value; } +}; + +A +foo (const E &e1, const E &e2) +{ + A a; + a.e1 = &e1; + a.e2 = &e2; + a.push_back ("foo"); + a.push_back ("bar"); + return a; +} + +C +bar () +{ + A ret; + for (const auto &item : foo (E{D {}}, E{D {}})) + { + co_await B{200000}; + ret.push_back (item); + } + co_return "foobar"; +} + +int +main () +{ + auto task = bar (); + if (__builtin_strcmp (task.get (), "foobar")) + __builtin_abort (); +}