diff mbox series

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

Message ID 4D28389F-09A8-4777-9CCD-8E91E7C24524@sandoe.co.uk
State New
Headers show
Series [C++,coroutines,1/7] Common code and base definitions. | expand

Commit Message

Iain Sandoe Jan. 9, 2020, 12:39 p.m. UTC
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?
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

Comments

Richard Biener Jan. 9, 2020, 1:12 p.m. UTC | #1
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
diff mbox series

Patch

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) {
+    }
+}