diff mbox series

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

Message ID BCAC2431-0DF3-4592-AC8B-2C8912743D4A@sandoe.co.uk
State New
Headers show
Series Implement C++ coroutines. | expand

Commit Message

Iain Sandoe Nov. 17, 2019, 10:28 a.m. UTC
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).

gcc/testsuite/ChangeLog:

2019-11-17  Iain Sandoe  <iain@sandoe.co.uk>

	* g++.dg/coroutines/co-yield-syntax-1.C: New test.
	* g++.dg/coroutines/co-yield-syntax-2.C: New test.
	* g++.dg/coroutines/co-yield-syntax-3.C: New test.
	* g++.dg/coroutines/coro-auto-fn.C: New test.
	* g++.dg/coroutines/coro-await-context-auto-fn.C: New test.
	* g++.dg/coroutines/coro-bad-return.C: New test.
	* g++.dg/coroutines/coro-builtins.C: New test.
	* g++.dg/coroutines/coro-constexpr-fn.C: New test.
	* g++.dg/coroutines/coro-context-ctor-dtor.C: New test.
	* g++.dg/coroutines/coro-context-main.C: New test.
	* g++.dg/coroutines/coro-context-vararg.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 test.
	* g++.dg/coroutines/coroutines.exp: New file.
	* g++.dg/coroutines/torture/co-await-0-triv.C: New test.
	* g++.dg/coroutines/torture/co-await-1-value.C: New test.
	* g++.dg/coroutines/torture/co-await-2-xform.C: New test.
	* g++.dg/coroutines/torture/co-await-3-rhs-op.C: New test.
	* g++.dg/coroutines/torture/co-await-4-control-flow.C: New test.
	* g++.dg/coroutines/torture/co-await-5-loop.C: New test.
	* g++.dg/coroutines/torture/co-await-6-ovl.C: New test.
	* g++.dg/coroutines/torture/co-await-7-tmpl.C: New test.
	* g++.dg/coroutines/torture/co-await-8-cascade.C: New test.
	* g++.dg/coroutines/torture/co-await-9-pair.C: New test.
	* g++.dg/coroutines/torture/co-ret-3.C: New test.
	* g++.dg/coroutines/torture/co-ret-4.C: New test.
	* g++.dg/coroutines/torture/co-ret-5.C: New test.
	* g++.dg/coroutines/torture/co-ret-6.C: New test.
	* g++.dg/coroutines/torture/co-ret-7.C: New test.
	* g++.dg/coroutines/torture/co-ret-8.C: New test.
	* g++.dg/coroutines/torture/co-ret-9.C: New test.
	* g++.dg/coroutines/torture/co-ret-void-is-ready.C: New test.
	* g++.dg/coroutines/torture/co-ret-void-is-suspend.C: New test.
	* g++.dg/coroutines/torture/co-yield-0-triv.C: New test.
	* g++.dg/coroutines/torture/co-yield-1-multi.C: New test.
	* g++.dg/coroutines/torture/co-yield-2-loop.C: New test.
	* g++.dg/coroutines/torture/co-yield-3-tmpl.C: New test.
	* g++.dg/coroutines/torture/co-yield-strings.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-0.C: New test.
	* g++.dg/coroutines/torture/func-params-1.C: New test.
	* g++.dg/coroutines/torture/func-params-2.C: New test.
	* g++.dg/coroutines/torture/func-params-3.C: New test.
	* g++.dg/coroutines/torture/func-params-4.C: New test.
	* g++.dg/coroutines/torture/func-params-5.C: New test.
	* g++.dg/coroutines/torture/gro_on_alloc_fail_0.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/co-yield-syntax-1.C          |   6 +
 .../g++.dg/coroutines/co-yield-syntax-2.C          |   6 +
 .../g++.dg/coroutines/co-yield-syntax-3.C          |  37 ++++
 gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C     |  12 ++
 .../g++.dg/coroutines/coro-await-context-auto-fn.C |  16 ++
 gcc/testsuite/g++.dg/coroutines/coro-bad-return.C  |  48 ++++++
 gcc/testsuite/g++.dg/coroutines/coro-builtins.C    |  17 ++
 .../g++.dg/coroutines/coro-constexpr-fn.C          |  12 ++
 .../g++.dg/coroutines/coro-context-ctor-dtor.C     |   8 +
 .../g++.dg/coroutines/coro-context-main.C          |   7 +
 .../g++.dg/coroutines/coro-context-vararg.C        |  13 ++
 gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C |  32 ++++
 .../g++.dg/coroutines/coro-missing-promise-yield.C |  35 ++++
 .../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         |  14 ++
 .../g++.dg/coroutines/coro-missing-ueh-2.C         |  16 ++
 .../g++.dg/coroutines/coro-missing-ueh-3.C         |  17 ++
 gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h |  25 +++
 gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C    |   9 +
 gcc/testsuite/g++.dg/coroutines/coro.h             | 123 ++++++++++++++
 gcc/testsuite/g++.dg/coroutines/coroutines.exp     |  50 ++++++
 .../g++.dg/coroutines/torture/co-await-0-triv.C    | 144 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-1-value.C   | 149 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-2-xform.C   | 155 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-3-rhs-op.C  | 155 +++++++++++++++++
 .../coroutines/torture/co-await-4-control-flow.C   | 148 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-5-loop.C    | 147 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-6-ovl.C     | 153 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-7-tmpl.C    | 149 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-8-cascade.C | 157 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-await-9-pair.C    | 155 +++++++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C | 112 ++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C | 129 ++++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C | 122 +++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C | 125 ++++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C | 114 +++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C | 126 ++++++++++++++
 gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C | 118 +++++++++++++
 .../coroutines/torture/co-ret-void-is-ready.C      | 107 ++++++++++++
 .../coroutines/torture/co-ret-void-is-suspend.C    | 111 ++++++++++++
 .../g++.dg/coroutines/torture/co-yield-0-triv.C    | 146 ++++++++++++++++
 .../g++.dg/coroutines/torture/co-yield-1-multi.C   | 159 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-yield-2-loop.C    | 153 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-yield-3-tmpl.C    | 160 +++++++++++++++++
 .../g++.dg/coroutines/torture/co-yield-strings.C   | 182 ++++++++++++++++++++
 .../g++.dg/coroutines/torture/coro-torture.exp     |  19 +++
 .../g++.dg/coroutines/torture/exceptions-test-0.C  | 189 +++++++++++++++++++++
 .../g++.dg/coroutines/torture/func-params-0.C      | 126 ++++++++++++++
 .../g++.dg/coroutines/torture/func-params-1.C      | 130 ++++++++++++++
 .../g++.dg/coroutines/torture/func-params-2.C      | 134 +++++++++++++++
 .../g++.dg/coroutines/torture/func-params-3.C      | 133 +++++++++++++++
 .../g++.dg/coroutines/torture/func-params-4.C      | 141 +++++++++++++++
 .../g++.dg/coroutines/torture/func-params-5.C      | 141 +++++++++++++++
 .../coroutines/torture/gro_on_alloc_fail_0.C       | 137 +++++++++++++++
 .../g++.dg/coroutines/torture/local-var-0.C        | 123 ++++++++++++++
 .../g++.dg/coroutines/torture/local-var-1.C        | 123 ++++++++++++++
 .../g++.dg/coroutines/torture/local-var-2.C        | 135 +++++++++++++++
 .../g++.dg/coroutines/torture/local-var-3.C        | 153 +++++++++++++++++
 .../g++.dg/coroutines/torture/local-var-4.C        | 162 ++++++++++++++++++
 .../coroutines/torture/mid-suspend-destruction-0.C | 127 ++++++++++++++
 61 files changed, 5920 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-builtins.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-main.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-vararg.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/coroutines.exp
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.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-0.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.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

Comments

Richard Biener Nov. 19, 2019, 10 a.m. UTC | #1
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.

Richard.

