On Tue, Sep 3, 2024 at 8:11 PM Arsen Arsenović <ar...@aarsen.me> wrote: > > Tested on x86_64-pc-linux-gnu. OK for trunk?
OK > ---------- >8 ---------- > We rely on .CO_YIELD calls being followed by an assignment (optionally) > and then a switch/if in the same basic block. This implies that a > .CO_YIELD can never end a block. However, since a call to .CO_YIELD is > still a call, if the function containing it calls setjmp, GCC thinks > that the .CO_YIELD can introduce abnormal control flow, and generates an > edge for the call. > > We know this is not the case; .CO_YIELD calls get removed quite early on > and have no effect, and result in no other calls, so .CO_YIELD can be > considered a leaf function, preventing generating an edge when calling > it. > > PR c++/106973 - coroutine generator and setjmp > > PR c++/106973 > > gcc/ChangeLog: > > * internal-fn.def (CO_YIELD): Mark as ECF_LEAF. > > gcc/testsuite/ChangeLog: > > * g++.dg/coroutines/pr106973.C: New test. > --- > gcc/internal-fn.def | 2 +- > gcc/testsuite/g++.dg/coroutines/pr106973.C | 22 ++++++++++++++++++++++ > 2 files changed, 23 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/coroutines/pr106973.C > > diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def > index 75b527b1ab0b..23b4ab02b300 100644 > --- a/gcc/internal-fn.def > +++ b/gcc/internal-fn.def > @@ -569,7 +569,7 @@ DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL) > > /* For coroutines. */ > DEF_INTERNAL_FN (CO_ACTOR, ECF_NOTHROW | ECF_LEAF, NULL) > -DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW, NULL) > +DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW | ECF_LEAF, NULL) > DEF_INTERNAL_FN (CO_SUSPN, ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (CO_FRAME, ECF_PURE | ECF_NOTHROW | ECF_LEAF, NULL) > > diff --git a/gcc/testsuite/g++.dg/coroutines/pr106973.C > b/gcc/testsuite/g++.dg/coroutines/pr106973.C > new file mode 100644 > index 000000000000..6db6cbc7711a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/coroutines/pr106973.C > @@ -0,0 +1,22 @@ > +// https://gcc.gnu.org/PR106973 > +// { dg-require-effective-target indirect_jumps } > +#include <coroutine> > +#include <setjmp.h> > + > +struct generator; > +struct generator_promise { > + generator get_return_object(); > + std::suspend_always initial_suspend(); > + std::suspend_always final_suspend() noexcept; > + std::suspend_always yield_value(int); > + void unhandled_exception(); > +}; > + > +struct generator { > + using promise_type = generator_promise; > +}; > +jmp_buf foo_env; > +generator foo() { > + setjmp(foo_env); > + co_yield 1; > +} > -- > 2.46.0 >