[C++ coroutines 6/7, v2] Testsuite.

Richard Biener richard.guenther@gmail.com
Thu Jan 9 13:17:00 GMT 2020


On Thu, Jan 9, 2020 at 1:39 PM Iain Sandoe <iain@sandoe.co.uk> wrote:
>
> Richard Biener <richard.guenther@gmail.com> wrote:
>
> > On Sun, Nov 17, 2019 at 11:29 AM Iain Sandoe <iain@sandoe.co.uk> wrote:
> >> There are two categories of test:
> >>
> >> 1. Checks for correctly formed source code and the error reporting.
> >> 2. Checks for transformation and code-gen.
> >>
> >> The second set are run as 'torture' tests for the standard options
> >> set, including LTO.  These are also intentionally run with no options
> >> provided (from the coroutines.exp script).
> >
> > OK once the rest is approved.
>
> Amended version attached, for the record, with cleanups and more tests as
> needed to cover the other changes in the series.
>
> SVN commit IDs noted in the revised header.
> Still OK?

Sure.

> Iain
>
> ======
>
> There are two categories of test:
>
> 1. Checks for correctly formed source code and the error reporting.
> 2. Checks for transformation and code-gen.
>
> The second set are run as 'torture' tests for the standard options
> set, including LTO.  These are also intentionally run with no options
> provided (from the coroutines.exp script).
>
> Squashed commits:
>
> r278441 - Remove reference to an unused builtin from coro.h
> r278442 - Fix a code-gen error in coro_maybe_expand_co_return.
> r278453 - Address review comments, updated error message,
> r278480 - Address review comments, new tests
> r278776 - JAddress review comments, update to make move of coro header easier
> r279020 - Fix bug in handling co_return co_await.
> r279046 - more tidyup, also factor code.
> r279049 - add more co-await tests and rename to consistent.
> r279050 - Add more co-yield syntax tests.
> r279078 - More testsuite refactoring.
> r279080 - Fix a bug in type dependency checks.
> r279095 - More testsuite refactoring.
> r279099 - Update operator overload tests.
> r279190 - Update co-return tests.
> r279191 - Just fix a format warning.
> r279198 - Improve test coverage, initial class tests.
> r279245 - Test syntax error from lambda with auto return.
> r279318 - Test function-like lambdas.
> r279383 - Use correct dg options for new compile tests.
> r279385 - Fix PR 92933 unnamed locals.
> r279396 - Fix lambda capture of references.
> r279403 - Add testcase to cover non-constant param refs.
> r279462 - Fix a bug where await_resume methods return references.
> r279693 - Rename co-await testcases to be consistent [NFC].
> r279694 - Rename co-return testcases to be consistent [NFC].
> r279711 - Rename co-yield testcases to be consistent [NFC].
> r279712 - Rename func params testcases to be consistent [NFC].
> r279719 - Fix a typo in a testcase name.
> r279805 - Address review comments, prepare to move coroutine header.
> r279817 - Update copyright year.
> r280004 - Add promise overloads of new and delete.
>
> gcc/testsuite/ChangeLog:
>
> 2020-01-09  Iain Sandoe  <iain@sandoe.co.uk>
>
>         * g++.dg/coroutines/co-await-syntax-00-needs-expr.C: New test.
>         * g++.dg/coroutines/co-await-syntax-01-outside-fn.C: New test.
>         * g++.dg/coroutines/co-await-syntax-02-outside-fn.C: New test.
>         * g++.dg/coroutines/co-await-syntax-03-auto.C: New test.
>         * g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C: New test.
>         * g++.dg/coroutines/co-await-syntax-05-constexpr.C: New test.
>         * g++.dg/coroutines/co-await-syntax-06-main.C: New test.
>         * g++.dg/coroutines/co-await-syntax-07-varargs.C: New test.
>         * g++.dg/coroutines/co-await-syntax-08-lambda-auto.C: New test.
>         * g++.dg/coroutines/co-return-syntax-01-outside-fn.C: New test.
>         * g++.dg/coroutines/co-return-syntax-02-outside-fn.C: New test.
>         * g++.dg/coroutines/co-return-syntax-03-auto.C: New test.
>         * g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C: New test.
>         * g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C: New test.
>         * g++.dg/coroutines/co-return-syntax-06-main.C: New test.
>         * g++.dg/coroutines/co-return-syntax-07-vararg.C: New test.
>         * g++.dg/coroutines/co-return-syntax-08-bad-return.C: New test.
>         * g++.dg/coroutines/co-return-syntax-09-lambda-auto.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-00-needs-expr.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-01-outside-fn.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-02-outside-fn.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-03-auto.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-05-constexpr.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-06-main.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-07-varargs.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-08-needs-expr.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C: New test.
>         * g++.dg/coroutines/coro-builtins.C: New test.
>         * g++.dg/coroutines/coro-missing-gro.C: New test.
>         * g++.dg/coroutines/coro-missing-promise-yield.C: New test.
>         * g++.dg/coroutines/coro-missing-ret-value.C: New test.
>         * g++.dg/coroutines/coro-missing-ret-void.C: New test.
>         * g++.dg/coroutines/coro-missing-ueh-1.C: New test.
>         * g++.dg/coroutines/coro-missing-ueh-2.C: New test.
>         * g++.dg/coroutines/coro-missing-ueh-3.C: New test.
>         * g++.dg/coroutines/coro-missing-ueh.h: New test.
>         * g++.dg/coroutines/coro-pre-proc.C: New test.
>         * g++.dg/coroutines/coro.h: New file.
>         * g++.dg/coroutines/coro1-ret-int-yield-int.h: New file.
>         * g++.dg/coroutines/coroutines.exp: New file.
>         * g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C: New test.
>         * g++.dg/coroutines/torture/alloc-01-overload-newdel.C: New test.
>         * g++.dg/coroutines/torture/call-00-co-aw-arg.C: New test.
>         * g++.dg/coroutines/torture/call-01-multiple-co-aw.C: New test.
>         * g++.dg/coroutines/torture/call-02-temp-co-aw.C: New test.
>         * g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C: New test.
>         * g++.dg/coroutines/torture/class-00-co-ret.C: New test.
>         * g++.dg/coroutines/torture/class-01-co-ret-parm.C: New test.
>         * g++.dg/coroutines/torture/class-02-templ-parm.C: New test.
>         * g++.dg/coroutines/torture/class-03-operator-templ-parm.C: New test.
>         * g++.dg/coroutines/torture/class-04-lambda-1.C: New test.
>         * g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C: New test.
>         * g++.dg/coroutines/torture/class-06-lambda-capture-ref.C: New test.
>         * g++.dg/coroutines/torture/co-await-00-trivial.C: New test.
>         * g++.dg/coroutines/torture/co-await-01-with-value.C: New test.
>         * g++.dg/coroutines/torture/co-await-02-xform.C: New test.
>         * g++.dg/coroutines/torture/co-await-03-rhs-op.C: New test.
>         * g++.dg/coroutines/torture/co-await-04-control-flow.C: New test.
>         * g++.dg/coroutines/torture/co-await-05-loop.C: New test.
>         * g++.dg/coroutines/torture/co-await-06-ovl.C: New test.
>         * g++.dg/coroutines/torture/co-await-07-tmpl.C: New test.
>         * g++.dg/coroutines/torture/co-await-08-cascade.C: New test.
>         * g++.dg/coroutines/torture/co-await-09-pair.C: New test.
>         * g++.dg/coroutines/torture/co-await-10-template-fn-arg.C: New test.
>         * g++.dg/coroutines/torture/co-await-11-forwarding.C: New test.
>         * g++.dg/coroutines/torture/co-await-12-operator-2.C: New test.
>         * g++.dg/coroutines/torture/co-await-13-return-ref.C: New test.
>         * g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C: New test.
>         * g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C: New test.
>         * g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C: New test.
>         * g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C: New test.
>         * g++.dg/coroutines/torture/co-ret-05-return-value.C: New test.
>         * g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C: New test.
>         * g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C: New test.
>         * g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C: New test.
>         * g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C: New test.
>         * g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C: New test.
>         * g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C: New test.
>         * g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C: New test.
>         * g++.dg/coroutines/torture/co-ret-13-template-2.C: New test.
>         * g++.dg/coroutines/torture/co-ret-14-template-3.C: New test.
>         * g++.dg/coroutines/torture/co-yield-00-triv.C: New test.
>         * g++.dg/coroutines/torture/co-yield-01-multi.C: New test.
>         * g++.dg/coroutines/torture/co-yield-02-loop.C: New test.
>         * g++.dg/coroutines/torture/co-yield-03-tmpl.C: New test.
>         * g++.dg/coroutines/torture/co-yield-04-complex-local-state.C: New test.
>         * g++.dg/coroutines/torture/co-yield-05-co-aw.C: New test.
>         * g++.dg/coroutines/torture/co-yield-06-fun-parm.C: New test.
>         * g++.dg/coroutines/torture/co-yield-07-template-fn-param.C: New test.
>         * g++.dg/coroutines/torture/co-yield-08-more-refs.C: New test.
>         * g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C: New test.
>         * g++.dg/coroutines/torture/coro-torture.exp: New file.
>         * g++.dg/coroutines/torture/exceptions-test-0.C: New test.
>         * g++.dg/coroutines/torture/func-params-00.C: New test.
>         * g++.dg/coroutines/torture/func-params-01.C: New test.
>         * g++.dg/coroutines/torture/func-params-02.C: New test.
>         * g++.dg/coroutines/torture/func-params-03.C: New test.
>         * g++.dg/coroutines/torture/func-params-04.C: New test.
>         * g++.dg/coroutines/torture/func-params-05.C: New test.
>         * g++.dg/coroutines/torture/func-params-06.C: New test.
>         * g++.dg/coroutines/torture/lambda-00-co-ret.C: New test.
>         * g++.dg/coroutines/torture/lambda-01-co-ret-parm.C: New test.
>         * g++.dg/coroutines/torture/lambda-02-co-yield-values.C: New test.
>         * g++.dg/coroutines/torture/lambda-03-auto-parm-1.C: New test.
>         * g++.dg/coroutines/torture/lambda-04-templ-parm.C: New test.
>         * g++.dg/coroutines/torture/lambda-05-capture-copy-local.C: New test.
>         * g++.dg/coroutines/torture/lambda-06-multi-capture.C: New test.
>         * g++.dg/coroutines/torture/lambda-07-multi-yield.C: New test.
>         * g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C: New test.
>         * g++.dg/coroutines/torture/local-var-0.C: New test.
>         * g++.dg/coroutines/torture/local-var-1.C: New test.
>         * g++.dg/coroutines/torture/local-var-2.C: New test.
>         * g++.dg/coroutines/torture/local-var-3.C: New test.
>         * g++.dg/coroutines/torture/local-var-4.C: New test.
>         * g++.dg/coroutines/torture/mid-suspend-destruction-0.C: New test.
>         * g++.dg/coroutines/torture/pr92933.C: New test.
> ---
>  .../coroutines/co-await-syntax-00-needs-expr.C     |   7 +
>  .../coroutines/co-await-syntax-01-outside-fn.C     |   5 +
>  .../coroutines/co-await-syntax-02-outside-fn.C     |   5 +
>  .../g++.dg/coroutines/co-await-syntax-03-auto.C    |  16 ++
>  .../coroutines/co-await-syntax-04-ctor-dtor.C      |   8 +
>  .../coroutines/co-await-syntax-05-constexpr.C      |  12 ++
>  .../g++.dg/coroutines/co-await-syntax-06-main.C    |   7 +
>  .../g++.dg/coroutines/co-await-syntax-07-varargs.C |  14 ++
>  .../coroutines/co-await-syntax-08-lambda-auto.C    |  19 +++
>  .../coroutines/co-return-syntax-01-outside-fn.C    |   6 +
>  .../coroutines/co-return-syntax-02-outside-fn.C    |   5 +
>  .../g++.dg/coroutines/co-return-syntax-03-auto.C   |  12 ++
>  .../coroutines/co-return-syntax-04-ctor-dtor.C     |   8 +
>  .../coroutines/co-return-syntax-05-constexpr-fn.C  |  12 ++
>  .../g++.dg/coroutines/co-return-syntax-06-main.C   |   7 +
>  .../g++.dg/coroutines/co-return-syntax-07-vararg.C |  14 ++
>  .../coroutines/co-return-syntax-08-bad-return.C    |  43 ++++++
>  .../coroutines/co-return-syntax-09-lambda-auto.C   |  19 +++
>  .../coroutines/co-yield-syntax-00-needs-expr.C     |   7 +
>  .../coroutines/co-yield-syntax-01-outside-fn.C     |   6 +
>  .../coroutines/co-yield-syntax-02-outside-fn.C     |   6 +
>  .../g++.dg/coroutines/co-yield-syntax-03-auto.C    |  12 ++
>  .../coroutines/co-yield-syntax-04-ctor-dtor.C      |   8 +
>  .../coroutines/co-yield-syntax-05-constexpr.C      |  12 ++
>  .../g++.dg/coroutines/co-yield-syntax-06-main.C    |   7 +
>  .../g++.dg/coroutines/co-yield-syntax-07-varargs.C |  14 ++
>  .../coroutines/co-yield-syntax-08-needs-expr.C     |  37 +++++
>  .../coroutines/co-yield-syntax-09-lambda-auto.C    |  19 +++
>  gcc/testsuite/g++.dg/coroutines/coro-builtins.C    |  17 +++
>  gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C |  32 ++++
>  .../g++.dg/coroutines/coro-missing-promise-yield.C |  33 ++++
>  .../g++.dg/coroutines/coro-missing-ret-value.C     |  34 +++++
>  .../g++.dg/coroutines/coro-missing-ret-void.C      |  34 +++++
>  .../g++.dg/coroutines/coro-missing-ueh-1.C         |  17 +++
>  .../g++.dg/coroutines/coro-missing-ueh-2.C         |  18 +++
>  .../g++.dg/coroutines/coro-missing-ueh-3.C         |  18 +++
>  gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h |  23 +++
>  gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C    |   9 ++
>  gcc/testsuite/g++.dg/coroutines/coro.h             | 151 +++++++++++++++++++
>  .../g++.dg/coroutines/coro1-ret-int-yield-int.h    | 133 ++++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/coroutines.exp     |  50 ++++++
>  .../torture/alloc-00-gro-on-alloc-fail.C           | 118 +++++++++++++++
>  .../coroutines/torture/alloc-01-overload-newdel.C  | 120 +++++++++++++++
>  .../g++.dg/coroutines/torture/call-00-co-aw-arg.C  |  73 +++++++++
>  .../coroutines/torture/call-01-multiple-co-aw.C    |  73 +++++++++
>  .../g++.dg/coroutines/torture/call-02-temp-co-aw.C |  72 +++++++++
>  .../coroutines/torture/call-03-temp-ref-co-aw.C    |  72 +++++++++
>  .../g++.dg/coroutines/torture/class-00-co-ret.C    |  41 +++++
>  .../coroutines/torture/class-01-co-ret-parm.C      |  57 +++++++
>  .../coroutines/torture/class-02-templ-parm.C       |  52 +++++++
>  .../torture/class-03-operator-templ-parm.C         |  52 +++++++
>  .../g++.dg/coroutines/torture/class-04-lambda-1.C  |  58 +++++++
>  .../torture/class-05-lambda-capture-copy-local.C   |  59 ++++++++
>  .../torture/class-06-lambda-capture-ref.C          |  59 ++++++++
>  .../coroutines/torture/co-await-00-trivial.C       |  52 +++++++
>  .../coroutines/torture/co-await-01-with-value.C    |  57 +++++++
>  .../g++.dg/coroutines/torture/co-await-02-xform.C  |  58 +++++++
>  .../g++.dg/coroutines/torture/co-await-03-rhs-op.C |  58 +++++++
>  .../coroutines/torture/co-await-04-control-flow.C  |  50 ++++++
>  .../g++.dg/coroutines/torture/co-await-05-loop.C   |  51 +++++++
>  .../g++.dg/coroutines/torture/co-await-06-ovl.C    |  65 ++++++++
>  .../g++.dg/coroutines/torture/co-await-07-tmpl.C   | 132 ++++++++++++++++
>  .../coroutines/torture/co-await-08-cascade.C       |  63 ++++++++
>  .../g++.dg/coroutines/torture/co-await-09-pair.C   |  57 +++++++
>  .../torture/co-await-10-template-fn-arg.C          |  60 ++++++++
>  .../coroutines/torture/co-await-11-forwarding.C    |  43 ++++++
>  .../coroutines/torture/co-await-12-operator-2.C    |  66 ++++++++
>  .../coroutines/torture/co-await-13-return-ref.C    |  58 +++++++
>  .../torture/co-ret-00-void-return-is-ready.C       |  90 +++++++++++
>  .../torture/co-ret-01-void-return-is-suspend.C     |  94 ++++++++++++
>  .../torture/co-ret-03-different-GRO-type.C         |  92 ++++++++++++
>  .../coroutines/torture/co-ret-04-GRO-nontriv.C     | 109 ++++++++++++++
>  .../coroutines/torture/co-ret-05-return-value.C    |  38 +++++
>  .../torture/co-ret-06-template-promise-val-1.C     | 105 +++++++++++++
>  .../coroutines/torture/co-ret-07-void-cast-expr.C  |  44 ++++++
>  .../torture/co-ret-08-template-cast-ret.C          | 104 +++++++++++++
>  .../coroutines/torture/co-ret-09-bool-await-susp.C |  97 ++++++++++++
>  .../torture/co-ret-10-expression-evaluates-once.C  |  49 ++++++
>  .../coroutines/torture/co-ret-11-co-ret-co-await.C |  40 +++++
>  .../torture/co-ret-12-co-ret-fun-co-await.C        |  48 ++++++
>  .../coroutines/torture/co-ret-13-template-2.C      |  56 +++++++
>  .../coroutines/torture/co-ret-14-template-3.C      |  58 +++++++
>  .../g++.dg/coroutines/torture/co-yield-00-triv.C   | 129 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-01-multi.C  |  64 ++++++++
>  .../g++.dg/coroutines/torture/co-yield-02-loop.C   |  68 +++++++++
>  .../g++.dg/coroutines/torture/co-yield-03-tmpl.C   | 140 +++++++++++++++++
>  .../torture/co-yield-04-complex-local-state.C      | 162 ++++++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-05-co-aw.C  |  55 +++++++
>  .../coroutines/torture/co-yield-06-fun-parm.C      |  64 ++++++++
>  .../torture/co-yield-07-template-fn-param.C        |  71 +++++++++
>  .../coroutines/torture/co-yield-08-more-refs.C     |  68 +++++++++
>  .../torture/co-yield-09-more-templ-refs.C          |  68 +++++++++
>  .../g++.dg/coroutines/torture/coro-torture.exp     |  19 +++
>  .../g++.dg/coroutines/torture/exceptions-test-0.C  | 167 +++++++++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-00.C     |  42 ++++++
>  .../g++.dg/coroutines/torture/func-params-01.C     |  45 ++++++
>  .../g++.dg/coroutines/torture/func-params-02.C     |  50 ++++++
>  .../g++.dg/coroutines/torture/func-params-03.C     |  49 ++++++
>  .../g++.dg/coroutines/torture/func-params-04.C     |  57 +++++++
>  .../g++.dg/coroutines/torture/func-params-05.C     |  57 +++++++
>  .../g++.dg/coroutines/torture/func-params-06.C     |  47 ++++++
>  .../g++.dg/coroutines/torture/lambda-00-co-ret.C   |  35 +++++
>  .../coroutines/torture/lambda-01-co-ret-parm.C     |  48 ++++++
>  .../coroutines/torture/lambda-02-co-yield-values.C |  64 ++++++++
>  .../coroutines/torture/lambda-03-auto-parm-1.C     |  46 ++++++
>  .../coroutines/torture/lambda-04-templ-parm.C      |  47 ++++++
>  .../torture/lambda-05-capture-copy-local.C         |  66 ++++++++
>  .../coroutines/torture/lambda-06-multi-capture.C   |  48 ++++++
>  .../coroutines/torture/lambda-07-multi-yield.C     |  46 ++++++
>  .../coroutines/torture/lambda-08-co-ret-parm-ref.C |  59 ++++++++
>  .../g++.dg/coroutines/torture/local-var-0.C        |  37 +++++
>  .../g++.dg/coroutines/torture/local-var-1.C        |  37 +++++
>  .../g++.dg/coroutines/torture/local-var-2.C        |  50 ++++++
>  .../g++.dg/coroutines/torture/local-var-3.C        |  65 ++++++++
>  .../g++.dg/coroutines/torture/local-var-4.C        |  75 +++++++++
>  .../coroutines/torture/mid-suspend-destruction-0.C | 107 +++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/pr92933.C  |  18 +++
>  117 files changed, 5986 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-00-needs-expr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-01-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-03-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-05-constexpr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-06-main.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-07-varargs.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-08-lambda-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-01-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-02-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-03-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-06-main.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-07-vararg.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-return-syntax-09-lambda-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-00-needs-expr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-02-outside-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-03-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-05-constexpr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-06-main.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-07-varargs.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-08-needs-expr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-builtins.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ret-void.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro.h
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro1-ret-int-yield-int.h
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coroutines.exp
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/alloc-01-overload-newdel.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/call-00-co-aw-arg.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/call-01-multiple-co-aw.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/call-02-temp-co-aw.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-00-co-ret.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-01-co-ret-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-02-templ-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-03-operator-templ-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-04-lambda-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/class-06-lambda-capture-ref.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-00-trivial.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-01-with-value.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-02-xform.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-03-rhs-op.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-04-control-flow.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-05-loop.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-06-ovl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-07-tmpl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-08-cascade.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-09-pair.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-10-template-fn-arg.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-11-forwarding.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-12-operator-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-13-return-ref.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-05-return-value.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-13-template-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-14-template-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-00-triv.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-01-multi.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-02-loop.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-03-tmpl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-04-complex-local-state.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-05-co-aw.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-06-fun-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-07-template-fn-param.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-08-more-refs.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-00.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-01.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-02.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-03.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-04.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-05.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-06.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-00-co-ret.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-01-co-ret-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-02-co-yield-values.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-03-auto-parm-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-04-templ-parm.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-05-capture-copy-local.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-06-multi-capture.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-yield.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/pr92933.C
>
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-00-needs-expr.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-00-needs-expr.C
> new file mode 100644
> index 0000000000..d068c3d19a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-00-needs-expr.C
> @@ -0,0 +1,7 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +void bar () {
> +  co_await;  // { dg-error "expected primary-expression before" }
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-01-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-01-outside-fn.C
> new file mode 100644
> index 0000000000..484859c706
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-01-outside-fn.C
> @@ -0,0 +1,5 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int x = co_await coro::suspend_always{}; // { dg-error {'co_await' cannot be used outside a function} }
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C
> new file mode 100644
> index 0000000000..4ce5c2e04a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-02-outside-fn.C
> @@ -0,0 +1,5 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +auto f (int x = co_await coro::suspend_always{}); // { dg-error {'co_await' cannot be used outside a function} }
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-03-auto.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-03-auto.C
> new file mode 100644
> index 0000000000..7f4ed9afef
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-03-auto.C
> @@ -0,0 +1,16 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +extern struct awaitable *aw ();
> +
> +auto bar () {
> +  int x = 1 + co_await *aw();  // { dg-error "cannot be used in a function with a deduced return type" }
> +
> +  return x;
> +}
> +
> +int main () {
> +  bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C
> new file mode 100644
> index 0000000000..ac0ba2e54f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-04-ctor-dtor.C
> @@ -0,0 +1,8 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +struct Foo {
> +  Foo ()  { co_await coro::suspend_always{}; } // { dg-error "cannot be used in a constructor" }
> +  ~Foo () { co_await coro::suspend_always{}; } // { dg-error "cannot be used in a destructor" }
> +};
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-05-constexpr.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-05-constexpr.C
> new file mode 100644
> index 0000000000..73a0b1499d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-05-constexpr.C
> @@ -0,0 +1,12 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +constexpr int bar () {
> +  co_await coro::suspend_always{}; // { dg-error "cannot be used in a .constexpr. function" }
> +  return 42; /* Suppress the "no return" error.  */
> +}
> +
> +int main () {
> +  return bar ();
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-06-main.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-06-main.C
> new file mode 100644
> index 0000000000..ab520baaff
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-06-main.C
> @@ -0,0 +1,7 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int main (int ac, char *av[]) {
> +  co_await coro::suspend_always{}; // { dg-error "cannot be used in the .main. function" }
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-07-varargs.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-07-varargs.C
> new file mode 100644
> index 0000000000..4e41dd3be4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-07-varargs.C
> @@ -0,0 +1,14 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int
> +bar (int x, ...)
> +{
> +  co_await coro::suspend_always{}; // { dg-error "cannot be used in a varargs function" }
> +}
> +
> +int main (int ac, char *av[]) {
> +  bar (5, ac);
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-08-lambda-auto.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-08-lambda-auto.C
> new file mode 100644
> index 0000000000..61db5feed3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-08-lambda-auto.C
> @@ -0,0 +1,19 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Check that we decline return type deduction for lambda coroutines.
> +
> +#include "coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  /* Attempt to deduce the return type for a lambda coroutine.  */
> +  auto f = []()
> +  {
> +    co_await coro::suspend_always{}; // { dg-error "cannot be used in a function with a deduced return type" }
> +  };
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-01-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-01-outside-fn.C
> new file mode 100644
> index 0000000000..3fcd8dd104
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-01-outside-fn.C
> @@ -0,0 +1,6 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +co_return; // { dg-error {expected unqualified-id before 'co_return'} }
> +
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-02-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-02-outside-fn.C
> new file mode 100644
> index 0000000000..cda36eb2a3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-02-outside-fn.C
> @@ -0,0 +1,5 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +auto f (co_return); // { dg-error {expected primary-expression before 'co_return'} }
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-03-auto.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-03-auto.C
> new file mode 100644
> index 0000000000..93a04dc459
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-03-auto.C
> @@ -0,0 +1,12 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +auto bar () {
> +  co_return 5;  // { dg-error "cannot be used in a function with a deduced return type" }
> +}
> +
> +int main () {
> +  bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C
> new file mode 100644
> index 0000000000..9396432e8b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-04-ctor-dtor.C
> @@ -0,0 +1,8 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +struct Foo {
> +  Foo ()  { co_return; } // { dg-error "cannot be used in a constructor" }
> +  ~Foo () { co_return 5; } // { dg-error "cannot be used in a destructor" }
> +};
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C
> new file mode 100644
> index 0000000000..69b109fb60
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-05-constexpr-fn.C
> @@ -0,0 +1,12 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +constexpr int bar () {
> +  co_return 5; // { dg-error "cannot be used in a .constexpr. function" }
> +  return 42; /* Suppress the "no return" error.  */
> +}
> +
> +int main () {
> +  return bar ();
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-06-main.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-06-main.C
> new file mode 100644
> index 0000000000..40d7e4e362
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-06-main.C
> @@ -0,0 +1,7 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int main (int ac, char *av[]) {
> +  co_return 0; // { dg-error "cannot be used in the .main. function" }
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-07-vararg.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-07-vararg.C
> new file mode 100644
> index 0000000000..0aea17a1db
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-07-vararg.C
> @@ -0,0 +1,14 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int
> +bar (int x, ...)
> +{
> +  co_return 1; // { dg-error "cannot be used in a varargs function" }
> +}
> +
> +int main (int ac, char *av[]) {
> +  bar (5, ac);
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C
> new file mode 100644
> index 0000000000..4bfa41cd4a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C
> @@ -0,0 +1,43 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +struct Coro {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<Coro::promise_type>;
> +  handle_type handle;
> +  Coro () : handle(0) {}
> +  Coro (handle_type _handle) : handle(_handle) {}
> +  Coro (Coro &&s) : handle(s.handle) { s.handle = nullptr; }
> +  Coro &operator = (Coro &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       return *this;
> +  }
> +  Coro (const Coro &) = delete;
> +  ~Coro() {
> +    if ( handle )
> +      handle.destroy();
> +  }
> +  struct promise_type {
> +  promise_type() {}
> +  ~promise_type() {}
> +  Coro get_return_object () { return Coro (handle_type::from_promise (*this)); }
> +  auto initial_suspend () { return coro::suspend_always{}; }
> +  auto final_suspend () { return coro::suspend_always{}; }
> +  void return_void () { }
> +   void unhandled_exception() { }
> +  };
> +};
> +
> +extern int x;
> +
> +// Diagnose disallowed "return" in coroutine.
> +Coro
> +bar () // { dg-error {a 'return' statement is not allowed} }
> +{
> +  if (x)
> +    return Coro();
> +  else
> +    co_return;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-09-lambda-auto.C b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-09-lambda-auto.C
> new file mode 100644
> index 0000000000..8fe52361ba
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-09-lambda-auto.C
> @@ -0,0 +1,19 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Check that we decline return type deduction for lambda coroutines.
> +
> +#include "coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  /* Attempt to deduce the return type for a lambda coroutine.  */
> +  auto f = []()
> +  {
> +    co_return 42; // { dg-error "cannot be used in a function with a deduced return type" }
> +  };
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-00-needs-expr.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-00-needs-expr.C
> new file mode 100644
> index 0000000000..547f1a31c0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-00-needs-expr.C
> @@ -0,0 +1,7 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +void foo () {
> +  co_yield;  // { dg-error "expected primary-expression before" }
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C
> new file mode 100644
> index 0000000000..30db0e963b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-01-outside-fn.C
> @@ -0,0 +1,6 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +auto f (int x = co_yield 5); // { dg-error {'co_yield' cannot be used outside a function} }
> +
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-02-outside-fn.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-02-outside-fn.C
> new file mode 100644
> index 0000000000..71e119fbef
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-02-outside-fn.C
> @@ -0,0 +1,6 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int a[] = { co_yield 21 }; // { dg-error {'co_yield' cannot be used outside a function} }
> +
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-03-auto.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-03-auto.C
> new file mode 100644
> index 0000000000..808a07f5e1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-03-auto.C
> @@ -0,0 +1,12 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +auto bar () {
> +  co_yield 5;  // { dg-error "cannot be used in a function with a deduced return type" }
> +}
> +
> +int main () {
> +  bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C
> new file mode 100644
> index 0000000000..cc46e01d77
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-04-ctor-dtor.C
> @@ -0,0 +1,8 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +struct Foo {
> +  Foo ()  { co_yield 4; } // { dg-error "cannot be used in a constructor" }
> +  ~Foo () { co_yield 4; } // { dg-error "cannot be used in a destructor" }
> +};
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-05-constexpr.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-05-constexpr.C
> new file mode 100644
> index 0000000000..39ef19c63b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-05-constexpr.C
> @@ -0,0 +1,12 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +constexpr int bar () {
> +  co_yield 5; // { dg-error "cannot be used in a .constexpr. function" }
> +  return 42; /* Suppress the "no return" error.  */
> +}
> +
> +int main () {
> +  return bar ();
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-06-main.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-06-main.C
> new file mode 100644
> index 0000000000..dcc3dbce75
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-06-main.C
> @@ -0,0 +1,7 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int main (int ac, char *av[]) {
> +  co_yield 0; // { dg-error "cannot be used in the .main. function" }
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-07-varargs.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-07-varargs.C
> new file mode 100644
> index 0000000000..f0b568335e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-07-varargs.C
> @@ -0,0 +1,14 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +int
> +bar (int x, ...)
> +{
> +  co_yield 1; // { dg-error "cannot be used in a varargs function" }
> +}
> +
> +int main (int ac, char *av[]) {
> +  bar (5, ac);
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-08-needs-expr.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-08-needs-expr.C
> new file mode 100644
> index 0000000000..86969f781e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-08-needs-expr.C
> @@ -0,0 +1,37 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Check syntax for missing expr in a coroutine context.
> +
> +#include "coro.h"
> +
> +struct DummyYield {
> +  coro::coroutine_handle<> handle;
> +  DummyYield () : handle (nullptr) {}
> +  DummyYield (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct dummy_yield {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    DummyYield get_return_object() {
> +      return DummyYield (coro::coroutine_handle<dummy_yield>::from_promise (*this));
> +    }
> +    void yield_value (int v) {}
> +    void return_value (int v) {}
> +    void unhandled_exception() { /*std::terminate();*/ };
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<DummyYield> {
> +    using promise_type = DummyYield::dummy_yield;
> +};
> +
> +DummyYield
> +bar ()
> +{
> +  co_yield; // { dg-error {expected primary-expression before} }
> +  co_return 0;
> +}
> +
> +int main (int ac, char *av[]) {
> +  DummyYield x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C
> new file mode 100644
> index 0000000000..5190face00
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-09-lambda-auto.C
> @@ -0,0 +1,19 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Check that we decline return type deduction for lambda coroutines.
> +
> +#include "coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  /* Attempt to deduce the return type for a lambda coroutine.  */
> +  auto f = []()
> +  {
> +    co_yield 42; // { dg-error "cannot be used in a function with a deduced return type" }
> +  };
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-builtins.C b/gcc/testsuite/g++.dg/coroutines/coro-builtins.C
> new file mode 100644
> index 0000000000..d7c4883384
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-builtins.C
> @@ -0,0 +1,17 @@
> +//  { dg-additional-options "-fsyntax-only " }
> +
> +typedef __SIZE_TYPE__ size_t;
> +
> +int main ()
> +{
> +  void *co_h;
> +  void *promise;
> +  const size_t co_align = 16;
> +
> +  bool d = __builtin_coro_done (co_h);
> +  __builtin_coro_resume (co_h);
> +  __builtin_coro_destroy (co_h);
> +  promise = __builtin_coro_promise (co_h, co_align, true);
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> new file mode 100644
> index 0000000000..fb02e9d580
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> @@ -0,0 +1,32 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Diagose missing get_return_object() in the promise type.
> +
> +#include "coro.h"
> +
> +struct MissingGRO {
> +  coro::coroutine_handle<> handle;
> +  MissingGRO () : handle (nullptr) {}
> +  MissingGRO (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct missing_gro {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    void return_void () {}
> +    void unhandled_exception() { /*std::terminate();*/ };
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<MissingGRO> {
> +    using promise_type = MissingGRO::missing_gro;
> +};
> +
> +MissingGRO
> +bar () // { dg-error {no member named 'get_return_object' in} }
> +{
> +  co_return;
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingGRO x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
> new file mode 100644
> index 0000000000..d489c3953a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
> @@ -0,0 +1,33 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +struct MissingPromiseYield {
> +  coro::coroutine_handle<> handle;
> +  MissingPromiseYield () : handle (nullptr) {}
> +  MissingPromiseYield (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct missing_yield {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    MissingPromiseYield get_return_object() {
> +      return MissingPromiseYield (coro::coroutine_handle<missing_yield>::from_promise (*this));
> +    }
> +    void return_value (int v) {}
> +    void unhandled_exception() { /*std::terminate();*/ };
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<MissingPromiseYield> {
> +    using promise_type = MissingPromiseYield::missing_yield;
> +};
> +
> +MissingPromiseYield
> +bar ()
> +{
> +  co_yield 22; // { dg-error {no member named 'yield_value' in} }
> +  co_return 0;
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingPromiseYield x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
> new file mode 100644
> index 0000000000..f238c4b9a3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
> @@ -0,0 +1,34 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +// Diagose missing return_value() in the promise type.
> +
> +#include "coro.h"
> +
> +struct MissingRetValue {
> +  coro::coroutine_handle<> handle;
> +  MissingRetValue () : handle (nullptr) {}
> +  MissingRetValue (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct missing_retvoid {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    MissingRetValue get_return_object() {
> +      return MissingRetValue (coro::coroutine_handle<missing_retvoid>::from_promise (*this));
> +    }
> +    void unhandled_exception() { /*std::terminate();*/ };
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<MissingRetValue> {
> +    using promise_type = MissingRetValue::missing_retvoid;
> +};
> +
> +MissingRetValue
> +bar ()
> +{
> +  co_return 6174; // { dg-error {no member named 'return_value' in} }
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingRetValue x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-void.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-void.C
> new file mode 100644
> index 0000000000..c9f84e5902
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-void.C
> @@ -0,0 +1,34 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +
> +#include "coro.h"
> +
> +// Diagose missing return_void() in the promise type.
> +
> +struct MissingRetVoid {
> +  coro::coroutine_handle<> handle;
> +  MissingRetVoid () : handle (nullptr) {}
> +  MissingRetVoid (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct missing_retvoid {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    MissingRetVoid get_return_object() {
> +      return MissingRetVoid (coro::coroutine_handle<missing_retvoid>::from_promise (*this));
> +    }
> +    void unhandled_exception() { /*std::terminate();*/ };
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<MissingRetVoid> {
> +    using promise_type = MissingRetVoid::missing_retvoid;
> +};
> +
> +MissingRetVoid
> +bar ()
> +{
> +  co_return; // { dg-error "no member named .return_void. in" }
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingRetVoid x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
> new file mode 100644
> index 0000000000..3943e78d9d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
> @@ -0,0 +1,17 @@
> +//  { dg-additional-options "-fsyntax-only -fexceptions -w" }
> +
> +// Diagose missing unhandled_exception() in the promise type.
> +
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +MissingUEH
> +bar () // { dg-error {no member named 'unhandled_exception' in} }
> +{
> +  co_return;
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingUEH x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
> new file mode 100644
> index 0000000000..0f105c4c2d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
> @@ -0,0 +1,18 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions " }
> +
> +// The missing method is warned for when exceptions are off and pedantic
> +// is on (default in the testsuite).
> +
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +MissingUEH
> +bar () // { dg-warning {no member named 'unhandled_exception' in} }
> +{
> +  co_return;
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingUEH x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
> new file mode 100644
> index 0000000000..d775d8a630
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
> @@ -0,0 +1,18 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions -Wno-pedantic" }
> +
> +/* We don't warn about the missing method, unless in pedantic mode, so
> +   this compile should be clean.  */
> +
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +MissingUEH
> +bar ()
> +{
> +  co_return;
> +}
> +
> +int main (int ac, char *av[]) {
> +  MissingUEH x = bar ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
> new file mode 100644
> index 0000000000..51e6135b8a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
> @@ -0,0 +1,23 @@
> +#ifndef __MissingUEH_H
> +#define __MissingUEH_H
> +
> +/* Common code for testing missing unhandled_exception.  */
> +struct MissingUEH {
> +  coro::coroutine_handle<> handle;
> +  MissingUEH () : handle (nullptr) {}
> +  MissingUEH (coro::coroutine_handle<> handle) : handle (handle) {}
> +  struct missing_ueh {
> +    coro::suspend_never initial_suspend() { return {}; }
> +    coro::suspend_never final_suspend() { return {}; }
> +    MissingUEH get_return_object() {
> +      return MissingUEH (coro::coroutine_handle<missing_ueh>::from_promise (*this));
> +    }
> +    void return_void () {}
> +  };
> +};
> +
> +template<> struct coro::coroutine_traits<MissingUEH> {
> +    using promise_type = MissingUEH::missing_ueh;
> +};
> +
> +#endif
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C b/gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C
> new file mode 100644
> index 0000000000..f22a5e0833
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C
> @@ -0,0 +1,9 @@
> +// Only need to compile this, with the default options from the .exp.
> +
> +#ifndef __cpp_coroutines
> +#error "coroutines should engaged."
> +#endif
> +
> +#if __cpp_coroutines != 201902L
> +#error "coroutine version out of sync."
> +#endif
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro.h b/gcc/testsuite/g++.dg/coroutines/coro.h
> new file mode 100644
> index 0000000000..ca12d2689e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro.h
> @@ -0,0 +1,151 @@
> +#if __has_include(<coroutine>)
> +
> +#include <coroutine>
> +
> +#  if __clang__
> +#    include <utility>
> +#  endif
> +
> +namespace coro = std;
> +
> +#elif __has_include(<experimental/coroutine>)
> +
> +#include <experimental/coroutine>
> +
> +#  if __clang__
> +#    include <utility>
> +#  endif
> +
> +namespace coro = std::experimental;
> +
> +#else
> +
> +#warning "no installed coroutine headers found, using test-suite local one"
> +
> +/* Dummy version to allow tests without an installed header.  */
> +#  ifndef __TESTSUITE_CORO_H_n4835
> +#  define __TESTSUITE_CORO_H_n4835
> +
> +// Fragments (with short-cuts) to mimic enough of the library header to
> +// make some progress.
> +
> +#  if __cpp_coroutines
> +
> +namespace std {
> +inline namespace __n4835 {
> +
> +// 21.11.1 coroutine traits
> +template<typename _R, typename...> struct coroutine_traits {
> +  using promise_type = typename _R::promise_type;
> +};
> +
> +// 21.11.2  coroutine handle
> +template <typename Promise = void> struct coroutine_handle;
> +
> +template <>
> +struct coroutine_handle<void> {
> +  public:
> +      // 21.11.2.1 construct/reset
> +  constexpr coroutine_handle () noexcept
> +    : __fr_ptr (0) {}
> +  constexpr coroutine_handle (decltype(nullptr) __h) noexcept
> +    : __fr_ptr (__h) {}
> +  coroutine_handle &operator= (decltype(nullptr)) noexcept {
> +    __fr_ptr = nullptr;
> +    return *this;
> +  }
> +
> +  public:
> +    // 21.11.2.2 export/import
> +    constexpr void *address () const noexcept { return __fr_ptr; }
> +    constexpr static coroutine_handle from_address (void *__a) noexcept {
> +      coroutine_handle __self;
> +      __self.__fr_ptr = __a;
> +      return __self;
> +    }
> +  public:
> +      // 21.11.2.3 observers
> +    constexpr explicit operator bool () const noexcept {
> +      return bool (__fr_ptr);
> +    }
> +    bool done () const noexcept {
> +      return __builtin_coro_done (__fr_ptr);
> +    }
> +      // 21.11.2.4 resumption
> +    void operator () () const { resume (); }
> +    void resume () const {
> +      __builtin_coro_resume (__fr_ptr);
> +    }
> +    void destroy () const {
> +      __builtin_coro_destroy (__fr_ptr);
> +    }
> +  protected:
> +    void *__fr_ptr;
> +};
> +
> +template <class _Promise>
> +struct coroutine_handle : coroutine_handle<> {
> +  // 21.11.2.1 construct/reset
> +  using coroutine_handle<>::coroutine_handle;
> +  static coroutine_handle from_promise(_Promise &p) {
> +    coroutine_handle __self;
> +    __self.__fr_ptr =
> +      __builtin_coro_promise((char *)&p,  __alignof(_Promise), true);
> +    return __self;
> +  }
> +  coroutine_handle& operator=(decltype(nullptr)) noexcept {
> +    coroutine_handle<>::operator=(nullptr);
> +    return *this;
> +  }
> +  // 21.11.2.2 export/import
> +  constexpr static coroutine_handle from_address(void* __a){
> +    coroutine_handle __self;
> +    __self.__fr_ptr = __a;
> +    return __self;
> +  }
> +  // 21.11.2.5 promise access
> +  _Promise& promise() const {
> +    void * __t = __builtin_coro_promise(this->__fr_ptr,
> +                                       __alignof(_Promise), false);
> +    return *static_cast<_Promise*>(__t);
> +  }
> +};
> +
> +// n4760 - 21.11.5 trivial awaitables
> +
> +struct suspend_always {
> +  bool await_ready() { return false; }
> +  void await_suspend(coroutine_handle<>) {}
> +  void await_resume() {}
> +};
> +
> +struct suspend_never {
> +  bool await_ready() { return true; }
> +  void await_suspend(coroutine_handle<>) {}
> +  void await_resume() {}
> +};
> +
> +} // namespace __n4835
> +} // namespace std
> +
> +namespace coro = std;
> +
> +#  else
> +#    error "coro.h requires support for coroutines, add -fcoroutines"
> +#  endif
> +#  endif // __TESTSUITE_CORO_H_n4835
> +
> +#endif // __has_include(<experimental/coroutine>)
> +
> +/* just to avoid cluttering dump files. */
> +extern "C" int puts (const char *);
> +extern "C" int printf (const char *, ...);
> +extern "C" void abort (void) __attribute__((__noreturn__));
> +
> +#ifndef OUTPUT
> +#  define PRINT(X)
> +#  define PRINTF (void)
> +#else
> +#  define PRINT(X) puts(X)
> +#  define PRINTF printf
> +#endif
> diff --git a/gcc/testsuite/g++.dg/coroutines/coro1-ret-int-yield-int.h b/gcc/testsuite/g++.dg/coroutines/coro1-ret-int-yield-int.h
> new file mode 100644
> index 0000000000..b961755e47
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro1-ret-int-yield-int.h
> @@ -0,0 +1,133 @@
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  // Some awaitables to use in tests.
> +  // With progress printing for debug.
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  ~suspend_always_prt() { PRINT ("susp-always-dtor"); }
> +  };
> +
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    suspend_always_intprt(int __x) : x(__x) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { PRINT ("susp-always-susp-intprt");}
> +    int await_resume() const noexcept { PRINT ("susp-always-resume-intprt"); return x;}
> +  };
> +
> +  /* This returns the square of the int that it was constructed with.  */
> +  struct suspend_always_longprtsq {
> +    long x;
> +    suspend_always_longprtsq() : x(12L) { PRINT ("suspend_always_longprtsq def ctor"); }
> +    suspend_always_longprtsq(long _x) : x(_x) { PRINTF ("suspend_always_longprtsq ctor with %ld\n", x); }
> +    ~suspend_always_longprtsq() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { PRINT ("susp-always-susp-longsq");}
> +    long await_resume() const noexcept { PRINT ("susp-always-resume-longsq"); return x * x;}
> +  };
> +
> +  struct suspend_always_intrefprt {
> +    int& x;
> +    suspend_always_intrefprt(int& __x) : x(__x) {}
> +    ~suspend_always_intrefprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { PRINT ("susp-always-susp-intprt");}
> +    int& await_resume() const noexcept { PRINT ("susp-always-resume-intprt"); return x;}
> +  };
> +
> +  struct promise_type {
> +
> +  promise_type() : vv(-1) {  PRINT ("Created Promise"); }
> +  promise_type(int __x) : vv(__x) {  PRINTF ("Created Promise with %d\n",__x); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +
> +#ifdef USE_AWAIT_TRANSFORM
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  auto await_transform (long v) {
> +    PRINTF ("await_transform a long () %ld\n",v);
> +    return suspend_always_longprtsq (v);
> +  }
> +
> +#endif
> +
> +  auto yield_value (int v) {
> +    PRINTF ("yield_value (%d)\n", v);
> +    vv = v;
> +    return suspend_always_prt{};
> +  }
> +
> +#ifdef RETURN_VOID
> +
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +
> +#else
> +
> +  void return_value (int v) {
> +    PRINTF ("return_value (%d)\n", v);
> +    vv = v;
> +  }
> +
> +#endif
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +
> +  int get_value () { return vv; }
> +  private:
> +    int vv;
> +  };
> +
> +};
> diff --git a/gcc/testsuite/g++.dg/coroutines/coroutines.exp b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> new file mode 100644
> index 0000000000..e7fd4dac46
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> @@ -0,0 +1,50 @@
> +#   Copyright (C) 2018-2020 Free Software Foundation, Inc.
> +
> +# Contributed by Iain Sandoe <iain@sandoe.co.uk> under contract to Facebook.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# Test C++ coroutines, requires c++17; doesn't, at present, seem much
> +# point in repeating these for other versions.
> +
> +# Load support procs.
> +load_lib g++-dg.exp
> +
> +# If a testcase doesn't have special options, use these.
> +global DEFAULT_CXXFLAGS
> +if ![info exists DEFAULT_CXXFLAGS] then {
> +    set DEFAULT_CXXFLAGS " -pedantic-errors -Wno-long-long"
> +}
> +
> +set DEFAULT_COROFLAGS $DEFAULT_CXXFLAGS
> +lappend DEFAULT_COROFLAGS "-std=c++17" "-fcoroutines"
> +
> +dg-init
> +
> +# Run the tests.
> +# g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] \
> +#        "" $DEFAULT_COROFLAGS
> +
> +foreach test [lsort [find $srcdir/$subdir {*.[CH]}]] {
> +    if [runtest_file_p $runtests $test] {
> +        set nshort [file tail [file dirname $test]]/[file tail $test]
> +        verbose "Testing $nshort $DEFAULT_COROFLAGS" 1
> +        dg-test $test "" $DEFAULT_COROFLAGS
> +        set testcase [string range $test [string length "$srcdir/"] end]
> +    }
> +}
> +
> +# done.
> +dg-finish
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C b/gcc/testsuite/g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C
> new file mode 100644
> index 0000000000..8430d053c6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/alloc-00-gro-on-alloc-fail.C
> @@ -0,0 +1,118 @@
> +//  { dg-do run }
> +
> +// check the code-gen for the failed alloc return.
> +
> +#include "../coro.h"
> +
> +#if __has_include(<new>)
> +#  include <new>
> +#else
> +
> +// Required when get_return_object_on_allocation_failure() is defined by
> +// the promise.
> +// we need a no-throw new, and new etc.  build the relevant pieces here to
> +// avoid needing the headers in the test.
> +
> +namespace std {
> +  struct nothrow_t {};
> +  constexpr nothrow_t nothrow = {};
> +  typedef __SIZE_TYPE__ size_t;
> +} // end namespace std
> +
> +void* operator new(std::size_t, const std::nothrow_t&) noexcept;
> +void  operator delete(void* __p, const std::nothrow_t&) noexcept;
> +#endif
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () noexcept : handle(0) {}
> +  coro1 (handle_type _handle) noexcept
> +    : handle(_handle)  {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) noexcept : handle(s.handle)  {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) noexcept {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() noexcept {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  static coro1 get_return_object_on_allocation_failure () noexcept;
> +  }; // promise
> +}; // coro1
> +
> +coro1 coro1::promise_type::
> +get_return_object_on_allocation_failure () noexcept {
> +  PRINT ("alloc fail return");
> +  return coro1 (nullptr);
> +}
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/alloc-01-overload-newdel.C b/gcc/testsuite/g++.dg/coroutines/torture/alloc-01-overload-newdel.C
> new file mode 100644
> index 0000000000..f779f6e486
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/alloc-01-overload-newdel.C
> @@ -0,0 +1,120 @@
> +//  { dg-do run }
> +
> +// check codegen for overloaded operator new/delete.
> +
> +#include "../coro.h"
> +
> +int used_ovl_new = 0;
> +int used_ovl_del = 0;
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () noexcept : handle(0) {}
> +  coro1 (handle_type _handle) noexcept
> +    : handle(_handle)  {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) noexcept : handle(s.handle)  {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) noexcept {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() noexcept {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  void *operator new (std::size_t sz) {
> +    PRINT ("promise_type: used overloaded operator new");
> +    used_ovl_new++;
> +    return ::operator new(sz);
> +  }
> +
> +  void operator delete (void *p)  {
> +    PRINT ("promise_type: used overloaded operator delete");
> +    used_ovl_del++;
> +    return ::operator delete(p);
> +  }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  }; // promise
> +}; // coro1
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  // Nest a scope so that we can inspect the flags after the DTORs run.
> +  {
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  }
> +  if (used_ovl_new != 1)
> +    {
> +      PRINT ("main: failed to call overloaded operator new");
> +      abort ();
> +    }
> +  if (used_ovl_del != 1)
> +    {
> +      PRINT ("main: failed to call overloaded operator delete");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/call-00-co-aw-arg.C b/gcc/testsuite/g++.dg/coroutines/torture/call-00-co-aw-arg.C
> new file mode 100644
> index 0000000000..ee108072f6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/call-00-co-aw-arg.C
> @@ -0,0 +1,73 @@
> +// { dg-do run }
> +
> +// Check that we can use co_await as a call parm.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +__attribute__((__noinline__))
> +static int
> +foo (int x)
> +{
> +  return x + 2;
> +}
> +
> +/* Function with a single await.  */
> +coro1
> +f ()
> +{
> +  gX = foo (co_await 9);
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] (initial suspend)");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] (await 9 parm)");
> +  f_coro.handle.resume();
> +
> +  if (gX != 11)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 11\n", gX);
> +      abort ();
> +    }
> +
> +  /* we should now have returned with the co_return 11 + 31) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done'");
> +      abort ();
> +    }
> +
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +
> +  puts ("main: done");
> +  return 0;
> +}
> \ No newline at end of file
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/call-01-multiple-co-aw.C b/gcc/testsuite/g++.dg/coroutines/torture/call-01-multiple-co-aw.C
> new file mode 100644
> index 0000000000..0f5785163f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/call-01-multiple-co-aw.C
> @@ -0,0 +1,73 @@
> +// { dg-do run }
> +
> +// Check that we can use multiple co_awaits as a call parm.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +__attribute__((__noinline__))
> +static int
> +bar (int x, int y)
> +{
> +  return x + y;
> +}
> +
> +/* Function with a multiple awaits.  */
> +coro1
> +g ()
> +{
> +  gX = bar (co_await 9, co_await 2);
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 g_coro = g ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (g_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] (initial suspend)");
> +  g_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] (parm 1)");
> +  g_coro.handle.resume();
> +  PRINT ("main: resuming [2] (parm 2)");
> +  g_coro.handle.resume();
> +  if (gX != 11)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 11\n", gX);
> +      abort ();
> +    }
> +
> +  /* we should now have returned with the co_return 11 + 31) */
> +  if (!g_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done'");
> +      abort ();
> +    }
> +
> +  int y = g_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +
> +  puts ("main: done");
> +  return 0;
> +}
> \ No newline at end of file
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/call-02-temp-co-aw.C b/gcc/testsuite/g++.dg/coroutines/torture/call-02-temp-co-aw.C
> new file mode 100644
> index 0000000000..4982c49d79
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/call-02-temp-co-aw.C
> @@ -0,0 +1,72 @@
> +// { dg-do run }
> +
> +// Check  foo (compiler temp, co_await).
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +__attribute__((__noinline__))
> +static int
> +bar (int x, int y)
> +{
> +  return x + y;
> +}
> +
> +/* Function with a compiler temporary and a co_await.  */
> +coro1
> +g ()
> +{
> +  gX = bar (gX + 8, co_await 2);
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 g_coro = g ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (g_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] (initial suspend)");
> +  g_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] (parm 1)");
> +  g_coro.handle.resume();
> +
> +  if (gX != 11)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 11\n", gX);
> +      abort ();
> +    }
> +
> +  /* we should now have returned with the co_return 11 + 31) */
> +  if (!g_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done'");
> +      abort ();
> +    }
> +
> +  int y = g_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +
> +  puts ("main: done");
> +  return 0;
> +}
> \ No newline at end of file
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C b/gcc/testsuite/g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C
> new file mode 100644
> index 0000000000..d0bb4667ac
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/call-03-temp-ref-co-aw.C
> @@ -0,0 +1,72 @@
> +// { dg-do run }
> +
> +// Check  foo (compiler temp, co_await).
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +__attribute__((__noinline__))
> +static int
> +bar (int x, const int& y)
> +{
> +  return x + y;
> +}
> +
> +/* Function with a compiler temporary and a co_await.  */
> +coro1
> +g ()
> +{
> +  gX = bar (gX + 8, co_await 2);
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 g_coro = g ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (g_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] (initial suspend)");
> +  g_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] (parm 1)");
> +  g_coro.handle.resume();
> +
> +  if (gX != 11)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 11\n", gX);
> +      abort ();
> +    }
> +
> +  /* we should now have returned with the co_return 11 + 31) */
> +  if (!g_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done'");
> +      abort ();
> +    }
> +
> +  int y = g_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +
> +  puts ("main: done");
> +  return 0;
> +}
> \ No newline at end of file
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-00-co-ret.C b/gcc/testsuite/g++.dg/coroutines/torture/class-00-co-ret.C
> new file mode 100644
> index 0000000000..932fe4b283
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-00-co-ret.C
> @@ -0,0 +1,41 @@
> +//  { dg-do run }
> +
> +// Simplest class.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +class foo
> +{
> +  public:
> +  coro1 meth ()
> +    {
> +      PRINT ("coro1: about to return");
> +      co_return 42;
> +    }
> +};
> +
> +int main ()
> +{
> +  foo inst;
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = inst.meth ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-01-co-ret-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/class-01-co-ret-parm.C
> new file mode 100644
> index 0000000000..0bd477044b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-01-co-ret-parm.C
> @@ -0,0 +1,57 @@
> +//  { dg-do run }
> +
> +// Class with parm capture
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +class foo
> +{
> +  public:
> +  coro1 meth (int x)
> +    {
> +      if (x > 30)
> +       {
> +         PRINT ("coro1: about to return k");
> +         co_return 6174;
> +       }
> +      else if (x > 20)
> +       {
> +         PRINT ("coro1: about to return the answer");
> +         co_return 42;
> +       }
> +      else
> +       {
> +         PRINT ("coro1: about to return 0");
> +         co_return 0;
> +       }
> +    }
> +};
> +
> +int main ()
> +{
> +  foo inst;
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = inst.meth (25);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    {
> +      PRINTF ("main: wrong result (%d)", y);
> +      abort ();
> +    }
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-02-templ-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/class-02-templ-parm.C
> new file mode 100644
> index 0000000000..0cc6069c32
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-02-templ-parm.C
> @@ -0,0 +1,52 @@
> +// { dg-do run }
> +
> +// template parm in a class
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +class foo
> +{
> +  public:
> +  coro1 meth (T y)
> +    {
> +      PRINT ("coro1: about to return");
> +      T x = y;
> +      co_return co_await x + 3;
> +    }
> +};
> +
> +int main ()
> +{
> +  foo<int> inst {};
> +  PRINT ("main: create coro1");
> +  coro1 x = inst.meth (17);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-03-operator-templ-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/class-03-operator-templ-parm.C
> new file mode 100644
> index 0000000000..2d888a7455
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-03-operator-templ-parm.C
> @@ -0,0 +1,52 @@
> +// { dg-do run }
> +
> +// template parm in a class
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +class foo
> +{
> +  public:
> +  coro1 operator()(T y)
> +    {
> +      PRINT ("coro1: about to return");
> +      T x = y;
> +      co_return co_await x + 3;
> +    }
> +};
> +
> +int main ()
> +{
> +  foo<int> inst {};
> +  PRINT ("main: create coro1");
> +  coro1 x = inst.operator()(17);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-04-lambda-1.C b/gcc/testsuite/g++.dg/coroutines/torture/class-04-lambda-1.C
> new file mode 100644
> index 0000000000..e191c20ac0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-04-lambda-1.C
> @@ -0,0 +1,58 @@
> +// { dg-do run }
> +
> +// template parm in a class
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +class foo
> +{
> +  public:
> +  auto get_lam ()
> +    {
> +      auto l = [](T y) -> coro1
> +      {
> +       T x = y;
> +       co_return co_await x + 3;
> +      };
> +      return l;
> +    }
> +};
> +
> +int main ()
> +{
> +  foo<int> inst {};
> +  auto ll = inst.get_lam ();
> +
> +  PRINT ("main: create coro1");
> +  int arg = 17; // avoid a dangling reference
> +  coro1 x = ll (arg);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C b/gcc/testsuite/g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C
> new file mode 100644
> index 0000000000..968940f505
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C
> @@ -0,0 +1,59 @@
> +// { dg-do run }
> +
> +// template parm in a class
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +class foo
> +{
> +  public:
> +  auto get_lam (int parm)
> +    {
> +      int local = 3;
> +      auto l = [=](T y) -> coro1
> +      {
> +       T x = y;
> +       co_return co_await x + local;
> +      };
> +      return l;
> +    }
> +};
> +
> +int main ()
> +{
> +  foo<int> inst {};
> +  auto ll = inst.get_lam (10);
> +
> +  PRINT ("main: create coro1");
> +  int arg = 17; // avoid a dangling reference
> +  coro1 x = ll (arg);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/class-06-lambda-capture-ref.C b/gcc/testsuite/g++.dg/coroutines/torture/class-06-lambda-capture-ref.C
> new file mode 100644
> index 0000000000..db60132b0e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/class-06-lambda-capture-ref.C
> @@ -0,0 +1,59 @@
> +// { dg-do run }
> +
> +// template parm in a class
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +class foo
> +{
> +  public:
> +  void use_lambda ()
> +    {
> +      int a_copy = 20;
> +      int a_ref = 10;
> +
> +      auto f = [&, a_copy]() -> coro1
> +      {
> +       co_yield a_ref + a_copy;
> +       co_return a_ref + a_copy;
> +      };
> +
> +      coro1 A = f ();
> +      A.handle.resume(); // Initial suspend.
> +      PRINT ("main: [a_copy = 20, a_ref = 10]");
> +
> +      int y = A.handle.promise().get_value();
> +      if (y != 30)
> +       {
> +         PRINTF ("main: co-yield = %d, should be 30\n", y);
> +         abort ();
> +       }
> +
> +      a_copy = 5;
> +      a_ref = 7;
> +
> +      A.handle.resume(); // from the yield.
> +      PRINT ("main: [a_copy = 5, a_ref = 7]");
> +
> +      y = A.handle.promise().get_value();
> +      if (y != 27)
> +       {
> +         PRINTF ("main: co-ret = %d, should be 27\n", y);
> +         abort ();
> +       }
> +      PRINT ("use_lambda: about to return");
> +    }
> +  ~foo () { PRINT ("foo: DTOR"); }
> +};
> +
> +int main ()
> +{
> +  foo<int> inst;
> +  inst.use_lambda();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-00-trivial.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-00-trivial.C
> new file mode 100644
> index 0000000000..a24c261599
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-00-trivial.C
> @@ -0,0 +1,52 @@
> +//  { dg-do run }
> +
> +// The simplest co_await we can do.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  co_await coro1::suspend_always_prt{};
> +  co_return gX + 10;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] co_await");
> +  f_coro.handle.resume();
> +  /* we should now have returned with the co_return (15) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 11)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 11\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-01-with-value.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-01-with-value.C
> new file mode 100644
> index 0000000000..db5c90224d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-01-with-value.C
> @@ -0,0 +1,57 @@
> +//  { dg-do run }
> +
> +/* The simplest valued co_await we can do.  */
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  gX = co_await coro1::suspend_always_intprt{};
> +  co_return gX + 10;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] co_await suspend_always_intprt");
> +  f_coro.handle.resume();
> +  if (gX != 5)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 5\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (15) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 15)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 15\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-02-xform.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-02-xform.C
> new file mode 100644
> index 0000000000..79ee6e1714
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-02-xform.C
> @@ -0,0 +1,58 @@
> +//  { dg-do run }
> +
> +// Test of basic await transform, no local state.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  gX = co_await 11;
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] co_await");
> +  f_coro.handle.resume();
> +  if (gX != 11)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 11\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (15) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-03-rhs-op.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-03-rhs-op.C
> new file mode 100644
> index 0000000000..6408432573
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-03-rhs-op.C
> @@ -0,0 +1,58 @@
> +//  { dg-do run }
> +
> +// Basic check of co_await with an expression to await transform.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  gX = co_await 11 + 15;
> +  co_return gX + 16;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [1] await");
> +  f_coro.handle.resume();
> +  if (gX != 26)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 26\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (26+16) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-04-control-flow.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-04-control-flow.C
> new file mode 100644
> index 0000000000..9bc99e875d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-04-control-flow.C
> @@ -0,0 +1,50 @@
> +//  { dg-do run }
> +
> +// Check correct operation of await transform.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +int y = 30;
> +
> +coro1
> +f ()
> +{
> +  if (gX < 12) {
> +    gX += y;
> +    gX += co_await 11;
> +  } else
> +    gX += co_await 12;
> +
> +  co_return gX;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    PRINTF ("main: gX : %d \n", gX);
> +    f_coro.handle.resume();
> +  } while (!f_coro.handle.done());
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-05-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-05-loop.C
> new file mode 100644
> index 0000000000..34af740c99
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-05-loop.C
> @@ -0,0 +1,51 @@
> +//  { dg-do run }
> +
> +// Check correct operation of co_await in a loop without local state.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  for (;;)
> +    {
> +      gX += co_await 11;
> +      if (gX > 100)
> +        break;
> +    }
> +  co_return gX;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    PRINTF ("main: gX : %d \n", gX);
> +    f_coro.handle.resume();
> +  } while (!f_coro.handle.done());
> +
> +  int y = f_coro.handle.promise().get_value();
> +  // first value above 100 is 10*11 + 1.
> +  if (y != 111)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 111\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-06-ovl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-06-ovl.C
> new file mode 100644
> index 0000000000..14945faffd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-06-ovl.C
> @@ -0,0 +1,65 @@
> +//  { dg-do run }
> +
> +// Basic check of the co_await operator overload.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* A very simple overload.  */
> +struct empty
> +{
> +  auto operator co_await() const & noexcept {
> +    return coro1::suspend_always_intprt{};
> +  }
> +};
> +
> +int gX = 1;
> +empty e{};
> +
> +coro1
> +f ()
> +{
> +  int a = co_await(e); /* operator ovl. */
> +  co_return gX + 5 + a;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done'");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] co_await");
> +  f_coro.handle.resume();
> +
> +  /* we should now have returned with the co_return (11) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 11)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 11\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-07-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-07-tmpl.C
> new file mode 100644
> index 0000000000..33f8e99d8c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-07-tmpl.C
> @@ -0,0 +1,132 @@
> +//  { dg-do run }
> +
> +// Check that we correctly operate when the coroutine object is templated.
> +
> +#include "../coro.h"
> +
> +template <typename T>
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT ("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT ("Moved coro1");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    return *this;
> +  }
> +  ~coro1() {
> +    PRINT ("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +    ~suspend_never_prt() {}
> +    bool await_ready() const noexcept { return true; }
> +    void await_suspend(handle_type h) const noexcept { PRINT ("susp-never-susp");}
> +    void await_resume() const noexcept {PRINT ("susp-never-resume");}
> +  };
> +
> +  struct  suspend_always_prt {
> +    T x;
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +    void await_resume() const noexcept {PRINT ("susp-always-resume");}
> +  };
> +
> +  /* This returns the int it was constructed with.  */
> +  struct suspend_always_intprt {
> +    T x;
> +    suspend_always_intprt() : x((T)5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(T _x) : x(_x)
> +      { PRINTF ("suspend_always_intprt ctor with %ld\n", (long)x); }
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { PRINT ("susp-always-susp-int");}
> +    int await_resume() const noexcept { PRINT ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  T value;
> +  promise_type()  { PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  coro1 get_return_object() {
> +    PRINT ("get_return_object: from handle from promise");
> +    return coro1 (handle_type::from_promise (*this));
> +  }
> +
> +  auto initial_suspend() {
> +    PRINT ("get initial_suspend ");
> +    return suspend_never_prt{};
> +  }
> +
> +  auto final_suspend() {
> +    PRINT ("get final_suspend");
> +    return suspend_always_prt{};
> +  }
> +
> +  void return_value (int v) {
> +    PRINTF ("return_value () %ld\n", (long) v);
> +    value = v;
> +  }
> +
> +  auto await_transform (T v) {
> +    PRINTF ("await_transform a T () %ld\n", (long)v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  T get_value () { return value; }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +int gX = 2;
> +
> +template <typename T>
> +coro1<T> f ()
> +{
> +  for (int i = 0; i < 4; ++i)
> +    {
> +      gX += co_await 10;
> +    }
> +  co_return gX;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  auto f_coro = f<int>();
> +
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 2)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 2\n", gX);
> +      abort ();
> +    }
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    f_coro.handle.resume();
> +  } while (!f_coro.handle.done());
> +
> +  int y = f_coro.handle.promise().get_value();
> +
> +  if (y != 42)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 42\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-08-cascade.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-08-cascade.C
> new file mode 100644
> index 0000000000..d34619d6b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-08-cascade.C
> @@ -0,0 +1,63 @@
> +//  { dg-do run }
> +
> +// Check cascaded co_await operations.
> +
> +#include "../coro.h"
> +
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +coro1 f ()
> +{
> +  /* We are going to use an await transform that takes a long, the
> +     await_resume squares it.
> +     so we get 11 ** 4, 14641.  */
> +  gX = (int) co_await co_await 11L;
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] - inital suspend");
> +  f_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] - nested");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [3] - outer");
> +  f_coro.handle.resume();
> +
> +  if (gX != 14641)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 14641\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (14672) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 14672)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 14672\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-09-pair.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-09-pair.C
> new file mode 100644
> index 0000000000..525c6fc467
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-09-pair.C
> @@ -0,0 +1,57 @@
> +//  { dg-do run }
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +coro1 f ()
> +{
> +  gX = co_await 11 + co_await 15;
> +  co_return gX + 31;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] (initial suspend)");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] one side of add");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [3] other side of add");
> +  f_coro.handle.resume();
> +  if (gX != 26)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 26\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (57) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 57)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 57\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-10-template-fn-arg.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-10-template-fn-arg.C
> new file mode 100644
> index 0000000000..71a5b18c3c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-10-template-fn-arg.C
> @@ -0,0 +1,60 @@
> +// { dg-do run }
> +
> +// Check type dependent function parms.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +// there is a promise ctor that takes a single int.
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +coro1
> +f (T y) noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  T x = y;
> +  co_return co_await x + 3;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f<int>(17);
> +
> +  /* We should have created the promise with an initial value of
> +     17.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 17 )
> +    {
> +      PRINTF ("main: wrong promise init (%d).", y);
> +      abort ();
> +    }
> +
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-11-forwarding.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-11-forwarding.C
> new file mode 100644
> index 0000000000..78c88ed14e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-11-forwarding.C
> @@ -0,0 +1,43 @@
> +//  { dg-do run }
> +
> +// Test of forwarding a templated awaitable to co_await.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Valued with an await_transform.  */
> +
> +template< typename AWAITABLE >
> +coro1
> +test_fwd (AWAITABLE&& awaitable)
> +{
> +  // the await_resume() just returns the saved int value.
> +  int a = co_await std::forward<AWAITABLE>(awaitable);
> +  // Which we co-return to the promise so that it can be
> +  // retrieved.
> +  co_return a;
> +}
> +
> +int main ()
> +{
> +  // We have an awaitable that stores the int it was constructed with.
> +  coro1::suspend_always_intprt g(15);
> +  struct coro1 g_coro = test_fwd (g);
> +
> +  PRINT ("main: resuming g [1] (initial suspend)");
> +  g_coro.handle.resume();
> +
> +  PRINT ("main: resuming g [2] co_await");
> +  g_coro.handle.resume();
> +
> +  int y = g_coro.handle.promise().get_value();
> +  if (y != 15)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 15\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-12-operator-2.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-12-operator-2.C
> new file mode 100644
> index 0000000000..189332b78e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-12-operator-2.C
> @@ -0,0 +1,66 @@
> +//  { dg-do run }
> +
> +// Basic check of the co_await operator overload.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* A very simple overload.  */
> +struct empty
> +{
> +  auto operator co_await() & noexcept {
> +    return coro1::suspend_always_intprt{};
> +  }
> +  auto operator co_await() && noexcept {
> +    return coro1::suspend_always_longprtsq(3L);
> +  }
> +};
> +
> +empty e{};
> +
> +coro1
> +f ()
> +{
> +  int a = co_await e; /* operator ovl lv. */
> +  int b = co_await empty{}; /* operator ovl rv. */
> +  co_return b + a;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done'");
> +      abort ();
> +    }
> +
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +
> +  PRINT ("main: resuming [2] co_await a");
> +  f_coro.handle.resume();
> +
> +  PRINT ("main: resuming [3] co_await b");
> +  f_coro.handle.resume();
> +
> +  /* we should now have returned with the co_return (14) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 14)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 14\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-13-return-ref.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-13-return-ref.C
> new file mode 100644
> index 0000000000..339ebe4ff2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-13-return-ref.C
> @@ -0,0 +1,58 @@
> +//  { dg-do run }
> +
> +/* The simplest valued co_await we can do.  */
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  int t = 5;
> +  gX = co_await coro1::suspend_always_intrefprt{t};
> +  co_return t + 10;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - checking gX");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: we should not be 'done' [1]");
> +      abort ();
> +    }
> +  PRINT ("main: resuming [1] initial suspend");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] co_await suspend_always_intprt");
> +  f_coro.handle.resume();
> +  if (gX != 5)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 5\n", gX);
> +      abort ();
> +    }
> +  /* we should now have returned with the co_return (15) */
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: we should be 'done' ");
> +      abort ();
> +    }
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 15)
> +    {
> +      PRINTF ("main: y is wrong : %d, should be 15\n", y);
> +      abort ();
> +    }
> +  puts ("main: done");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C
> new file mode 100644
> index 0000000000..f551c6e760
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-00-void-return-is-ready.C
> @@ -0,0 +1,90 @@
> +//  { dg-do run }
> +
> +// Basic functionality check, co_return.
> +// Here we check the case that initial suspend is "never", so that the co-
> +// routine runs to completion immediately.
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept {PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  coro1 get_return_object () {
> +    PRINT ("get_return_object: from handle from promise");
> +    return coro1 (handle_type::from_promise (*this));
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (never) ");
> +    return suspend_never_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always) ");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - should be done");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently was not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C
> new file mode 100644
> index 0000000000..03fc6eeb84
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-01-void-return-is-suspend.C
> @@ -0,0 +1,94 @@
> +//  { dg-do run }
> +
> +// Basic functionality check, co_return.
> +// Here we check the case that initial suspend is "always".
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  coro1 get_return_object () {
> +    PRINT ("get_return_object: from handle from promise");
> +    return coro1 (handle_type::from_promise (*this));
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C
> new file mode 100644
> index 0000000000..36da680f7f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-03-different-GRO-type.C
> @@ -0,0 +1,92 @@
> +//  { dg-do run }
> +
> +// GRO differs from the eventual return type.
> +
> +# include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C
> new file mode 100644
> index 0000000000..29fb9424f8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-04-GRO-nontriv.C
> @@ -0,0 +1,109 @@
> +//  { dg-do run }
> +
> +// GRO differs from eventual return type and has non-trivial dtor.
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +
> +  struct nontriv {
> +    handle_type handle;
> +    nontriv () : handle(0) {PRINT("nontriv nul ctor");}
> +    nontriv (handle_type _handle)
> +       : handle(_handle) {
> +        PRINT("Created nontriv object from handle");
> +    }
> +    ~nontriv () {
> +         PRINT("Destroyed nontriv");
> +    }
> +  };
> +
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (nontriv _nt)
> +    : handle(_nt.handle) {
> +        PRINT("Created coro1 object from nontriv");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return nontriv(handle_type::from_promise (*this));
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-05-return-value.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-05-return-value.C
> new file mode 100644
> index 0000000000..42b80ff6bb
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-05-return-value.C
> @@ -0,0 +1,38 @@
> +//  { dg-do run }
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return 42;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C
> new file mode 100644
> index 0000000000..5b1acb8145
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-06-template-promise-val-1.C
> @@ -0,0 +1,105 @@
> +//  { dg-do run }
> +
> +// Test returning a T.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +#include "../coro.h"
> +
> +struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(coro::coroutine_handle<>) const noexcept
> +    { PRINT ("susp-never-susp"); }
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +};
> +
> +/* NOTE: this has a DTOR to test that pathway.  */
> +struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(coro::coroutine_handle<>) const noexcept
> +    { PRINT ("susp-always-susp"); }
> +  void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +  ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +};
> +
> +template <typename T>
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +    PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("coro1 op=  ");
> +    return *this;
> +  }
> +  ~coro1() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct promise_type {
> +  T value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +
> +  auto initial_suspend () const {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () const {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_value (T v) {
> +    PRINTF ("return_value () %d\n",v);
> +    value = v;
> +  }
> +  T get_value (void) { return value; }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +coro1<float>
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return (float) 42;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  coro1<float> x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != (float)42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C
> new file mode 100644
> index 0000000000..b1a06f2849
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-07-void-cast-expr.C
> @@ -0,0 +1,44 @@
> +//  { dg-do run }
> +
> +// Check that "co_return (void)expression;" evaluates expression once.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define RETURN_VOID
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +__attribute__((__noinline__))
> +int foo (void) { PRINT ("called the int fn foo"); gX +=1 ; return gX; }
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return (void)foo();
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  // We want to check that foo() was called exactly once.
> +  if (gX != 2)
> +    {
> +      PRINT ("main: failed check for a single call to foo()");
> +      abort ();
> +    }
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C
> new file mode 100644
> index 0000000000..266bc7b3b2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-08-template-cast-ret.C
> @@ -0,0 +1,104 @@
> +//  { dg-do run }
> +
> +// Test templated co-return.
> +
> +#include "../coro.h"
> +
> +struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(coro::coroutine_handle<>) const noexcept
> +    { PRINT ("susp-never-susp"); }
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +};
> +
> +/* NOTE: this has a DTOR to test that pathway.  */
> +struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(coro::coroutine_handle<>) const noexcept
> +    { PRINT ("susp-always-susp"); }
> +  void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +  ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +};
> +
> +template <typename T>
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +    PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("coro1 op=  ");
> +    return *this;
> +  }
> +  ~coro1() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct promise_type {
> +  T value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  suspend_always_prt initial_suspend () const {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  suspend_always_prt final_suspend () const {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_value (T v) {
> +    PRINTF ("return_value () %d\n",v);
> +    value = v;
> +  }
> +  T get_value (void) { return value; }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +template <typename T>
> +coro1<T> f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return (T)42;
> +}
> +
> +// The test will only really for int, but that's OK here.
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  auto x = f<int>();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C
> new file mode 100644
> index 0000000000..91f3f14cc0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C
> @@ -0,0 +1,97 @@
> +//  { dg-do run }
> +
> +// test boolean return from await_suspend ().
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        PRINT("Destroyed coro1");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  bool await_suspend(handle_type) const noexcept {
> +    PRINT ("susp-never-susp"); // never executed.
> +    return true; // ...
> +  }
> +  void await_resume() const noexcept {PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  bool await_suspend(handle_type) const noexcept {
> +    PRINT ("susp-always-susp, but we're going to continue.. ");
> +    return false; // not going to suspend.
> +  }
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  coro1 get_return_object () {
> +    PRINT ("get_return_object: from handle from promise");
> +    return coro1 (handle_type::from_promise (*this));
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always, but really never) ");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always, but never) ");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  auto p = x.handle.promise ();
> +  auto aw = p.initial_suspend();
> +  auto f = aw.await_suspend(coro::coroutine_handle<coro1::promise_type>::from_address ((void *)&x));
> +  PRINT ("main: got coro1 - should be done");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently was not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C
> new file mode 100644
> index 0000000000..7b07be5f44
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-10-expression-evaluates-once.C
> @@ -0,0 +1,49 @@
> +// { dg-do run }
> +
> +// Check that "co_return expression;" only evaluates expression once.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Give foo() a measureable side-effect.  */
> +int gX = 1;
> +__attribute__((__noinline__))
> +int foo (void)
> +{
> +  PRINT ("called the int fn foo");
> +  gX += 1;
> +  return gX;
> +}
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return foo();
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  // We want to check that foo() was called exactly once.
> +  if (gX != 2)
> +    {
> +      PRINT ("main: failed check for a single call to foo()");
> +      abort ();
> +    }
> +  PRINT ("main: after resume");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C
> new file mode 100644
> index 0000000000..06939107d8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-11-co-ret-co-await.C
> @@ -0,0 +1,40 @@
> +// { dg-do run }
> +
> +// Check co_return co_await
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return co_await coro1::suspend_always_intprt{};
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume 1 (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: after resume 2 (await intprt)");
> +
> +  int y = x.handle.promise().get_value();
> +  if ( y != 5 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C
> new file mode 100644
> index 0000000000..50124c080b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-12-co-ret-fun-co-await.C
> @@ -0,0 +1,48 @@
> +// { dg-do run }
> +
> +// Check co_return function (co_await)
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +__attribute__((__noinline__))
> +static int
> +foo (int x)
> +{
> +  return x + 2;
> +}
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return foo (co_await 5);
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume 1 (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: after resume 2 (await parm)");
> +
> +  int y = x.handle.promise().get_value();
> +  if ( y != 7 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-13-template-2.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-13-template-2.C
> new file mode 100644
> index 0000000000..9d4a4de8eb
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-13-template-2.C
> @@ -0,0 +1,56 @@
> +// { dg-do run }
> +
> +// Check type dependent function parms.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +// there is a promise ctor that takes a single int.
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +coro1
> +f (T y) noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  T x = y;
> +  co_return 3;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f<int>(17);
> +
> +  /* We should have created the promise with an initial value of
> +     17.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 17 )
> +    {
> +      PRINT ("main: wrong promise init.");
> +      abort ();
> +    }
> +
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  /* Now we should have the co_returned value.  */
> +  y = x.handle.promise().get_value();
> +  if ( y != 3 )
> +    {
> +      PRINT ("main: wrong answer.");
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-14-template-3.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-14-template-3.C
> new file mode 100644
> index 0000000000..ebc1adba82
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-14-template-3.C
> @@ -0,0 +1,58 @@
> +// { dg-do run }
> +
> +// Check type dependent function parms.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +// there is a promise ctor that takes a single int.
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T, typename U, typename V>
> +coro1
> +f (T x, U y, V z) noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  T xi = (T) y;
> +  T yi = (T) z;
> +  T zi = x;
> +  co_return 3 + xi + yi + zi;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f<int, float, double>(2, 18.0F, 19.0);
> +
> +  /* We should be using the default promise ctor, which sets the value
> +     to -1.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != -1 )
> +    {
> +      PRINT ("main: wrong promise init.");
> +      abort ();
> +    }
> +
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  /* Now we should have the co_returned value.  */
> +  y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    {
> +      PRINT ("main: wrong answer.");
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-00-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-00-triv.C
> new file mode 100644
> index 0000000000..586b6b2571
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-00-triv.C
> @@ -0,0 +1,129 @@
> +//  { dg-do run }
> +
> +// Test yielding an int.
> +
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +// Check that we resolve the correct overload for the yield_value method.
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("coro1 op=  ");
> +    return *this;
> +  }
> +  ~coro1() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +    bool await_ready() const noexcept { return true; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  };
> +
> +  /* NOTE: this has a DTOR to test that pathway.  */
> +  struct  suspend_always_prt {
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +    ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +  };
> +
> +  struct promise_type {
> +  int value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_value (int v) {
> +    PRINTF ("return_value () %d\n",v);
> +    value = v;
> +  }
> +  auto yield_value (int v) {
> +    PRINTF ("yield_value () %d and suspend always\n",v);
> +    value = v;
> +    return suspend_always_prt{};
> +  }
> +  /* Some non-matching overloads.  */
> +  auto yield_value (suspend_always_prt s, int x) {
> +    return s;
> +  }
> +  auto yield_value (void) {
> +    return 42;
> +  }
> +  int get_value (void) { return value; }
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("f: about to yield 42");
> +  co_yield 42;
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42");
> +  PRINT ("main: got coro1 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-01-multi.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-01-multi.C
> new file mode 100644
> index 0000000000..5df69c7f15
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-01-multi.C
> @@ -0,0 +1,64 @@
> +//  { dg-do run }
> +
> +// Test yielding an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("f: about to yield 42");
> +  co_yield 42;
> +
> +  PRINT ("f: about to yield 11");
> +  co_yield 11;
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 11 )
> +    abort ();
> +  PRINT ("main: apparently got 11 - resuming (3)");
> +  if (x.handle.done())
> +    {
> +   PRINT ("main: done?");
> +   abort();
> +    }
> +  x.handle.resume();
> +  PRINT ("main: after resume (2) checking return");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-02-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-02-loop.C
> new file mode 100644
> index 0000000000..8d4f1d5d82
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-02-loop.C
> @@ -0,0 +1,68 @@
> +//  { dg-do run }
> +
> +// Test co_yield in a loop with no local state.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int gX = 1;
> +
> +struct coro1
> +f () noexcept
> +{
> +  for (gX = 5; gX < 10 ; gX++)
> +    {
> +      PRINTF ("f: about to yield %d\n", gX);
> +      co_yield gX;
> +     }
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (gX != 1)
> +    {
> +      PRINTF ("main: gX is wrong : %d, should be 1\n", gX);
> +      abort ();
> +    }
> +  if (f_coro.handle.done())
> +    abort();
> +  f_coro.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = f_coro.handle.promise().get_value();
> +  if (y != 5)
> +    {
> +      PRINTF ("main: got %d not 5.\n",y);
> +      abort ();
> +    }
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    y = f_coro.handle.promise().get_value();
> +    if (y != gX)
> +      {
> +        PRINTF ("main: got %d not %d.\n",y, gX);
> +        abort ();
> +      }
> +    PRINTF ("main: gX : %d \n", gX);
> +    f_coro.handle.resume();
> +  } while (!f_coro.handle.done());
> +
> +  y = f_coro.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-03-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-03-tmpl.C
> new file mode 100644
> index 0000000000..cceee1f19e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-03-tmpl.C
> @@ -0,0 +1,140 @@
> +//  { dg-do run }
> +
> +// Test co_yield in templated code.
> +
> +#include "../coro.h"
> +
> +template <typename T>
> +struct looper {
> +
> +  struct promise_type {
> +  T value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +
> +  void return_value (T v) {
> +    PRINTF ("return_value () %lf\n", (double)v);
> +    value = v;
> +  }
> +
> +  auto yield_value (T v) {
> +    PRINTF ("yield_value () %lf and suspend always\n", (double)v);
> +    value = v;
> +    return suspend_always_prt{};
> +  }
> +
> +  T get_value (void) { return value; }
> +
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +
> +  using handle_type = coro::coroutine_handle<looper::promise_type>;
> +  handle_type handle;
> +
> +  looper () : handle(0) {}
> +  looper (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  looper (const looper &) = delete; // no copying
> +  looper (looper &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("looper mv ctor ");
> +  }
> +  looper &operator = (looper &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("looper op=  ");
> +    return *this;
> +  }
> +  ~looper() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +    bool await_ready() const noexcept { return true; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  };
> +
> +  /* NOTE: this has a DTOR to test that pathway.  */
> +  struct  suspend_always_prt {
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +    ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +  };
> +
> +};
> +
> +// Contrived to avoid non-scalar state across the yield.
> +template <typename T>
> +looper<T> f () noexcept
> +{
> +  for (int i = 5; i < 10 ; ++i)
> +    {
> +      PRINTF ("f: about to yield %d\n", i);
> +      co_yield (T) i;
> +    }
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +// contrived, only going to work for an int.
> +int main ()
> +{
> +  PRINT ("main: create int looper");
> +  auto f_coro = f<int> ();
> +
> +  if (f_coro.handle.done())
> +    {
> +      PRINT ("main: said we were done, but we hadn't started!");
> +      abort();
> +    }
> +
> +  PRINT ("main: OK -- looping");
> +  int y, test = 5;
> +  do {
> +    f_coro.handle.resume();
> +    if (f_coro.handle.done())
> +      break;
> +    y = f_coro.handle.promise().get_value();
> +    if (y != test)
> +      {
> +       PRINTF ("main: failed for test %d, got %d\n", test, y);
> +       abort();
> +      }
> +    test++;
> +  } while (test < 20);
> +
> +  y = f_coro.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +
> +  PRINT ("main: apparently got 6174");
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-04-complex-local-state.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-04-complex-local-state.C
> new file mode 100644
> index 0000000000..d9330b33b7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-04-complex-local-state.C
> @@ -0,0 +1,162 @@
> +//  { dg-do run }
> +
> +// using non-trivial types in the coro.
> +
> +# include "../coro.h"
> +
> +#include <vector>
> +#include <string>
> +
> +template <typename T>
> +struct looper {
> +
> +  struct promise_type {
> +  T value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +
> +  void return_value (T v) {
> +    PRINTF ("return_value () %s\n",  v.c_str());
> +    value = v;
> +  }
> +
> +  auto yield_value (T v) {
> +    PRINTF ("yield_value () %s and suspend always\n", v.c_str());
> +    value = v;
> +    return suspend_always_prt{};
> +  }
> +
> +  T get_value (void) { return value; }
> +
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +
> +  using handle_type = coro::coroutine_handle<looper::promise_type>;
> +  handle_type handle;
> +
> +  looper () : handle(0) {}
> +  looper (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  looper (const looper &) = delete; // no copying
> +  looper (looper &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("looper mv ctor ");
> +  }
> +  looper &operator = (looper &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("looper op=  ");
> +    return *this;
> +  }
> +  ~looper() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +    bool await_ready() const noexcept { return true; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  };
> +
> +  /* NOTE: this has a DTOR to test that pathway.  */
> +  struct  suspend_always_prt {
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +    ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +  };
> +
> +};
> +
> +int gX ;
> +
> +struct mycounter
> +{
> +  mycounter () : v(0) { PRINT ("mycounter CTOR"); }
> +  ~mycounter () { gX = 6174; PRINT ("mycounter DTOR"); }
> +  int value () { return v; }
> +  void incr () { v++; }
> +  int v;
> +};
> +
> +template <typename T>
> +looper<T> with_ctorable_state (std::vector<T> d) noexcept
> +{
> +  std::vector<T> loc;
> +  unsigned lim = d.size()-1;
> +  mycounter c;
> +  for (unsigned  i = 0; i < lim ; ++i)
> +    {
> +      loc.push_back(d[i]);
> +      c.incr();
> +      PRINTF ("f: about to yield value %d \n", i);
> +      co_yield loc[i];
> +     }
> +  loc.push_back(d[lim]);
> +
> +  PRINT ("f: done");
> +  co_return loc[lim];
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create looper");
> +  std::vector<std::string> input = {"first", "the", "quick", "reddish", "fox", "done" };
> +  auto f_coro = with_ctorable_state<std::string> (input);
> +
> +  PRINT ("main: got looper - resuming (1)");
> +  if (f_coro.handle.done())
> +    abort();
> +
> +  f_coro.handle.resume();
> +  std::string s = f_coro.handle.promise().get_value();
> +  if ( s != "first" )
> +    abort ();
> +
> +  PRINTF ("main: got : %s\n", s.c_str());
> +  unsigned check = 1;
> +  do {
> +    f_coro.handle.resume();
> +    s = f_coro.handle.promise().get_value();
> +    if (s != input[check++])
> +      abort ();
> +    PRINTF ("main: got : %s\n", s.c_str());
> +  } while (!f_coro.handle.done());
> +
> +  if ( s != "done" )
> +    abort ();
> +
> +  PRINT ("main: should be done");
> +  if (!f_coro.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +
> +  if (gX != 6174)
> +    {
> +      PRINT ("main: apparently we didn't run mycounter DTOR...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-05-co-aw.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-05-co-aw.C
> new file mode 100644
> index 0000000000..043f97b6e1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-05-co-aw.C
> @@ -0,0 +1,55 @@
> +// { dg-do run }
> +
> +// Check co_return co_await
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("f: about to yield");
> +  co_yield co_await coro1::suspend_always_intprt(42);
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: resuming (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: resuming (await intprt)");
> +  x.handle.resume();
> +
> +  PRINT ("main: after resume (2)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42");
> +
> +  PRINT ("main: got coro1 - resuming (co_yield)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +
> +  PRINT ("main: after resume (co_yield)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-06-fun-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-06-fun-parm.C
> new file mode 100644
> index 0000000000..c74e44d15d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-06-fun-parm.C
> @@ -0,0 +1,64 @@
> +// { dg-do run }
> +
> +// Check co_return co_await
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +__attribute__((__noinline__))
> +static int
> +foo (int x)
> +{
> +  return x + 2;
> +}
> +
> +/* Function with a single await.  */
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("f: about to yield");
> +  co_yield foo (co_await 40);
> +
> +  PRINT ("f: about to return 6174");
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: resuming (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: resuming (await intprt)");
> +  x.handle.resume();
> +
> +  PRINT ("main: after resume (2)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42");
> +
> +  PRINT ("main: got coro1 - resuming (co_yield)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +
> +  PRINT ("main: after resume (co_yield)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-07-template-fn-param.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-07-template-fn-param.C
> new file mode 100644
> index 0000000000..74dae63395
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-07-template-fn-param.C
> @@ -0,0 +1,71 @@
> +// { dg-do run }
> +
> +// Check type dependent function parms.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +// there is a promise ctor that takes a single int.
> +
> +#include "../coro1-ret-int-yield-int.h"
> +
> +template <typename T>
> +coro1
> +f (T y) noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  T x = y;
> +  co_yield x + 3;
> +  co_return 42;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f<int>(17);
> +
> +  /* We should have created the promise with an initial value of
> +     17.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 17 )
> +    {
> +      PRINTF ("main: wrong promise init (%d).", y);
> +      abort ();
> +    }
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: got coro1 - resuming");
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  if (x.handle.done())
> +    abort();
> +
> +  /* Now we should have the co_yielded value.  */
> +  y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  PRINT ("main: after resume (co_yield)");
> +  x.handle.resume();
> +
> +  /* now we should have the co_returned value.  */
> +  y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-08-more-refs.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-08-more-refs.C
> new file mode 100644
> index 0000000000..8e39127a1a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-08-more-refs.C
> @@ -0,0 +1,68 @@
> +// { dg-do run }
> +
> +// Check co_return co_await
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* Tests for .  */
> +struct test
> +{
> +  auto operator co_await() & noexcept {
> +    return coro1::suspend_always_intprt{};
> +  }
> +
> +  auto operator co_await() && noexcept {
> +    return coro1::suspend_always_longprtsq(3L);
> +  }
> +};
> +
> +struct coro1
> +f (test thing) noexcept
> +{
> +  co_yield co_await static_cast<test&&>(thing);
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +
> +  struct coro1 x = f (test{});
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: resuming (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: resuming (await intprt)");
> +  x.handle.resume();
> +
> +  int y = x.handle.promise().get_value();
> +  if ( y != 9 )
> +    {
> +      PRINTF ("main: co-yield gave %d, should be 9\n", y);
> +      abort ();
> +    }
> +
> +  PRINT ("main: got coro1 - resuming (co_yield)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    {
> +      PRINTF ("main: co-return gave %d, should be 9\n", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C
> new file mode 100644
> index 0000000000..3abbe1c43a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-09-more-templ-refs.C
> @@ -0,0 +1,68 @@
> +// { dg-do run }
> +
> +// Check co_return co_await
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +/* A very simple overload.  */
> +struct test
> +{
> +  auto operator co_await() & noexcept {
> +    return coro1::suspend_always_intprt{};
> +  }
> +
> +  auto operator co_await() && noexcept {
> +    return coro1::suspend_always_longprtsq(3L);
> +  }
> +};
> +
> +template<typename RESULT, typename PARAM>
> +RESULT
> +f (PARAM thing) noexcept
> +{
> +  co_yield co_await static_cast<PARAM&&>(thing);
> +  co_return 6174;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f<coro1, test> (test{});
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: resuming (initial suspend)");
> +  x.handle.resume();
> +  PRINT ("main: resuming (await intprt)");
> +  x.handle.resume();
> +
> +  int y = x.handle.promise().get_value();
> +  if ( y != 9 )
> +    {
> +      PRINTF ("main: co-yield gave %d, should be 9\n", y);
> +      abort ();
> +    }
> +
> +  PRINT ("main: got coro1 - resuming (co_yield)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    {
> +      PRINTF ("main: co-return gave %d, should be 9\n", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp b/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
> new file mode 100644
> index 0000000000..d2463b2798
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
> @@ -0,0 +1,19 @@
> +# This harness is for tests that should be run at all optimisation levels.
> +
> +load_lib g++-dg.exp
> +load_lib torture-options.exp
> +
> +global DG_TORTURE_OPTIONS LTO_TORTURE_OPTIONS
> +
> +dg-init
> +torture-init
> +
> +set DEFAULT_COROFLAGS $DEFAULT_CXXFLAGS
> +lappend DEFAULT_COROFLAGS "-std=c++17" "-fcoroutines"
> +
> +set-torture-options [concat $DG_TORTURE_OPTIONS $LTO_TORTURE_OPTIONS]
> +
> +gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.C]] "" $DEFAULT_COROFLAGS
> +
> +torture-finish
> +dg-finish
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C b/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
> new file mode 100644
> index 0000000000..164c804797
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
> @@ -0,0 +1,167 @@
> +//  { dg-do run }
> +
> +// Test exceptions.
> +
> +#include "../coro.h"
> +#include <exception>
> +
> +int gX = 0;
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    PRINT("coro1 op=  ");
> +    return *this;
> +  }
> +  ~coro1() {
> +    PRINT("Destroyed coro1");
> +    if ( handle )
> +      handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +    bool await_ready() const noexcept { return true; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  };
> +
> +  /* NOTE: this has a DTOR to test that pathway.  */
> +  struct  suspend_always_prt {
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); }
> +    void await_resume() const noexcept { PRINT ("susp-always-resume"); }
> +    ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
> +  };
> +
> +  struct promise_type {
> +  int value;
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { PRINT ("Destroyed Promise"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_value (int v) {
> +    PRINTF ("return_value () %d\n",v);
> +    value = v;
> +  }
> +  auto yield_value (int v) {
> +    PRINTF ("yield_value () %d and suspend always\n",v);
> +    value = v;
> +    return suspend_always_prt{};
> +  }
> +  /* Some non-matching overloads.  */
> +  auto yield_value (suspend_always_prt s, int x) {
> +    return s;
> +  }
> +  auto yield_value (void) {
> +    return 42;//suspend_always_prt{};
> +  }
> +  int get_value (void) { return value; }
> +
> +  void unhandled_exception() {
> +    PRINT ("unhandled_exception: caught one!");
> +    gX = -1;
> +    // returning from here should end up in final_suspend.
> +    }
> +  };
> +};
> +
> +// So we want to check that the internal behaviour of try/catch is
> +// working OK - and that if we have an unhandled exception it is caught
> +// by the wrapper that we add to the rewritten func.
> +
> +struct coro1 throw_and_catch () noexcept
> +{
> +  int caught = 0;
> +
> +  try {
> +    PRINT ("f: about to yield 42");
> +    co_yield 42;
> +
> +    throw (20);
> +
> +    PRINT ("f: about to yield 6174");
> +    co_return 6174;
> +
> +  } catch (int x) {
> +    PRINTF ("f: caught %d\n", x);
> +    caught = x;
> +  }
> +
> +  PRINTF ("f: about to yield what we caught %d\n", caught);
> +  co_yield caught;
> +
> +  throw ("bah");
> +
> +  PRINT ("f: about to return 22");
> +  co_return 22;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = throw_and_catch ();
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: got coro, resuming..");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got the expected 42");
> +  if (x.handle.done())
> +    abort();
> +  PRINT ("main: resuming...");
> +  x.handle.resume();
> +
> +  y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    abort ();
> +  PRINT ("main: apparently got 20, which we expected");
> +  if (x.handle.done())
> +    abort();
> +
> +  PRINT ("main: resuming...");
> +  x.handle.resume();
> +  // This should cause the throw of "bah" which is unhandled.
> +  // We should catch the unhandled exception and then fall through
> +  // to the final suspend point... thus be "done".
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  // When we caught the unhandled exception we flagged it instead of
> +  // std::terminate-ing.
> +  if (gX != -1)
> +    {
> +      PRINT ("main: apparently failed to catch");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-00.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-00.C
> new file mode 100644
> index 0000000000..b5716972d4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-00.C
> @@ -0,0 +1,42 @@
> +//  { dg-do run }
> +
> +// Test promise construction from function args list.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return 42;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (555);
> +  int y = x.handle.promise().get_value();
> +  if ( y != 555 )
> +    {
> +      PRINT ("main: incorrect ctor value");
> +      abort ();
> +    }
> +  PRINTF ("main: after coro1 ctor %d - now resuming\n", y);
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-01.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-01.C
> new file mode 100644
> index 0000000000..f530431a6b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-01.C
> @@ -0,0 +1,45 @@
> +//  { dg-do run }
> +
> +// Simplest test that we correctly handle function params in the body
> +// of the coroutine.  No local state, just the parm.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  if (x > 20)
> +    {
> +      PRINT ("coro1: about to return k");
> +      co_return 6174;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return the answer");
> +      co_return 42;
> +    }
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (32);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-02.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-02.C
> new file mode 100644
> index 0000000000..396b438cb2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-02.C
> @@ -0,0 +1,50 @@
> +//  { dg-do run }
> +
> +// Test that we correctly re-write multiple uses of a function param
> +// in the body.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  if (x > 30)
> +    {
> +      PRINT ("coro1: about to return k");
> +      co_return 6174;
> +    }
> +  else if (x > 20)
> +    {
> +      PRINT ("coro1: about to return the answer");
> +      co_return 42;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return 0");
> +      co_return 0;
> +    }
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (25);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-03.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-03.C
> new file mode 100644
> index 0000000000..bf699722a1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-03.C
> @@ -0,0 +1,49 @@
> +//  { dg-do run }
> +
> +// Test that we can use a function param in a co_xxxx status.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  if (x > 30)
> +    {
> +      PRINT ("coro1: about to return k");
> +      co_return 6174;
> +    }
> +  else if (x > 20)
> +    {
> +      PRINTF ("coro1: about to co-return %d", x);
> +      co_return x;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return 0");
> +      co_return 0;
> +    }
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (25);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 25 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-04.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-04.C
> new file mode 100644
> index 0000000000..789e2c05b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-04.C
> @@ -0,0 +1,57 @@
> +//  { dg-do run }
> +
> +// Test that we can manage a constructed param copy.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +// Require a ctor.
> +struct nontriv {
> +  int a, b, c;
> +  nontriv (int _a, int _b, int _c) : a(_a), b(_b), c(_c) {}
> +  virtual int getA () { return a; }
> +};
> +
> +struct coro1
> +f (nontriv t) noexcept
> +{
> +  if (t.a > 30)
> +    {
> +      PRINTF ("coro1: about to return %d", t.b);
> +      co_return t.b;
> +    }
> +  else if (t.a > 20)
> +    {
> +      PRINTF ("coro1: about to co-return %d", t.c);
> +      co_return t.c;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return 0");
> +      co_return 0;
> +    }
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  nontriv test (25, 6174, 42);
> +  struct coro1 x = f (test);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-05.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-05.C
> new file mode 100644
> index 0000000000..8bdb2b5d0f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-05.C
> @@ -0,0 +1,57 @@
> +//  { dg-do run }
> +
> +// Test that we can manage a constructed param reference
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +// Require a ctor.
> +struct nontriv {
> +  int a, b, c;
> +  nontriv (int _a, int _b, int _c) : a(_a), b(_b), c(_c) {}
> +  virtual int getA () { return a; }
> +};
> +
> +struct coro1
> +f (nontriv &t) noexcept
> +{
> +  if (t.a > 30)
> +    {
> +      PRINTF ("coro1: about to return %d", t.b);
> +      co_return t.b;
> +    }
> +  else if (t.a > 20)
> +    {
> +      PRINTF ("coro1: about to co-return %d", t.c);
> +      co_return t.c;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return 0");
> +      co_return 0;
> +    }
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  nontriv test (25, 6174, 42);
> +  struct coro1 x = f (test);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-06.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-06.C
> new file mode 100644
> index 0000000000..cbcfe67ff1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-06.C
> @@ -0,0 +1,47 @@
> +//  { dg-do run }
> +
> +// check references are handled as expected.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +coro1
> +f (int& a_ref, int a_copy)
> +{
> +    co_yield a_ref + a_copy;
> +    co_return a_ref + a_copy;
> +}
> +
> +int main ()
> +{
> +  int a_copy = 20;
> +  int a_ref = 10;
> +
> +  coro1 A = f (a_ref, a_copy);
> +  A.handle.resume(); // Initial suspend.
> +  PRINT ("main: [a_copy = 20, a_ref = 10]");
> +
> +  int y = A.handle.promise().get_value();
> +  if (y != 30)
> +    {
> +      PRINTF ("main: co-yield = %d, should be 30\n", y);
> +      abort ();
> +    }
> +
> +  a_copy = 5;
> +  a_ref = 7;
> +
> +  A.handle.resume();
> +  PRINT ("main: [a_copy = 5, a_ref = 7]");
> +
> +  y = A.handle.promise().get_value();
> +  if (y != 27)
> +    {
> +      PRINTF ("main: co-ret = %d, should be 27\n", y);
> +      abort ();
> +    }
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-00-co-ret.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-00-co-ret.C
> new file mode 100644
> index 0000000000..61e284d5c8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-00-co-ret.C
> @@ -0,0 +1,35 @@
> +//  { dg-do run }
> +
> +// Simplest lambda
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  auto f = []() -> coro1
> +  {
> +    PRINT ("coro1: about to return");
> +    co_return 42;
> +  };
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-01-co-ret-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-01-co-ret-parm.C
> new file mode 100644
> index 0000000000..378eedc6d8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-01-co-ret-parm.C
> @@ -0,0 +1,48 @@
> +//  { dg-do run }
> +
> +// Lambda with parm
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  auto f = [](int x) -> coro1
> +  {
> +    if (x > 30)
> +     {
> +       PRINT ("coro1: about to return k");
> +       co_return 6174;
> +     }
> +    else if (x > 20)
> +     {
> +       PRINT ("coro1: about to return the answer");
> +       co_return 42;
> +     }
> +    else
> +     {
> +       PRINT ("coro1: about to return 0");
> +       co_return 0;
> +     }
> +  };
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = f (25);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-02-co-yield-values.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-02-co-yield-values.C
> new file mode 100644
> index 0000000000..a6f592cd77
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-02-co-yield-values.C
> @@ -0,0 +1,64 @@
> +//  { dg-do run }
> +
> +// lambda with parm and local state
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  auto f = [](int start) -> coro1
> +  {
> +    int value = start;
> +    PRINT ("f: about to yield start");
> +    co_yield start;
> +
> +    value -= 31;
> +    PRINT ("f: about to yield (value-31)");
> +    co_yield value;
> +
> +    value += 6163;
> +    PRINT ("f: about to return (value+6163)");
> +    co_return value;
> +  };
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = f (42);
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 11 )
> +    abort ();
> +  PRINT ("main: apparently got 11 - resuming (3)");
> +  if (x.handle.done())
> +    {
> +   PRINT ("main: done?");
> +   abort();
> +    }
> +  x.handle.resume();
> +  PRINT ("main: after resume (2) checking return");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-03-auto-parm-1.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-03-auto-parm-1.C
> new file mode 100644
> index 0000000000..bfa5400225
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-03-auto-parm-1.C
> @@ -0,0 +1,46 @@
> +//  { dg-do run }
> +
> +// generic Lambda with auto parm (c++14)
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  auto f = [](auto y) -> coro1
> +  {
> +    PRINT ("coro1: about to return");
> +    auto x = y;
> +    co_return co_await x + 3;
> +  };
> +
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f((int)17);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-04-templ-parm.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-04-templ-parm.C
> new file mode 100644
> index 0000000000..adf31e22db
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-04-templ-parm.C
> @@ -0,0 +1,47 @@
> +// { dg-do run }
> +// { dg-additional-options "-std=c++2a" }
> +
> +// generic Lambda with template parm (from c++20)
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#define USE_AWAIT_TRANSFORM
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  auto f = []<typename T>(T y) -> coro1
> +  {
> +    PRINT ("coro1: about to return");
> +    T x = y;
> +    co_return co_await x + 3;
> +  };
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = f.operator()<int>(17);
> +  if (x.handle.done())
> +    abort();
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (initial suspend)");
> +
> +  x.handle.resume();
> +  PRINT ("main: after resume (co_await)");
> +
> +  /* Now we should have the co_returned value.  */
> +  int y = x.handle.promise().get_value();
> +  if ( y != 20 )
> +    {
> +      PRINTF ("main: wrong result (%d).", y);
> +      abort ();
> +    }
> +
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-05-capture-copy-local.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-05-capture-copy-local.C
> new file mode 100644
> index 0000000000..7cd6648cca
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-05-capture-copy-local.C
> @@ -0,0 +1,66 @@
> +//  { dg-do run }
> +
> +// lambda with parm and local state
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  int local = 31;
> +
> +  auto f = [=](int start) -> coro1
> +  {
> +    int value = start;
> +    PRINT ("f: about to yield start");
> +    co_yield start;
> +
> +    value -= local;
> +    PRINT ("f: about to yield (value-31)");
> +    co_yield value;
> +
> +    value += 6163;
> +    PRINT ("f: about to return (value+6163)");
> +    co_return value;
> +  };
> +
> +  PRINT ("main: create coro1");
> +  coro1 x = f (42);
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 11 )
> +    abort ();
> +  PRINT ("main: apparently got 11 - resuming (3)");
> +  if (x.handle.done())
> +    {
> +   PRINT ("main: done?");
> +   abort();
> +    }
> +  x.handle.resume();
> +  PRINT ("main: after resume (2) checking return");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-06-multi-capture.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-06-multi-capture.C
> new file mode 100644
> index 0000000000..7b445d3d9c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-06-multi-capture.C
> @@ -0,0 +1,48 @@
> +//  { dg-do run }
> +
> +// lambda with parm and local state
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  int a_copy = 20;
> +  int a_ref = 10;
> +
> +  auto f = [&, a_copy]() -> coro1
> +  {
> +    co_return a_ref + a_copy;
> +  };
> +
> +  {
> +    coro1 A = f ();
> +    A.handle.resume();
> +    PRINT ("main: [a_copy = 20, a_ref = 10]");
> +
> +    int y = A.handle.promise().get_value();
> +    if (y != 30)
> +      {
> +       PRINTF ("main: A co-ret = %d, should be 30\n", y);
> +       abort ();
> +      }
> +  }
> +
> +  a_copy = 5;
> +  a_ref = 7;
> +
> +  coro1 B = f ();
> +  B.handle.resume();
> +  PRINT ("main: [a_copy = 5, a_ref = 7]");
> +
> +  int y = B.handle.promise().get_value();
> +  if (y != 27)
> +    {
> +      PRINTF ("main: B co-ret = %d, should be 27\n", y);
> +      abort ();
> +    }
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-yield.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-yield.C
> new file mode 100644
> index 0000000000..2bd58cbf2e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-yield.C
> @@ -0,0 +1,46 @@
> +//  { dg-do run }
> +
> +// lambda with parm and local state
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  int a_copy = 20;
> +  int a_ref = 10;
> +
> +  auto f = [&, a_copy]() -> coro1
> +  {
> +    co_yield a_ref + a_copy;
> +    co_return a_ref + a_copy;
> +  };
> +
> +  coro1 A = f ();
> +  A.handle.resume(); // Initial suspend.
> +  PRINT ("main: [a_copy = 20, a_ref = 10]");
> +
> +  int y = A.handle.promise().get_value();
> +  if (y != 30)
> +    {
> +      PRINTF ("main: co-yield = %d, should be 30\n", y);
> +      abort ();
> +    }
> +
> +  a_copy = 5;
> +  a_ref = 7;
> +
> +  A.handle.resume();
> +  PRINT ("main: [a_copy = 5, a_ref = 7]");
> +
> +  y = A.handle.promise().get_value();
> +  if (y != 27)
> +    {
> +      PRINTF ("main: co-ret = %d, should be 27\n", y);
> +      abort ();
> +    }
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C
> new file mode 100644
> index 0000000000..4d5a44fe29
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-08-co-ret-parm-ref.C
> @@ -0,0 +1,59 @@
> +//  { dg-do run }
> +
> +// Test that we can use a function param in a co_xxxx status.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +int main ()
> +{
> +  int val;
> +
> +  auto f = [&] (int x) -> coro1
> +  {
> +    if (val + x > 25)
> +      {
> +        PRINT ("coro1: about to return k");
> +        co_return 6174;
> +      }
> +    else if (val + x > 20)
> +      {
> +        PRINTF ("coro1: about to co-return %d\n", val + x);
> +        co_return val + x;
> +      }
> +    else if (val + x > 5)
> +      {
> +        PRINTF ("coro1: about to co-return %d\n", val);
> +        co_return val;
> +      }
> +    else
> +      {
> +        PRINT ("coro1: about to return 0");
> +        co_return 0;
> +      }
> +  };
> +
> +  PRINT ("main: create coro1");
> +
> +  val = 20;  // We should get this by ref.
> +  int arg = 5; // and this as a regular parm.
> +
> +  coro1 x = f (arg);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 25 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
> new file mode 100644
> index 0000000000..a8956457dc
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
> @@ -0,0 +1,37 @@
> +//  { dg-do run }
> +
> +// Simplest local decl.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f () noexcept
> +{
> +  const int answer = 42;
> +  PRINTF ("coro1: about to return %d\n", answer);
> +  co_return answer;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
> new file mode 100644
> index 0000000000..69a5b70756
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
> @@ -0,0 +1,37 @@
> +//  { dg-do run }
> +
> +// Simplest local var
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  int answer = x + 6132;
> +  PRINTF ("coro1: about to return %d\n", answer);
> +  co_return answer;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (42);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
> new file mode 100644
> index 0000000000..f232edabda
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
> @@ -0,0 +1,50 @@
> +//  { dg-do run }
> +
> +// Test local vars in nested scopes
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int x) noexcept
> +{
> +  int y = x;
> +  const int test = 20;
> +  if (y > test)
> +    {
> +      int fred = y - 20;
> +      PRINTF ("coro1: about to return %d\n", fred);
> +      co_return fred;
> +    }
> +  else
> +    {
> +      PRINT ("coro1: about to return the answer\n");
> +      co_return y;
> +    }
> +
> +  co_return x;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (6194);
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
> new file mode 100644
> index 0000000000..bd06db53d4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
> @@ -0,0 +1,65 @@
> +//  { dg-do run }
> +
> +// Test modifying a local var and yielding several instances of it.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int start) noexcept
> +{
> +  int value = start;
> +  PRINT ("f: about to yield start");
> +  co_yield start;
> +
> +  value -= 31;
> +  PRINT ("f: about to yield (value-31)");
> +  co_yield value;
> +
> +  value += 6163;
> +  PRINT ("f: about to return (value+6163)");
> +  co_return value;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (42);
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 42 )
> +    abort ();
> +  PRINT ("main: apparently got 42 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 11 )
> +    abort ();
> +  PRINT ("main: apparently got 11 - resuming (3)");
> +  if (x.handle.done())
> +    {
> +   PRINT ("main: done?");
> +   abort();
> +    }
> +  x.handle.resume();
> +  PRINT ("main: after resume (2) checking return");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
> new file mode 100644
> index 0000000000..419eb6b646
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
> @@ -0,0 +1,75 @@
> +//  { dg-do run }
> +
> +// Test modifying a local var across nested scopes containing vars
> +// hiding those at outer scopes.
> +
> +#include "../coro.h"
> +
> +// boiler-plate for tests of codegen
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct coro1
> +f (int start) noexcept
> +{
> +  int value = start;
> +  {
> +    int value = start + 5;
> +    {
> +       int value = start + 20;
> +    }
> +    {
> +       int value = start + 1;
> +       PRINT ("f: about to yield start");
> +       co_yield value;
> +    }
> +  }
> +
> +  value -= 31;
> +  PRINT ("f: about to yield (value-31)");
> +  co_yield value;
> +
> +  value += 6163;
> +  PRINT ("f: about to return (value+6163)");
> +  co_return value;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f (42);
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = x.handle.promise().get_value();
> +  if ( y != 43 )
> +    abort ();
> +  PRINT ("main: apparently got 42 - resuming (2)");
> +  if (x.handle.done())
> +    abort();
> +  x.handle.resume();
> +  PRINT ("main: after resume (2)");
> +  y = x.handle.promise().get_value();
> +  if ( y != 11 )
> +    abort ();
> +  PRINT ("main: apparently got 11 - resuming (3)");
> +  if (x.handle.done())
> +    {
> +   PRINT ("main: done?");
> +   abort();
> +    }
> +  x.handle.resume();
> +  PRINT ("main: after resume (2) checking return");
> +  y = x.handle.promise().get_value();
> +  if ( y != 6174 )
> +    abort ();
> +  PRINT ("main: apparently got 6174");
> +  if (!x.handle.done())
> +    {
> +      PRINT ("main: apparently not done...");
> +      abort ();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C b/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
> new file mode 100644
> index 0000000000..934fb19de7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
> @@ -0,0 +1,107 @@
> +// { dg-do run }
> +// { dg-output "main: returning\n" }
> +// { dg-output "Destroyed coro1\n" }
> +// { dg-output "Destroyed suspend_always_prt\n" }
> +// { dg-output "Destroyed Promise\n" }
> +
> +// Check that we still get the right DTORs run when we let a suspended coro
> +// go out of scope.
> +
> +#include "../coro.h"
> +
> +struct coro1 {
> +  struct promise_type;
> +  using handle_type = coro::coroutine_handle<coro1::promise_type>;
> +  handle_type handle;
> +  coro1 () : handle(0) {}
> +  coro1 (handle_type _handle)
> +    : handle(_handle) {
> +        PRINT("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +       s.handle = nullptr;
> +       PRINT("coro1 mv ctor ");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +       handle = s.handle;
> +       s.handle = nullptr;
> +       PRINT("coro1 op=  ");
> +       return *this;
> +  }
> +  ~coro1() {
> +        printf ("Destroyed coro1\n");
> +        if ( handle )
> +          handle.destroy();
> +  }
> +
> +  struct suspend_never_prt {
> +  bool await_ready() const noexcept { return true; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-never-resume");}
> +  ~suspend_never_prt() {};
> +  };
> +
> +  struct  suspend_always_prt {
> +  bool await_ready() const noexcept { return false; }
> +  void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
> +  void await_resume() const noexcept { PRINT ("susp-always-resume");}
> +  ~suspend_always_prt() { printf ("Destroyed suspend_always_prt\n"); }
> +  };
> +
> +  struct promise_type {
> +  promise_type() {  PRINT ("Created Promise"); }
> +  ~promise_type() { printf ("Destroyed Promise\n"); }
> +
> +  auto get_return_object () {
> +    PRINT ("get_return_object: handle from promise");
> +    return handle_type::from_promise (*this);
> +  }
> +  auto initial_suspend () {
> +    PRINT ("get initial_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +
> +  void unhandled_exception() { PRINT ("** unhandled exception"); }
> +  };
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 x = f ();
> +  PRINT ("main: got coro1 - resuming");
> +  if (x.handle.done())
> +    {
> +      PRINT ("main: f() should be suspended, says it's done");
> +      abort();
> +    }
> +
> +#if __has_builtin (__builtin_coro_suspended)
> +  if (! __builtin_coro_suspended(handle))
> +    {
> +      PRINT ("main: f() should be suspended, but says it isn't");
> +      abort();
> +    }
> +#endif
> +
> +  /* We are suspended... so let everything out of scope and therefore
> +     destroy it.  */
> +
> +  puts ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr92933.C b/gcc/testsuite/g++.dg/coroutines/torture/pr92933.C
> new file mode 100644
> index 0000000000..b2f1be78b3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/pr92933.C
> @@ -0,0 +1,18 @@
> +//  { dg-do compile }
> +
> +// Test that we compile the simple case described in PR 92933
> +
> +#include "../coro.h"
> +
> +#define RETURN_VOID
> +#include "../coro1-ret-int-yield-int.h"
> +
> +struct some_error {};
> +
> +coro1
> +foo() {
> +    try {
> +        co_return;
> +    } catch (some_error) {
> +    }
> +}
> --
> 2.14.3



More information about the Libstdc++ mailing list