> gcc/testsuite/ChangeLog:
>
> 2019-11-17  Iain Sandoe  <iain@sandoe.co.uk>
>
>         * g++.dg/coroutines/co-yield-syntax-1.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-2.C: New test.
>         * g++.dg/coroutines/co-yield-syntax-3.C: New test.
>         * g++.dg/coroutines/coro-auto-fn.C: New test.
>         * g++.dg/coroutines/coro-await-context-auto-fn.C: New test.
>         * g++.dg/coroutines/coro-bad-return.C: New test.
>         * g++.dg/coroutines/coro-builtins.C: New test.
>         * g++.dg/coroutines/coro-constexpr-fn.C: New test.
>         * g++.dg/coroutines/coro-context-ctor-dtor.C: New test.
>         * g++.dg/coroutines/coro-context-main.C: New test.
>         * g++.dg/coroutines/coro-context-vararg.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 test.
>         * g++.dg/coroutines/coroutines.exp: New file.
>         * g++.dg/coroutines/torture/co-await-0-triv.C: New test.
>         * g++.dg/coroutines/torture/co-await-1-value.C: New test.
>         * g++.dg/coroutines/torture/co-await-2-xform.C: New test.
>         * g++.dg/coroutines/torture/co-await-3-rhs-op.C: New test.
>         * g++.dg/coroutines/torture/co-await-4-control-flow.C: New test.
>         * g++.dg/coroutines/torture/co-await-5-loop.C: New test.
>         * g++.dg/coroutines/torture/co-await-6-ovl.C: New test.
>         * g++.dg/coroutines/torture/co-await-7-tmpl.C: New test.
>         * g++.dg/coroutines/torture/co-await-8-cascade.C: New test.
>         * g++.dg/coroutines/torture/co-await-9-pair.C: New test.
>         * g++.dg/coroutines/torture/co-ret-3.C: New test.
>         * g++.dg/coroutines/torture/co-ret-4.C: New test.
>         * g++.dg/coroutines/torture/co-ret-5.C: New test.
>         * g++.dg/coroutines/torture/co-ret-6.C: New test.
>         * g++.dg/coroutines/torture/co-ret-7.C: New test.
>         * g++.dg/coroutines/torture/co-ret-8.C: New test.
>         * g++.dg/coroutines/torture/co-ret-9.C: New test.
>         * g++.dg/coroutines/torture/co-ret-void-is-ready.C: New test.
>         * g++.dg/coroutines/torture/co-ret-void-is-suspend.C: New test.
>         * g++.dg/coroutines/torture/co-yield-0-triv.C: New test.
>         * g++.dg/coroutines/torture/co-yield-1-multi.C: New test.
>         * g++.dg/coroutines/torture/co-yield-2-loop.C: New test.
>         * g++.dg/coroutines/torture/co-yield-3-tmpl.C: New test.
>         * g++.dg/coroutines/torture/co-yield-strings.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-0.C: New test.
>         * g++.dg/coroutines/torture/func-params-1.C: New test.
>         * g++.dg/coroutines/torture/func-params-2.C: New test.
>         * g++.dg/coroutines/torture/func-params-3.C: New test.
>         * g++.dg/coroutines/torture/func-params-4.C: New test.
>         * g++.dg/coroutines/torture/func-params-5.C: New test.
>         * g++.dg/coroutines/torture/gro_on_alloc_fail_0.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/co-yield-syntax-1.C          |   6 +
>  .../g++.dg/coroutines/co-yield-syntax-2.C          |   6 +
>  .../g++.dg/coroutines/co-yield-syntax-3.C          |  37 ++++
>  gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C     |  12 ++
>  .../g++.dg/coroutines/coro-await-context-auto-fn.C |  16 ++
>  gcc/testsuite/g++.dg/coroutines/coro-bad-return.C  |  48 ++++++
>  gcc/testsuite/g++.dg/coroutines/coro-builtins.C    |  17 ++
>  .../g++.dg/coroutines/coro-constexpr-fn.C          |  12 ++
>  .../g++.dg/coroutines/coro-context-ctor-dtor.C     |   8 +
>  .../g++.dg/coroutines/coro-context-main.C          |   7 +
>  .../g++.dg/coroutines/coro-context-vararg.C        |  13 ++
>  gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C |  32 ++++
>  .../g++.dg/coroutines/coro-missing-promise-yield.C |  35 ++++
>  .../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         |  14 ++
>  .../g++.dg/coroutines/coro-missing-ueh-2.C         |  16 ++
>  .../g++.dg/coroutines/coro-missing-ueh-3.C         |  17 ++
>  gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h |  25 +++
>  gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C    |   9 +
>  gcc/testsuite/g++.dg/coroutines/coro.h             | 123 ++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/coroutines.exp     |  50 ++++++
>  .../g++.dg/coroutines/torture/co-await-0-triv.C    | 144 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-1-value.C   | 149 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-2-xform.C   | 155 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-3-rhs-op.C  | 155 +++++++++++++++++
>  .../coroutines/torture/co-await-4-control-flow.C   | 148 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-5-loop.C    | 147 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-6-ovl.C     | 153 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-7-tmpl.C    | 149 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-8-cascade.C | 157 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-await-9-pair.C    | 155 +++++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C | 112 ++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C | 129 ++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C | 122 +++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C | 125 ++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C | 114 +++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C | 126 ++++++++++++++
>  gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C | 118 +++++++++++++
>  .../coroutines/torture/co-ret-void-is-ready.C      | 107 ++++++++++++
>  .../coroutines/torture/co-ret-void-is-suspend.C    | 111 ++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-0-triv.C    | 146 ++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-1-multi.C   | 159 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-2-loop.C    | 153 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-3-tmpl.C    | 160 +++++++++++++++++
>  .../g++.dg/coroutines/torture/co-yield-strings.C   | 182 ++++++++++++++++++++
>  .../g++.dg/coroutines/torture/coro-torture.exp     |  19 +++
>  .../g++.dg/coroutines/torture/exceptions-test-0.C  | 189 +++++++++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-0.C      | 126 ++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-1.C      | 130 ++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-2.C      | 134 +++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-3.C      | 133 +++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-4.C      | 141 +++++++++++++++
>  .../g++.dg/coroutines/torture/func-params-5.C      | 141 +++++++++++++++
>  .../coroutines/torture/gro_on_alloc_fail_0.C       | 137 +++++++++++++++
>  .../g++.dg/coroutines/torture/local-var-0.C        | 123 ++++++++++++++
>  .../g++.dg/coroutines/torture/local-var-1.C        | 123 ++++++++++++++
>  .../g++.dg/coroutines/torture/local-var-2.C        | 135 +++++++++++++++
>  .../g++.dg/coroutines/torture/local-var-3.C        | 153 +++++++++++++++++
>  .../g++.dg/coroutines/torture/local-var-4.C        | 162 ++++++++++++++++++
>  .../coroutines/torture/mid-suspend-destruction-0.C | 127 ++++++++++++++
>  61 files changed, 5920 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-builtins.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-main.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-vararg.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/coroutines.exp
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.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-0.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
>  create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.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
>
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
> new file mode 100644
> index 0000000..30db0e9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.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-2.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
> new file mode 100644
> index 0000000..71e119f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.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-3.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
> new file mode 100644
> index 0000000..20a5b56
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
> @@ -0,0 +1,37 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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/coro-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
> new file mode 100644
> index 0000000..93a04dc
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.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/coro-await-context-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
> new file mode 100644
> index 0000000..7f4ed9a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.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/coro-bad-return.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
> new file mode 100644
> index 0000000..e5b848d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
> @@ -0,0 +1,48 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "coro.h"
> +#endif
> +namespace coro = std::experimental;
> +
> +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 "return statement not allowed" }
> +{
> +  if (x)
> +    return Coro();
> +  else
> +    co_return;
> +}
> 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 0000000..d7c4883
> --- /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-constexpr-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
> new file mode 100644
> index 0000000..69b109f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-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/coro-context-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
> new file mode 100644
> index 0000000..9396432
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-main.C b/gcc/testsuite/g++.dg/coroutines/coro-context-main.C
> new file mode 100644
> index 0000000..40d7e4e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-vararg.C b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
> new file mode 100644
> index 0000000..55a0295
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
> @@ -0,0 +1,13 @@
> +//  { 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/coro-missing-gro.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> new file mode 100644
> index 0000000..8bedb77
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> @@ -0,0 +1,32 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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 0000000..95f567f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
> @@ -0,0 +1,35 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +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 0000000..fd81ce7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
> @@ -0,0 +1,34 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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 0000000..17a2180
> --- /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"
> +
> +namespace coro = std::experimental;
> +
> +/* 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 0000000..964b9f1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
> @@ -0,0 +1,14 @@
> +//  { dg-additional-options "-fsyntax-only -fexceptions -w" }
> +#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 0000000..caf8fb9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
> @@ -0,0 +1,16 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions " }
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +// The missing method is warned for when exceptions are off and pedantic
> +// is on (default in the testsuite).
> +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 0000000..f6ca196
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
> @@ -0,0 +1,17 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions -Wno-pedantic" }
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +/* We don't warn about the missing method, unless in pedantic mode, so
> +   this compile should be clean.  */
> +
> +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 0000000..7a32354
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
> @@ -0,0 +1,25 @@
> +#ifndef __MissingUEH_H
> +#define __MissingUEH_H
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing unhandled_exception() in the promise type.  */
> +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 0000000..f22a5e0
> --- /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 0000000..64df497
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro.h
> @@ -0,0 +1,123 @@
> +#if __has_include(<experimental/coroutine>)
> +
> +#include <experimental/coroutine>
> +
> +#else
> +#ifndef __CORO_H_n4835
> +#define __CORO_H_n4835
> +
> +// Fragments (with short-cuts) to mimic enough of the library header to
> +// make some progress.
> +
> +#if __cpp_coroutines
> +
> +namespace std {
> +namespace experimental {
> +inline namespace coroutines_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);
> +    }
> +    bool suspended_p () const {
> +      return __builtin_coro_is_suspended (__fr_ptr);
> +    }
> +  protected:
> +    void *__fr_ptr;
> +
> +  private:
> +    bool __is_suspended() const noexcept  {
> +      return __builtin_coro_is_suspended (__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 std::experimental::coroutines_n4775
> +
> +#else
> +# error "coro.h requires support for coroutines, add -fcoroutines"
> +#endif
> +#endif // __CORO_H_n4835
> +
> +#endif
> diff --git a/gcc/testsuite/g++.dg/coroutines/coroutines.exp b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> new file mode 100644
> index 0000000..0696cc8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> @@ -0,0 +1,50 @@
> +#   Copyright (C) 2018-2019 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/co-await-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
> new file mode 100644
> index 0000000..000d083
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
> @@ -0,0 +1,144 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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) {
> +        puts("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    puts("Moved coro1");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    return *this;
> +  }
> +  ~coro1() {
> +    puts("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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* The simplest valued co_await we can do.  */
> +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]");
> +  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-1-value.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
> new file mode 100644
> index 0000000..cdc7b92
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
> @@ -0,0 +1,149 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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) {
> +        puts("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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* The simplest valued co_await we can do.  */
> +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]");
> +  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-2-xform.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
> new file mode 100644
> index 0000000..3b1bb71
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +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]");
> +  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-3-rhs-op.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
> new file mode 100644
> index 0000000..1fb54f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  gX = co_await 11 + 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]");
> +  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 (15) */
> +  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-4-control-flow.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
> new file mode 100644
> index 0000000..594dfe5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
> @@ -0,0 +1,148 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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-5-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
> new file mode 100644
> index 0000000..86223be
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
> @@ -0,0 +1,147 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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();
> +  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-6-ovl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
> new file mode 100644
> index 0000000..fc67246
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  struct empty {
> +    auto operator co_await() const noexcept {
> +      return suspend_always_prt{};
> +    }
> +  };
> +};
> +
> +
> +/* The simplest valued co_await we can do.  */
> +int gX = 1;
> +coro1::empty e{};
> +
> +coro1
> +f ()
> +{
> +  co_await (e); /* overload */
> +  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]");
> +  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-7-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
> new file mode 100644
> index 0000000..032e35f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
> @@ -0,0 +1,149 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 an int.  */
> +  struct suspend_always_intprt {
> +    T x;
> +    suspend_always_intprt() : x(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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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-8-cascade.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
> new file mode 100644
> index 0000000..f3504d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
> @@ -0,0 +1,157 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 * x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +coro1 f ()
> +{
> +  /* the await transform takes an int, the await_resume squares it.
> +     so we get 11 ** 4, 14641.  */
> +  gX = co_await 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] - nested");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] - 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-9-pair.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
> new file mode 100644
> index 0000000..8713adf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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] one side of add");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [1] 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-ret-3.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
> new file mode 100644
> index 0000000..f57c4e9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
> @@ -0,0 +1,112 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from the eventual return type.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
> new file mode 100644
> index 0000000..d85199e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
> @@ -0,0 +1,129 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from eventual return type and has non-trivial dtor.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
> new file mode 100644
> index 0000000..0eb0055
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
> @@ -0,0 +1,122 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
> new file mode 100644
> index 0000000..1aad1b1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
> @@ -0,0 +1,125 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning a T.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-7.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
> new file mode 100644
> index 0000000..0af0922
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
> @@ -0,0 +1,114 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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");}
> +  };
> +
> +  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 {
> +  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{};
> +    //return std::experimental::suspend_always{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +__attribute__((__noinline__))
> +int foo (void) { PRINT ("called the int fn foo");  return 2; }
> +
> +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();
> +  PRINT ("main: after resume");
> +  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-8.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
> new file mode 100644
> index 0000000..f79201c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
> @@ -0,0 +1,126 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test templated co-return.
> +
> +/* 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__));
> +
> +#define BROKEN
> +
> +#ifndef OUTPUT
> +#  define PRINT(X)
> +#  define PRINTF (void)
> +#else
> +#  define PRINT(X) puts(X)
> +#  define PRINTF printf
> +#endif
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-9.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
> new file mode 100644
> index 0000000..b2dd776
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
> @@ -0,0 +1,118 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* boolean return from await_suspend ().  */
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  //__builtin_coro_promise ((void*)0, 16, true);
> +  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-void-is-ready.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
> new file mode 100644
> index 0000000..f5662d1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
> @@ -0,0 +1,107 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  //__builtin_coro_promise ((void*)0, 16, true);
> +  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-void-is-suspend.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
> new file mode 100644
> index 0000000..bc2ab1e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
> @@ -0,0 +1,111 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
> new file mode 100644
> index 0000000..4d76a99
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
> @@ -0,0 +1,146 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-1-multi.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
> new file mode 100644
> index 0000000..341af61
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
> @@ -0,0 +1,159 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-2-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
> new file mode 100644
> index 0000000..53851d9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +int gX ;
> +
> +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;
> +
> +  //co_return 0;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (f_coro.handle.done())
> +    abort();
> +  f_coro.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = f_coro.handle.promise().get_value();
> +
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    //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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
> new file mode 100644
> index 0000000..b1659e8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
> @@ -0,0 +1,160 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test co_yield in templated code.
> +
> +/* 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
> +
> +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; }
> +
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  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-strings.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
> new file mode 100644
> index 0000000..9c953ba
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
> @@ -0,0 +1,182 @@
> +//  { dg-do run }
> +
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +#include <vector>
> +#include <string>
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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; }
> +
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  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 ();
> +      //x.handle.resume();
> +    }
> +
> +  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/coro-torture.exp b/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
> new file mode 100644
> index 0000000..d2463b2
> --- /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 0000000..9601564
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
> @@ -0,0 +1,189 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +#include <exception>
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {
> +    PRINT ("unhandled_exception: caught one!");/*exit(1);*/
> +    gX = -1;
> +    // returning from here should end up in final_suspend.
> +    //std::terminate ();
> +    }
> +  };
> +};
> +
> +// 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-0.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
> new file mode 100644
> index 0000000..308f7ef
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
> @@ -0,0 +1,126 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test promise construction from function args list.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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(int x) : value (x) {  PRINTF ("Created Promise with %d\n", x); }
> +  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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 )
> +    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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
> new file mode 100644
> index 0000000..4408ae1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
> @@ -0,0 +1,130 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
> new file mode 100644
> index 0000000..2d97e76
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
> @@ -0,0 +1,134 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we correctly re-write multiple uses of a function param
> +// in the body.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
> new file mode 100644
> index 0000000..1242b13
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
> @@ -0,0 +1,133 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can use a function param in a co_xxxx status.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
> new file mode 100644
> index 0000000..729aae6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
> @@ -0,0 +1,141 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can manage a constructed param copy.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +// 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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
> new file mode 100644
> index 0000000..e0c3d2f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
> @@ -0,0 +1,141 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can manage a constructed param copy.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +// 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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
> new file mode 100644
> index 0000000..40a3620
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
> @@ -0,0 +1,137 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// check the code-gen for the failed alloc return.
> +
> +#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
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..f78787b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
> @@ -0,0 +1,123 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..9dd7ab3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
> @@ -0,0 +1,123 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..886c913
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
> @@ -0,0 +1,135 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..53b7e71
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test modifying a local var and yielding several instances of it.
> +
> +/* 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
> +
> +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{};
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..5d4c0ff
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
> @@ -0,0 +1,162 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test modifying a local var and yielding several instances of it.
> +
> +/* 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
> +
> +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{};
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..6e68688
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
> @@ -0,0 +1,127 @@
> +// { 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.
> +
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from the eventual return type.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 (! x.handle.suspended_p())
> +    {
> +      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;
> +}
> --
> 2.8.1
>
>
JunMa Nov. 20, 2019, 11:12 a.m. UTC | #2
在 2019/11/17 下午6:28, Iain Sandoe 写道:
> 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).
>
> gcc/testsuite/ChangeLog:
>
> 2019-11-17  Iain Sandoe  <iain@sandoe.co.uk>
>
> 	* g++.dg/coroutines/co-yield-syntax-1.C: New test.
> 	* g++.dg/coroutines/co-yield-syntax-2.C: New test.
> 	* g++.dg/coroutines/co-yield-syntax-3.C: New test.
> 	* g++.dg/coroutines/coro-auto-fn.C: New test.
> 	* g++.dg/coroutines/coro-await-context-auto-fn.C: New test.
> 	* g++.dg/coroutines/coro-bad-return.C: New test.
> 	* g++.dg/coroutines/coro-builtins.C: New test.
> 	* g++.dg/coroutines/coro-constexpr-fn.C: New test.
> 	* g++.dg/coroutines/coro-context-ctor-dtor.C: New test.
> 	* g++.dg/coroutines/coro-context-main.C: New test.
> 	* g++.dg/coroutines/coro-context-vararg.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 test.
> 	* g++.dg/coroutines/coroutines.exp: New file.
> 	* g++.dg/coroutines/torture/co-await-0-triv.C: New test.
> 	* g++.dg/coroutines/torture/co-await-1-value.C: New test.
> 	* g++.dg/coroutines/torture/co-await-2-xform.C: New test.
> 	* g++.dg/coroutines/torture/co-await-3-rhs-op.C: New test.
> 	* g++.dg/coroutines/torture/co-await-4-control-flow.C: New test.
> 	* g++.dg/coroutines/torture/co-await-5-loop.C: New test.
> 	* g++.dg/coroutines/torture/co-await-6-ovl.C: New test.
> 	* g++.dg/coroutines/torture/co-await-7-tmpl.C: New test.
> 	* g++.dg/coroutines/torture/co-await-8-cascade.C: New test.
> 	* g++.dg/coroutines/torture/co-await-9-pair.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-3.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-4.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-5.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-6.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-7.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-8.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-9.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-void-is-ready.C: New test.
> 	* g++.dg/coroutines/torture/co-ret-void-is-suspend.C: New test.
> 	* g++.dg/coroutines/torture/co-yield-0-triv.C: New test.
> 	* g++.dg/coroutines/torture/co-yield-1-multi.C: New test.
> 	* g++.dg/coroutines/torture/co-yield-2-loop.C: New test.
> 	* g++.dg/coroutines/torture/co-yield-3-tmpl.C: New test.
> 	* g++.dg/coroutines/torture/co-yield-strings.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-0.C: New test.
> 	* g++.dg/coroutines/torture/func-params-1.C: New test.
> 	* g++.dg/coroutines/torture/func-params-2.C: New test.
> 	* g++.dg/coroutines/torture/func-params-3.C: New test.
> 	* g++.dg/coroutines/torture/func-params-4.C: New test.
> 	* g++.dg/coroutines/torture/func-params-5.C: New test.
> 	* g++.dg/coroutines/torture/gro_on_alloc_fail_0.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/co-yield-syntax-1.C          |   6 +
>   .../g++.dg/coroutines/co-yield-syntax-2.C          |   6 +
>   .../g++.dg/coroutines/co-yield-syntax-3.C          |  37 ++++
>   gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C     |  12 ++
>   .../g++.dg/coroutines/coro-await-context-auto-fn.C |  16 ++
>   gcc/testsuite/g++.dg/coroutines/coro-bad-return.C  |  48 ++++++
>   gcc/testsuite/g++.dg/coroutines/coro-builtins.C    |  17 ++
>   .../g++.dg/coroutines/coro-constexpr-fn.C          |  12 ++
>   .../g++.dg/coroutines/coro-context-ctor-dtor.C     |   8 +
>   .../g++.dg/coroutines/coro-context-main.C          |   7 +
>   .../g++.dg/coroutines/coro-context-vararg.C        |  13 ++
>   gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C |  32 ++++
>   .../g++.dg/coroutines/coro-missing-promise-yield.C |  35 ++++
>   .../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         |  14 ++
>   .../g++.dg/coroutines/coro-missing-ueh-2.C         |  16 ++
>   .../g++.dg/coroutines/coro-missing-ueh-3.C         |  17 ++
>   gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h |  25 +++
>   gcc/testsuite/g++.dg/coroutines/coro-pre-proc.C    |   9 +
>   gcc/testsuite/g++.dg/coroutines/coro.h             | 123 ++++++++++++++
>   gcc/testsuite/g++.dg/coroutines/coroutines.exp     |  50 ++++++
>   .../g++.dg/coroutines/torture/co-await-0-triv.C    | 144 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-1-value.C   | 149 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-2-xform.C   | 155 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-3-rhs-op.C  | 155 +++++++++++++++++
>   .../coroutines/torture/co-await-4-control-flow.C   | 148 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-5-loop.C    | 147 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-6-ovl.C     | 153 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-7-tmpl.C    | 149 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-8-cascade.C | 157 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-await-9-pair.C    | 155 +++++++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C | 112 ++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C | 129 ++++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C | 122 +++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C | 125 ++++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C | 114 +++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C | 126 ++++++++++++++
>   gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C | 118 +++++++++++++
>   .../coroutines/torture/co-ret-void-is-ready.C      | 107 ++++++++++++
>   .../coroutines/torture/co-ret-void-is-suspend.C    | 111 ++++++++++++
>   .../g++.dg/coroutines/torture/co-yield-0-triv.C    | 146 ++++++++++++++++
>   .../g++.dg/coroutines/torture/co-yield-1-multi.C   | 159 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-yield-2-loop.C    | 153 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-yield-3-tmpl.C    | 160 +++++++++++++++++
>   .../g++.dg/coroutines/torture/co-yield-strings.C   | 182 ++++++++++++++++++++
>   .../g++.dg/coroutines/torture/coro-torture.exp     |  19 +++
>   .../g++.dg/coroutines/torture/exceptions-test-0.C  | 189 +++++++++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-0.C      | 126 ++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-1.C      | 130 ++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-2.C      | 134 +++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-3.C      | 133 +++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-4.C      | 141 +++++++++++++++
>   .../g++.dg/coroutines/torture/func-params-5.C      | 141 +++++++++++++++
>   .../coroutines/torture/gro_on_alloc_fail_0.C       | 137 +++++++++++++++
>   .../g++.dg/coroutines/torture/local-var-0.C        | 123 ++++++++++++++
>   .../g++.dg/coroutines/torture/local-var-1.C        | 123 ++++++++++++++
>   .../g++.dg/coroutines/torture/local-var-2.C        | 135 +++++++++++++++
>   .../g++.dg/coroutines/torture/local-var-3.C        | 153 +++++++++++++++++
>   .../g++.dg/coroutines/torture/local-var-4.C        | 162 ++++++++++++++++++
>   .../coroutines/torture/mid-suspend-destruction-0.C | 127 ++++++++++++++
>   61 files changed, 5920 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-builtins.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-main.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/coro-context-vararg.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/coroutines.exp
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.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-0.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
>   create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.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
>
> diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
> new file mode 100644
> index 0000000..30db0e9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.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-2.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
> new file mode 100644
> index 0000000..71e119f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.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-3.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
> new file mode 100644
> index 0000000..20a5b56
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
> @@ -0,0 +1,37 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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/coro-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
> new file mode 100644
> index 0000000..93a04dc
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.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/coro-await-context-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
> new file mode 100644
> index 0000000..7f4ed9a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.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/coro-bad-return.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
> new file mode 100644
> index 0000000..e5b848d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
> @@ -0,0 +1,48 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "coro.h"
> +#endif
> +namespace coro = std::experimental;
> +
> +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 "return statement not allowed" }
> +{
> +  if (x)
> +    return Coro();
> +  else
> +    co_return;
> +}
> 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 0000000..d7c4883
> --- /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-constexpr-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
> new file mode 100644
> index 0000000..69b109f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-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/coro-context-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
> new file mode 100644
> index 0000000..9396432
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-main.C b/gcc/testsuite/g++.dg/coroutines/coro-context-main.C
> new file mode 100644
> index 0000000..40d7e4e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-vararg.C b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
> new file mode 100644
> index 0000000..55a0295
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
> @@ -0,0 +1,13 @@
> +//  { 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/coro-missing-gro.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> new file mode 100644
> index 0000000..8bedb77
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
> @@ -0,0 +1,32 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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 0000000..95f567f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
> @@ -0,0 +1,35 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +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 0000000..fd81ce7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
> @@ -0,0 +1,34 @@
> +//  { dg-additional-options "-fsyntax-only -w" }
> +#include "coro.h"
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing return_void() in the promise type.  */
> +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 0000000..17a2180
> --- /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"
> +
> +namespace coro = std::experimental;
> +
> +/* 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 0000000..964b9f1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
> @@ -0,0 +1,14 @@
> +//  { dg-additional-options "-fsyntax-only -fexceptions -w" }
> +#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 0000000..caf8fb9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
> @@ -0,0 +1,16 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions " }
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +// The missing method is warned for when exceptions are off and pedantic
> +// is on (default in the testsuite).
> +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 0000000..f6ca196
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
> @@ -0,0 +1,17 @@
> +//  { dg-additional-options "-fsyntax-only -fno-exceptions -Wno-pedantic" }
> +#include "coro.h"
> +#include "coro-missing-ueh.h"
> +
> +/* We don't warn about the missing method, unless in pedantic mode, so
> +   this compile should be clean.  */
> +
> +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 0000000..7a32354
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
> @@ -0,0 +1,25 @@
> +#ifndef __MissingUEH_H
> +#define __MissingUEH_H
> +
> +namespace coro = std::experimental;
> +
> +/* Diagose missing unhandled_exception() in the promise type.  */
> +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 0000000..f22a5e0
> --- /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 0000000..64df497
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coro.h
> @@ -0,0 +1,123 @@
> +#if __has_include(<experimental/coroutine>)
> +
> +#include <experimental/coroutine>
> +
> +#else
> +#ifndef __CORO_H_n4835
> +#define __CORO_H_n4835
> +
> +// Fragments (with short-cuts) to mimic enough of the library header to
> +// make some progress.
> +
> +#if __cpp_coroutines
> +
> +namespace std {
> +namespace experimental {
> +inline namespace coroutines_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);
> +    }
> +    bool suspended_p () const {
> +      return __builtin_coro_is_suspended (__fr_ptr);
> +    }
> +  protected:
> +    void *__fr_ptr;
> +
> +  private:
> +    bool __is_suspended() const noexcept  {
> +      return __builtin_coro_is_suspended (__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 std::experimental::coroutines_n4775
> +
> +#else
> +# error "coro.h requires support for coroutines, add -fcoroutines"
> +#endif
> +#endif // __CORO_H_n4835
> +
> +#endif
> diff --git a/gcc/testsuite/g++.dg/coroutines/coroutines.exp b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> new file mode 100644
> index 0000000..0696cc8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
> @@ -0,0 +1,50 @@
> +#   Copyright (C) 2018-2019 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/co-await-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
> new file mode 100644
> index 0000000..000d083
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
> @@ -0,0 +1,144 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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) {
> +        puts("Created coro1 object from handle");
> +  }
> +  coro1 (const coro1 &) = delete; // no copying
> +  coro1 (coro1 &&s) : handle(s.handle) {
> +    s.handle = nullptr;
> +    puts("Moved coro1");
> +  }
> +  coro1 &operator = (coro1 &&s) {
> +    handle = s.handle;
> +    s.handle = nullptr;
> +    return *this;
> +  }
> +  ~coro1() {
> +    puts("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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* The simplest valued co_await we can do.  */
> +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]");
> +  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-1-value.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
> new file mode 100644
> index 0000000..cdc7b92
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
> @@ -0,0 +1,149 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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) {
> +        puts("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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* The simplest valued co_await we can do.  */
> +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]");
> +  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-2-xform.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
> new file mode 100644
> index 0000000..3b1bb71
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +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]");
> +  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-3-rhs-op.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
> new file mode 100644
> index 0000000..1fb54f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +
> +coro1
> +f ()
> +{
> +  gX = co_await 11 + 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]");
> +  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 (15) */
> +  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-4-control-flow.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
> new file mode 100644
> index 0000000..594dfe5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
> @@ -0,0 +1,148 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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-5-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
> new file mode 100644
> index 0000000..86223be
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
> @@ -0,0 +1,147 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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();
> +  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-6-ovl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
> new file mode 100644
> index 0000000..fc67246
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) {}
> +    ~suspend_always_intprt() {}
> +    bool await_ready() const noexcept { return false; }
> +    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
> +    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  struct empty {
> +    auto operator co_await() const noexcept {
> +      return suspend_always_prt{};
> +    }
> +  };
> +};
> +
> +
> +/* The simplest valued co_await we can do.  */
> +int gX = 1;
> +coro1::empty e{};
> +
> +coro1
> +f ()
> +{
> +  co_await (e); /* overload */
> +  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]");
> +  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-7-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
> new file mode 100644
> index 0000000..032e35f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
> @@ -0,0 +1,149 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 an int.  */
> +  struct suspend_always_intprt {
> +    T x;
> +    suspend_always_intprt() : x(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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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-8-cascade.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
> new file mode 100644
> index 0000000..f3504d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
> @@ -0,0 +1,157 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 * x;}
> +  };
> +
> +  struct promise_type {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* Valued with an await_transform.  */
> +int gX = 1;
> +coro1 f ()
> +{
> +  /* the await transform takes an int, the await_resume squares it.
> +     so we get 11 ** 4, 14641.  */
> +  gX = co_await 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] - nested");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [2] - 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-9-pair.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
> new file mode 100644
> index 0000000..8713adf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
> @@ -0,0 +1,155 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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 {
> +    int 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 an int.  */
> +  struct suspend_always_intprt {
> +    int x;
> +    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
> +    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
> +  int 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 () %d\n",v);
> +    value = v;
> +  }
> +
> +  auto await_transform (int v) {
> +    PRINTF ("await_transform an int () %d\n",v);
> +    return suspend_always_intprt (v);
> +  }
> +
> +  int get_value () { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +/* 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] one side of add");
> +  f_coro.handle.resume();
> +  PRINT ("main: resuming [1] 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-ret-3.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
> new file mode 100644
> index 0000000..f57c4e9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
> @@ -0,0 +1,112 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from the eventual return type.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
> new file mode 100644
> index 0000000..d85199e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
> @@ -0,0 +1,129 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from eventual return type and has non-trivial dtor.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
> new file mode 100644
> index 0000000..0eb0055
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
> @@ -0,0 +1,122 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
> new file mode 100644
> index 0000000..1aad1b1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
> @@ -0,0 +1,125 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning a T.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-7.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
> new file mode 100644
> index 0000000..0af0922
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
> @@ -0,0 +1,114 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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");}
> +  };
> +
> +  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 {
> +  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{};
> +    //return std::experimental::suspend_always{};
> +  }
> +  auto final_suspend () {
> +    PRINT ("get final_suspend (always)");
> +    return suspend_always_prt{};
> +  }
> +  void return_void () {
> +    PRINT ("return_void ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +__attribute__((__noinline__))
> +int foo (void) { PRINT ("called the int fn foo");  return 2; }
> +
> +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();
> +  PRINT ("main: after resume");
> +  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-8.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
> new file mode 100644
> index 0000000..f79201c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
> @@ -0,0 +1,126 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test templated co-return.
> +
> +/* 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__));
> +
> +#define BROKEN
> +
> +#ifndef OUTPUT
> +#  define PRINT(X)
> +#  define PRINTF (void)
> +#else
> +#  define PRINT(X) puts(X)
> +#  define PRINTF printf
> +#endif
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-9.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
> new file mode 100644
> index 0000000..b2dd776
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
> @@ -0,0 +1,118 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* boolean return from await_suspend ().  */
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  //__builtin_coro_promise ((void*)0, 16, true);
> +  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-void-is-ready.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
> new file mode 100644
> index 0000000..f5662d1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
> @@ -0,0 +1,107 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +struct coro1
> +f () noexcept
> +{
> +  PRINT ("coro1: about to return");
> +  co_return;
> +}
> +
> +int main ()
> +{
> +  //__builtin_coro_promise ((void*)0, 16, true);
> +  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-void-is-suspend.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
> new file mode 100644
> index 0000000..bc2ab1e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
> @@ -0,0 +1,111 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +  //int x;
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
> new file mode 100644
> index 0000000..4d76a99
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
> @@ -0,0 +1,146 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-1-multi.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
> new file mode 100644
> index 0000000..341af61
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
> @@ -0,0 +1,159 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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-2-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
> new file mode 100644
> index 0000000..53851d9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +int gX ;
> +
> +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;
> +
> +  //co_return 0;
> +}
> +
> +int main ()
> +{
> +  PRINT ("main: create coro1");
> +  struct coro1 f_coro = f ();
> +  PRINT ("main: got coro1 - resuming (1)");
> +  if (f_coro.handle.done())
> +    abort();
> +  f_coro.handle.resume();
> +  PRINT ("main: after resume (1)");
> +  int y = f_coro.handle.promise().get_value();
> +
> +  PRINT ("main: gX OK -- looping");
> +  do {
> +    //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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
> new file mode 100644
> index 0000000..b1659e8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
> @@ -0,0 +1,160 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test co_yield in templated code.
> +
> +/* 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
> +
> +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; }
> +
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  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-strings.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
> new file mode 100644
> index 0000000..9c953ba
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
> @@ -0,0 +1,182 @@
> +//  { dg-do run }
> +
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +#include <vector>
> +#include <string>
> +
> +namespace coro = std::experimental;
> +
> +/* 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
> +
> +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; }
> +
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +
> +  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 ();
> +      //x.handle.resume();
> +    }
> +
> +  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/coro-torture.exp b/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
> new file mode 100644
> index 0000000..d2463b2
> --- /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 0000000..9601564
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
> @@ -0,0 +1,189 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +#include <exception>
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {
> +    PRINT ("unhandled_exception: caught one!");/*exit(1);*/
> +    gX = -1;
> +    // returning from here should end up in final_suspend.
> +    //std::terminate ();
> +    }
> +  };
> +};
> +
> +// 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-0.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
> new file mode 100644
> index 0000000..308f7ef
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
> @@ -0,0 +1,126 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test promise construction from function args list.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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(int x) : value (x) {  PRINTF ("Created Promise with %d\n", x); }
> +  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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 )
> +    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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
> new file mode 100644
> index 0000000..4408ae1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
> @@ -0,0 +1,130 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
> new file mode 100644
> index 0000000..2d97e76
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
> @@ -0,0 +1,134 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we correctly re-write multiple uses of a function param
> +// in the body.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
> new file mode 100644
> index 0000000..1242b13
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
> @@ -0,0 +1,133 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can use a function param in a co_xxxx status.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
> new file mode 100644
> index 0000000..729aae6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
> @@ -0,0 +1,141 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can manage a constructed param copy.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +// 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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
> new file mode 100644
> index 0000000..e0c3d2f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
> @@ -0,0 +1,141 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test that we can manage a constructed param copy.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +// 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 ();
> +      //x.handle.resume();
> +    }
> +  PRINT ("main: returning");
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
> new file mode 100644
> index 0000000..40a3620
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
> @@ -0,0 +1,137 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// check the code-gen for the failed alloc return.
> +
> +#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
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..f78787b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
> @@ -0,0 +1,123 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..9dd7ab3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
> @@ -0,0 +1,123 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 ();
> +      //x.handle.resume();
> +    }
> +  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 0000000..886c913
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
> @@ -0,0 +1,135 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test returning an int.
> +// We will use the promise to contain this to avoid having to include
> +// additional C++ headers.
> +
> +/* 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
> +
> +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;
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..53b7e71
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
> @@ -0,0 +1,153 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test modifying a local var and yielding several instances of it.
> +
> +/* 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
> +
> +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{};
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..5d4c0ff
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
> @@ -0,0 +1,162 @@
> +//  { dg-do run }
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// Test modifying a local var and yielding several instances of it.
> +
> +/* 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
> +
> +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{};
> +  }
> +  int get_value (void) { return value; }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 0000000..6e68688
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
> @@ -0,0 +1,127 @@
> +// { 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.
> +
> +#if __clang__
> +# include <experimental/coroutine>
> +# include <utility>
> +#else
> +# include "../coro.h"
> +#endif
> +
> +namespace coro = std::experimental;
> +
> +// GRO differs from the eventual return type.
> +
> +/* 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)
> +#else
> +#  define PRINT(X) puts(X)
> +#endif
> +
> +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 ()");
> +  }
> +  // Placeholder to satisfy parser, not doing exceptions yet.
> +  void unhandled_exception() {  /*exit(1);*/ }
> +  };
> +};
> +
> +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 (! x.handle.suspended_p())
> +    {
> +      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;
> +}

I find that the patches donot support 'for co_await'. And it is
quiet simple to implement range based 'for co_await' based on your
patches, since it's just need few more works on range for source to
source transform. Any reason for that?

Regards
JunMa
Iain Sandoe Nov. 20, 2019, 11:22 a.m. UTC | #3
Hello JunMa,

JunMa <JunMa@linux.alibaba.com> wrote:

> 在 2019/11/17 下午6:28, Iain Sandoe 写道:

> I find that the patches donot support 'for co_await'. And it is
> quiet simple to implement range based 'for co_await' based on your
> patches, since it's just need few more works on range for source to
> source transform. Any reason for that?

If I understand your question correctly,

for example TS n4775, there was:

[stmt.stmt]
  ….
  for co_await ( for-range-declaration : for-range-initializer ) statement

yes?

This was removed by a later committee resolution, and was *not* merged
to the C++20 Working Draft (I am currently working to n4835).

So, the reason it is not implemented in GCC at present, is that it is not clear
exactly what form it might take if introduced in some future proposal for
enhanced coroutines.

hope that answers the question,
thanks
Iain
JunMa Nov. 20, 2019, 1:11 p.m. UTC | #4
在 2019/11/20 下午7:22, Iain Sandoe 写道:
> Hello JunMa,
>
> JunMa <JunMa@linux.alibaba.com> wrote:
>
>> 在 2019/11/17 下午6:28, Iain Sandoe 写道:
>> I find that the patches donot support 'for co_await'. And it is
>> quiet simple to implement range based 'for co_await' based on your
>> patches, since it's just need few more works on range for source to
>> source transform. Any reason for that?
> If I understand your question correctly,
>
> for example TS n4775, there was:
>
> [stmt.stmt]
>    ….
>    for co_await ( for-range-declaration : for-range-initializer ) statement
>
> yes?
>
> This was removed by a later committee resolution, and was *not* merged
> to the C++20 Working Draft (I am currently working to n4835).
>
> So, the reason it is not implemented in GCC at present, is that it is not clear
> exactly what form it might take if introduced in some future proposal for
> enhanced coroutines.
>
> hope that answers the question,
> thanks
> Iain
Hi Iain,
     Thanks, that make sense.

Regards
JunMa
JunMa Jan. 7, 2020, 2:42 p.m. UTC | #5
在 2019/11/20 下午9:11, JunMa 写道:
> 在 2019/11/20 下午7:22, Iain Sandoe 写道:
>> Hello JunMa,
>>
>> JunMa <JunMa@linux.alibaba.com> wrote:
>>
>>> 在 2019/11/17 下午6:28, Iain Sandoe 写道:
>>> I find that the patches donot support 'for co_await'. And it is
>>> quiet simple to implement range based 'for co_await' based on your
>>> patches, since it's just need few more works on range for source to
>>> source transform. Any reason for that?
>> If I understand your question correctly,
>>
>> for example TS n4775, there was:
>>
>> [stmt.stmt]
>>    ….
>>    for co_await ( for-range-declaration : for-range-initializer ) 
>> statement
>>
>> yes?
>>
>> This was removed by a later committee resolution, and was *not* merged
>> to the C++20 Working Draft (I am currently working to n4835).
>>
>> So, the reason it is not implemented in GCC at present, is that it is 
>> not clear
>> exactly what form it might take if introduced in some future proposal 
>> for
>> enhanced coroutines.
>>
>> hope that answers the question,
>> thanks
>> Iain
> Hi Iain,
>     Thanks, that make sense.
>
> Regards
> JunMa
Hi Iain

In current implementation of the allocating storage for coroutine,
it does not follow the rules in n4835 which look up in the scope of
the promise type first. Is there any reason? If not, would youimplement
this following the rules of n4835? Thanks.

Regards
JunMa
diff mbox series

Patch

diff --git a/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.C
new file mode 100644
index 0000000..30db0e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-1.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-2.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.C
new file mode 100644
index 0000000..71e119f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-2.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-3.C b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
new file mode 100644
index 0000000..20a5b56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/co-yield-syntax-3.C
@@ -0,0 +1,37 @@ 
+//  { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+namespace coro = std::experimental;
+
+/* Diagose missing return_void() in the promise type.  */
+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/coro-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.C
new file mode 100644
index 0000000..93a04dc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-auto-fn.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/coro-await-context-auto-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.C
new file mode 100644
index 0000000..7f4ed9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-await-context-auto-fn.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/coro-bad-return.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
new file mode 100644
index 0000000..e5b848d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-return.C
@@ -0,0 +1,48 @@ 
+//  { dg-additional-options "-fsyntax-only -w" }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "coro.h"
+#endif
+namespace coro = std::experimental;
+
+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 "return statement not allowed" }
+{
+  if (x)
+    return Coro(); 
+  else
+    co_return;
+}
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 0000000..d7c4883
--- /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-constexpr-fn.C b/gcc/testsuite/g++.dg/coroutines/coro-constexpr-fn.C
new file mode 100644
index 0000000..69b109f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-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/coro-context-ctor-dtor.C b/gcc/testsuite/g++.dg/coroutines/coro-context-ctor-dtor.C
new file mode 100644
index 0000000..9396432
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-main.C b/gcc/testsuite/g++.dg/coroutines/coro-context-main.C
new file mode 100644
index 0000000..40d7e4e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-context-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/coro-context-vararg.C b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
new file mode 100644
index 0000000..55a0295
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-context-vararg.C
@@ -0,0 +1,13 @@ 
+//  { 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/coro-missing-gro.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
new file mode 100644
index 0000000..8bedb77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-gro.C
@@ -0,0 +1,32 @@ 
+//  { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+namespace coro = std::experimental;
+
+/* Diagose missing return_void() in the promise type.  */
+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 0000000..95f567f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-promise-yield.C
@@ -0,0 +1,35 @@ 
+//  { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+namespace coro = std::experimental;
+
+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 0000000..fd81ce7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ret-value.C
@@ -0,0 +1,34 @@ 
+//  { dg-additional-options "-fsyntax-only -w" }
+#include "coro.h"
+
+namespace coro = std::experimental;
+
+/* Diagose missing return_void() in the promise type.  */
+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 0000000..17a2180
--- /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"
+
+namespace coro = std::experimental;
+
+/* 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 0000000..964b9f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-1.C
@@ -0,0 +1,14 @@ 
+//  { dg-additional-options "-fsyntax-only -fexceptions -w" }
+#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 0000000..caf8fb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-2.C
@@ -0,0 +1,16 @@ 
+//  { dg-additional-options "-fsyntax-only -fno-exceptions " }
+#include "coro.h"
+#include "coro-missing-ueh.h"
+
+// The missing method is warned for when exceptions are off and pedantic
+// is on (default in the testsuite).
+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 0000000..f6ca196
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh-3.C
@@ -0,0 +1,17 @@ 
+//  { dg-additional-options "-fsyntax-only -fno-exceptions -Wno-pedantic" }
+#include "coro.h"
+#include "coro-missing-ueh.h"
+
+/* We don't warn about the missing method, unless in pedantic mode, so
+   this compile should be clean.  */
+
+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 0000000..7a32354
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-ueh.h
@@ -0,0 +1,25 @@ 
+#ifndef __MissingUEH_H
+#define __MissingUEH_H
+
+namespace coro = std::experimental;
+
+/* Diagose missing unhandled_exception() in the promise type.  */
+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 0000000..f22a5e0
--- /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 0000000..64df497
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coro.h
@@ -0,0 +1,123 @@ 
+#if __has_include(<experimental/coroutine>)
+
+#include <experimental/coroutine>
+
+#else
+#ifndef __CORO_H_n4835
+#define __CORO_H_n4835
+
+// Fragments (with short-cuts) to mimic enough of the library header to
+// make some progress.
+
+#if __cpp_coroutines
+
+namespace std {
+namespace experimental {
+inline namespace coroutines_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);
+    }
+    bool suspended_p () const {
+      return __builtin_coro_is_suspended (__fr_ptr);
+    }
+  protected:
+    void *__fr_ptr;
+
+  private:
+    bool __is_suspended() const noexcept  {
+      return __builtin_coro_is_suspended (__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 std::experimental::coroutines_n4775
+
+#else
+# error "coro.h requires support for coroutines, add -fcoroutines"
+#endif
+#endif // __CORO_H_n4835
+
+#endif
diff --git a/gcc/testsuite/g++.dg/coroutines/coroutines.exp b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
new file mode 100644
index 0000000..0696cc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/coroutines.exp
@@ -0,0 +1,50 @@ 
+#   Copyright (C) 2018-2019 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/co-await-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
new file mode 100644
index 0000000..000d083
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-0-triv.C
@@ -0,0 +1,144 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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) {
+        puts("Created coro1 object from handle");
+  }
+  coro1 (const coro1 &) = delete; // no copying
+  coro1 (coro1 &&s) : handle(s.handle) {
+    s.handle = nullptr;
+    puts("Moved coro1");
+  }
+  coro1 &operator = (coro1 &&s) {
+    handle = s.handle;
+    s.handle = nullptr;
+    return *this;
+  }
+  ~coro1() {
+    puts("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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) {}
+    ~suspend_always_intprt() {}
+    bool await_ready() const noexcept { return false; }
+    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
+    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
+  };
+
+  struct promise_type {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* The simplest valued co_await we can do.  */
+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]");
+  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-1-value.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
new file mode 100644
index 0000000..cdc7b92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-1-value.C
@@ -0,0 +1,149 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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) {
+        puts("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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) {}
+    ~suspend_always_intprt() {}
+    bool await_ready() const noexcept { return false; }
+    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
+    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
+  };
+
+  struct promise_type {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* The simplest valued co_await we can do.  */
+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]");
+  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-2-xform.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
new file mode 100644
index 0000000..3b1bb71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-2-xform.C
@@ -0,0 +1,155 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* Valued with an await_transform.  */
+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]");
+  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-3-rhs-op.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
new file mode 100644
index 0000000..1fb54f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-3-rhs-op.C
@@ -0,0 +1,155 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* Valued with an await_transform.  */
+int gX = 1;
+
+coro1
+f ()
+{
+  gX = co_await 11 + 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]");
+  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 (15) */
+  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-4-control-flow.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
new file mode 100644
index 0000000..594dfe5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-4-control-flow.C
@@ -0,0 +1,148 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* 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-5-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
new file mode 100644
index 0000000..86223be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-5-loop.C
@@ -0,0 +1,147 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* 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();
+  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-6-ovl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
new file mode 100644
index 0000000..fc67246
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-6-ovl.C
@@ -0,0 +1,153 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) {}
+    ~suspend_always_intprt() {}
+    bool await_ready() const noexcept { return false; }
+    void await_suspend(coro::coroutine_handle<>) const noexcept { puts ("susp-always-susp-int");}
+    int await_resume() const noexcept {puts ("susp-always-resume-int"); return x;}
+  };
+
+  struct promise_type {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+
+  struct empty {
+    auto operator co_await() const noexcept { 
+      return suspend_always_prt{};
+    }
+  };
+};
+
+
+/* The simplest valued co_await we can do.  */
+int gX = 1;
+coro1::empty e{};
+
+coro1
+f ()
+{
+  co_await (e); /* overload */
+  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]");
+  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-7-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
new file mode 100644
index 0000000..032e35f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-7-tmpl.C
@@ -0,0 +1,149 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 an int.  */
+  struct suspend_always_intprt {
+    T x;
+    suspend_always_intprt() : x(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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* 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-8-cascade.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
new file mode 100644
index 0000000..f3504d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-8-cascade.C
@@ -0,0 +1,157 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 * x;}
+  };
+
+  struct promise_type {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* Valued with an await_transform.  */
+int gX = 1;
+coro1 f ()
+{
+  /* the await transform takes an int, the await_resume squares it.
+     so we get 11 ** 4, 14641.  */
+  gX = co_await 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] - nested");
+  f_coro.handle.resume();
+  PRINT ("main: resuming [2] - 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-9-pair.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
new file mode 100644
index 0000000..8713adf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-9-pair.C
@@ -0,0 +1,155 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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
+
+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 {
+    int 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 an int.  */
+  struct suspend_always_intprt {
+    int x;
+    suspend_always_intprt() : x(5) { PRINT ("suspend_always_intprt def ctor"); }
+    suspend_always_intprt(int _x) : x(_x) { PRINTF ("suspend_always_intprt ctor with %d\n", 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 {
+  int 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 () %d\n",v);
+    value = v;
+  }
+
+  auto await_transform (int v) {
+    PRINTF ("await_transform an int () %d\n",v);
+    return suspend_always_intprt (v);
+  }
+
+  int get_value () { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+/* 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] one side of add");
+  f_coro.handle.resume();
+  PRINT ("main: resuming [1] 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-ret-3.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
new file mode 100644
index 0000000..f57c4e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-3.C
@@ -0,0 +1,112 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// GRO differs from the eventual return type.
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
new file mode 100644
index 0000000..d85199e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-4.C
@@ -0,0 +1,129 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// GRO differs from eventual return type and has non-trivial dtor.
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
new file mode 100644
index 0000000..0eb0055
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-5.C
@@ -0,0 +1,122 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
new file mode 100644
index 0000000..1aad1b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-6.C
@@ -0,0 +1,125 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning a T.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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-7.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
new file mode 100644
index 0000000..0af0922
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-7.C
@@ -0,0 +1,114 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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");}
+  };
+
+  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 {
+  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{};
+    //return std::experimental::suspend_always{};
+  }
+  auto final_suspend () {
+    PRINT ("get final_suspend (always)");
+    return suspend_always_prt{};
+  }
+  void return_void () {
+    PRINT ("return_void ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+__attribute__((__noinline__))
+int foo (void) { PRINT ("called the int fn foo");  return 2; }
+
+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();
+  PRINT ("main: after resume");
+  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-8.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
new file mode 100644
index 0000000..f79201c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-8.C
@@ -0,0 +1,126 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test templated co-return.
+
+/* 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__));
+
+#define BROKEN
+
+#ifndef OUTPUT
+#  define PRINT(X)
+#  define PRINTF (void)
+#else
+#  define PRINT(X) puts(X)
+#  define PRINTF printf
+#endif
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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-9.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
new file mode 100644
index 0000000..b2dd776
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-9.C
@@ -0,0 +1,118 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* boolean return from await_suspend ().  */
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+struct coro1
+f () noexcept
+{
+  PRINT ("coro1: about to return");
+  co_return;
+}
+
+int main ()
+{
+  //__builtin_coro_promise ((void*)0, 16, true);
+  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-void-is-ready.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
new file mode 100644
index 0000000..f5662d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-ready.C
@@ -0,0 +1,107 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+struct coro1
+f () noexcept
+{
+  PRINT ("coro1: about to return");
+  co_return;
+}
+
+int main ()
+{
+  //__builtin_coro_promise ((void*)0, 16, true);
+  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-void-is-suspend.C b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
new file mode 100644
index 0000000..bc2ab1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-ret-void-is-suspend.C
@@ -0,0 +1,111 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  //int x;
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
new file mode 100644
index 0000000..4d76a99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-0-triv.C
@@ -0,0 +1,146 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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-1-multi.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
new file mode 100644
index 0000000..341af61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-1-multi.C
@@ -0,0 +1,159 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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-2-loop.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
new file mode 100644
index 0000000..53851d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-2-loop.C
@@ -0,0 +1,153 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+int gX ;
+
+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;
+  
+  //co_return 0;
+}
+
+int main ()
+{
+  PRINT ("main: create coro1");
+  struct coro1 f_coro = f ();
+  PRINT ("main: got coro1 - resuming (1)");
+  if (f_coro.handle.done())
+    abort();
+  f_coro.handle.resume();
+  PRINT ("main: after resume (1)");
+  int y = f_coro.handle.promise().get_value();
+
+  PRINT ("main: gX OK -- looping");
+  do {
+    //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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
new file mode 100644
index 0000000..b1659e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-3-tmpl.C
@@ -0,0 +1,160 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test co_yield in templated code.
+
+/* 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
+
+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; }
+
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  
+  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-strings.C b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
new file mode 100644
index 0000000..9c953ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/co-yield-strings.C
@@ -0,0 +1,182 @@ 
+//  { dg-do run }
+
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+#include <vector>
+#include <string>
+
+namespace coro = std::experimental;
+
+/* 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
+
+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; }
+
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+  
+  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 ();
+      //x.handle.resume();
+    }
+
+  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/coro-torture.exp b/gcc/testsuite/g++.dg/coroutines/torture/coro-torture.exp
new file mode 100644
index 0000000..d2463b2
--- /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 0000000..9601564
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/exceptions-test-0.C
@@ -0,0 +1,189 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+#include <exception>
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {
+    PRINT ("unhandled_exception: caught one!");/*exit(1);*/
+    gX = -1;
+    // returning from here should end up in final_suspend.
+    //std::terminate ();
+    }
+  };
+};
+
+// 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-0.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
new file mode 100644
index 0000000..308f7ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-0.C
@@ -0,0 +1,126 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test promise construction from function args list.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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(int x) : value (x) {  PRINTF ("Created Promise with %d\n", x); }
+  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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 )
+    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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
new file mode 100644
index 0000000..4408ae1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-1.C
@@ -0,0 +1,130 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
new file mode 100644
index 0000000..2d97e76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-2.C
@@ -0,0 +1,134 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test that we correctly re-write multiple uses of a function param
+// in the body.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
new file mode 100644
index 0000000..1242b13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-3.C
@@ -0,0 +1,133 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test that we can use a function param in a co_xxxx status.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
new file mode 100644
index 0000000..729aae6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-4.C
@@ -0,0 +1,141 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test that we can manage a constructed param copy.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+// 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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
new file mode 100644
index 0000000..e0c3d2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/func-params-5.C
@@ -0,0 +1,141 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test that we can manage a constructed param copy.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+// 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 ();
+      //x.handle.resume();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
new file mode 100644
index 0000000..40a3620
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/gro_on_alloc_fail_0.C
@@ -0,0 +1,137 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// check the code-gen for the failed alloc return.
+
+#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
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  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 ();
+      //x.handle.resume();
+    }
+  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 0000000..f78787b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-0.C
@@ -0,0 +1,123 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  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 0000000..9dd7ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-1.C
@@ -0,0 +1,123 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 ();
+      //x.handle.resume();
+    }
+  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 0000000..886c913
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-2.C
@@ -0,0 +1,135 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test returning an int.
+// We will use the promise to contain this to avoid having to include
+// additional C++ headers.
+
+/* 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
+
+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;
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 0000000..53b7e71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-3.C
@@ -0,0 +1,153 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test modifying a local var and yielding several instances of it.
+
+/* 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
+
+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{};
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 0000000..5d4c0ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/local-var-4.C
@@ -0,0 +1,162 @@ 
+//  { dg-do run }
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// Test modifying a local var and yielding several instances of it.
+
+/* 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
+
+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{};
+  }
+  int get_value (void) { return value; }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 0000000..6e68688
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/mid-suspend-destruction-0.C
@@ -0,0 +1,127 @@ 
+// { 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.
+
+#if __clang__
+# include <experimental/coroutine>
+# include <utility>
+#else
+# include "../coro.h"
+#endif
+
+namespace coro = std::experimental;
+
+// GRO differs from the eventual return type.
+
+/* 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)
+#else
+#  define PRINT(X) puts(X)
+#endif
+
+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 ()");
+  }
+  // Placeholder to satisfy parser, not doing exceptions yet.
+  void unhandled_exception() {  /*exit(1);*/ }
+  };
+};
+
+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 (! x.handle.suspended_p())
+    {
+      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;
+}