diff mbox series

[C++,coroutines,5/7,v2] Standard library header.

Message ID BB4CFE6D-1A01-4747-AEFD-A319ECE2A6A7@sandoe.co.uk
State New
Headers show
Series [C++,coroutines,1/7] Common code and base definitions. | expand

Commit Message

Iain Sandoe Jan. 9, 2020, 12:39 p.m. UTC
Hi Jonathan

The SVN commit IDs that relate to the amendments are noted in the
revised patch header below.

Jonathan Wakely <jwakely@redhat.com> wrote:

> On 17/11/19 10:27 +0000, Iain Sandoe wrote:

>> 	* include/Makefile.in: Regnerated.
> 
> "Regnerated" typo.
Fixed,

>> 	${experimental_srcdir}/chrono \
>> +	${experimental_srcdir}/coroutine \
> 
> The experimental dir is (currently) only used for TS headers. All
> C++20 support is currently experimental, so adding <coroutines> where
> <concepts> and <ranges> have been added would be OK.
> 
> But I'm not really clear if this is an implementation of the TS or the
> C++20 feature.  If it's a hybrid, putting it in
> <experimental/coroutines> is fine.

Mea culpa;
this began life as a TS and when it was included in the WD (and then CD)
I failed to move the header and update.

My intention is that the facility will work with at least C++14 as a GNU
extension (as do the impls. in clang and EDG).  In fact, I can’t see any
real reason that it wouldn’t work with C++11 - but time is too short for
that experiment.

> When the final <coroutines> header is added it will need to be in
> libsupc++ so that it's included for freestanding builds (and at that
> point it won't be able to use <bits/stl_function.h>, but that will be
> OK as the final header will be C++20-only and can rely on <compare>
> unconditionally, which is also freestanding).

Well, for the reason above, I have made this not depend on the availability
of <compare> or spaceship.

>> +/** @file experimental/coroutine
>> + *  This is an experimental C++ Library header against the C++20 CD n4835.
>> + *  @ingroup coroutine-ts
> 
> The coroutine-ts doc group should be defined somewhere.

I’ve reworked the doxygen stuff somewhat, although freely admit that it’s currently
rather weak as documentation.  I do expect some more editorial changes to the std
and documentation could be improved before 10 releases.

>> +  namespace experimental {
>> +  inline namespace coroutines_n4835 {
> 
> This should be a reserved name too, e.g. __coroutines_n4835.
done
>> 
>> +    constexpr coroutine_handle () noexcept : __fr_ptr (0) {}
> 
> The libstdc++ naming convention is _M_xxx for non-static members (both
> data members and member functions) and _S_xxx for static members
> (again, both data member and functions).
> 
> This helps to distinguish members from other uglified names like
> function parameters and local variables.
done.

Hopefully, this amended version is closer and the intent is clearer.
OK for trunk now?
thanks
Iain

———

This provides the interfaces mandated by the standard and implements
the interaction with the coroutine frame by means of inline use of
builtins expanded at compile-time.  There should be a 1:1 correspondence
with the standard sections which are cross-referenced.

There is no runtime content.

At this stage we have the content in an inline namespace "__n4835" for
the current CD.

Squashed commits:

r278724 - Address review comments, GNU naming conventions
r278778 - Address review comments, update doxygen group info.
r279817 - Update copyright year.
r279845 - Address review comments, move coroutine header to std.
r280038 - Correct pathname in the edit header.

libstdc++-v3/ChangeLog:

2020-01-09  Iain Sandoe  <iain@sandoe.co.uk>

	* include/Makefile.am: Add coroutine to the std set.
	* include/Makefile.in: Regenerated.
	* include/std/coroutine: New file.
---
 libstdc++-v3/include/Makefile.am   |   1 +
 libstdc++-v3/include/Makefile.in   |   1 +
 libstdc++-v3/include/std/coroutine | 269 +++++++++++++++++++++++++++++++++++++
 3 files changed, 271 insertions(+)
 create mode 100644 libstdc++-v3/include/std/coroutine

Comments

Jonathan Wakely Jan. 9, 2020, 1:33 p.m. UTC | #1
On 09/01/20 12:39 +0000, Iain Sandoe wrote:
>Hi Jonathan
>
>The SVN commit IDs that relate to the amendments are noted in the
>revised patch header below.
>
>Jonathan Wakely <jwakely@redhat.com> wrote:
>
>> On 17/11/19 10:27 +0000, Iain Sandoe wrote:
>
>>> 	* include/Makefile.in: Regnerated.
>>
>> "Regnerated" typo.
>Fixed,
>
>>> 	${experimental_srcdir}/chrono \
>>> +	${experimental_srcdir}/coroutine \
>>
>> The experimental dir is (currently) only used for TS headers. All
>> C++20 support is currently experimental, so adding <coroutines> where
>> <concepts> and <ranges> have been added would be OK.
>>
>> But I'm not really clear if this is an implementation of the TS or the
>> C++20 feature.  If it's a hybrid, putting it in
>> <experimental/coroutines> is fine.
>
>Mea culpa;
>this began life as a TS and when it was included in the WD (and then CD)
>I failed to move the header and update.
>
>My intention is that the facility will work with at least C++14 as a GNU
>extension (as do the impls. in clang and EDG).  In fact, I can’t see any
>real reason that it wouldn’t work with C++11 - but time is too short for
>that experiment.

Life's too short to support C++11. GCC's default is C++14, so anybody
explicitly requesting C++11 should expect not to get shiny new toys.

It uses names that aren't reserved in C++14 and C++17, but as it's a
new header anybody explicitly including it in C++14 gets what they
deserve^W asked for. Another option would be to use:

#if __cplusplus > 201703L || (__cplusplus >= 201402L && !defined __STRICT_ANSI__)

I don't think we need to do that. We can revisit if people complain,
but I doubt they will.

>> When the final <coroutines> header is added it will need to be in
>> libsupc++ so that it's included for freestanding builds (and at that
>> point it won't be able to use <bits/stl_function.h>, but that will be
>> OK as the final header will be C++20-only and can rely on <compare>
>> unconditionally, which is also freestanding).
>
>Well, for the reason above, I have made this not depend on the availability
>of <compare> or spaceship.

Makes sense.

>>> +/** @file experimental/coroutine
>>> + *  This is an experimental C++ Library header against the C++20 CD n4835.
>>> + *  @ingroup coroutine-ts
>>
>> The coroutine-ts doc group should be defined somewhere.
>
>I’ve reworked the doxygen stuff somewhat, although freely admit that it’s currently
>rather weak as documentation.  I do expect some more editorial changes to the std
>and documentation could be improved before 10 releases.

That's fine. Our doxygen API docs need a lot of improvement anyway.

>>> +  namespace experimental {
>>> +  inline namespace coroutines_n4835 {
>>
>> This should be a reserved name too, e.g. __coroutines_n4835.
>done
>>>
>>> +    constexpr coroutine_handle () noexcept : __fr_ptr (0) {}
>>
>> The libstdc++ naming convention is _M_xxx for non-static members (both
>> data members and member functions) and _S_xxx for static members
>> (again, both data member and functions).
>>
>> This helps to distinguish members from other uglified names like
>> function parameters and local variables.
>done.
>
>Hopefully, this amended version is closer and the intent is clearer.
>OK for trunk now?
>thanks
>Iain
>
>———
>
>This provides the interfaces mandated by the standard and implements
>the interaction with the coroutine frame by means of inline use of
>builtins expanded at compile-time.  There should be a 1:1 correspondence
>with the standard sections which are cross-referenced.
>
>There is no runtime content.
>
>At this stage we have the content in an inline namespace "__n4835" for
>the current CD.
>
>Squashed commits:
>
>r278724 - Address review comments, GNU naming conventions
>r278778 - Address review comments, update doxygen group info.
>r279817 - Update copyright year.
>r279845 - Address review comments, move coroutine header to std.
>r280038 - Correct pathname in the edit header.
>
>libstdc++-v3/ChangeLog:
>
>2020-01-09  Iain Sandoe  <iain@sandoe.co.uk>
>
>	* include/Makefile.am: Add coroutine to the std set.
>	* include/Makefile.in: Regenerated.
>	* include/std/coroutine: New file.
>---
> libstdc++-v3/include/Makefile.am   |   1 +
> libstdc++-v3/include/Makefile.in   |   1 +
> libstdc++-v3/include/std/coroutine | 269 +++++++++++++++++++++++++++++++++++++
> 3 files changed, 271 insertions(+)
> create mode 100644 libstdc++-v3/include/std/coroutine
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index b38defcafb..ad4404793b 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -38,6 +38,7 @@ std_headers = \
> 	${std_srcdir}/complex \
> 	${std_srcdir}/concepts \
> 	${std_srcdir}/condition_variable \
>+	${std_srcdir}/coroutine \
> 	${std_srcdir}/deque \
> 	${std_srcdir}/execution \
> 	${std_srcdir}/filesystem \
>diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>index ae4a493ea6..f8b5645224 100644
>--- a/libstdc++-v3/include/Makefile.in
>+++ b/libstdc++-v3/include/Makefile.in
>@@ -382,6 +382,7 @@ std_headers = \
> 	${std_srcdir}/complex \
> 	${std_srcdir}/concepts \
> 	${std_srcdir}/condition_variable \
>+	${std_srcdir}/coroutine \
> 	${std_srcdir}/deque \
> 	${std_srcdir}/execution \
> 	${std_srcdir}/filesystem \
>diff --git a/libstdc++-v3/include/std/coroutine b/libstdc++-v3/include/std/coroutine
>new file mode 100644
>index 0000000000..9eaffaba12
>--- /dev/null
>+++ b/libstdc++-v3/include/std/coroutine
>@@ -0,0 +1,269 @@
>+// <coroutine> -*- C++ -*-
>+
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
>+// any later version.
>+
>+// This library 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/coroutine
>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_EXPERIMENTAL_COROUTINE
>+#define _GLIBCXX_EXPERIMENTAL_COROUTINE 1

Did you mean to leave EXPERIMENTAL in this macro?
(If you change it, don't forget the one on the last line of the file).

>+
>+#pragma GCC system_header
>+
>+// It is very likely that earlier versions would work, but they are untested.
>+#if __cplusplus >= 201402L
>+
>+#include <bits/c++config.h>
>+
>+/**
>+ * @defgroup coroutines Coroutines
>+ *
>+ * Components for supporting coroutine implementations.
>+ */
>+
>+#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
>+#  include <compare>
>+#  define _COROUTINES_USE_SPACESHIP 1
>+#else
>+#  include <bits/stl_function.h>
>+#  define _COROUTINES_USE_SPACESHIP 0
>+#endif
>+
>+namespace std _GLIBCXX_VISIBILITY (default)
>+{
>+  _GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#if __cpp_coroutines
>+  inline namespace __n4835 {
>+
>+  // 17.12.2 coroutine traits
>+  /// [coroutine.traits]
>+  /// [coroutine.traits.primary]
>+  template <typename _R, typename...> struct coroutine_traits

_R isn't in our list of identifiers to avoid, but it's uncomfortably
close to some of them. We generally try to avoid single-letter names.
Please use something like _Ret or _Res instead.

>+  {
>+    using promise_type = typename _R::promise_type;
>+  };
>+
>+  // 17.12.3 Class template coroutine_handle
>+  /// [coroutine.handle]
>+  template <typename _Promise = void> struct coroutine_handle;
>+
>+  template <> struct coroutine_handle<void>
>+  {
>+  public:
>+    // 17.12.3.1, construct/reset
>+    constexpr coroutine_handle () noexcept : _M_fr_ptr (0) {}
>+    constexpr coroutine_handle (decltype (nullptr) __h) noexcept

std::nullptr_t is defined in <bits/c++config.h> so you could use that
here.

>+      : _M_fr_ptr (__h)
>+    {}

New line after this function body please.

>+    coroutine_handle &operator= (decltype (nullptr)) noexcept

Libstdc++ coding standards differ from the rest of GCC. We group the
ptr-declarator with the type, not the name, and there's no space
before the parens, so:

     coroutine_handle& operator=(nullptr_t) noexcept

>+    {
>+      _M_fr_ptr = nullptr;
>+      return *this;
>+    }
>+
>+  public:
>+    // 17.12.3.2, export/import
>+    constexpr void *address () const noexcept { return _M_fr_ptr; }
>+    constexpr static coroutine_handle from_address (void *__a) noexcept
>+    {
>+      coroutine_handle __self;
>+      __self._M_fr_ptr = __a;
>+      return __self;
>+    }
>+
>+  public:
>+    // 17.12.3.3, observers
>+    constexpr explicit operator bool () const noexcept
>+    {
>+      return bool(_M_fr_ptr);
>+    }
>+    bool done () const noexcept { return __builtin_coro_done (_M_fr_ptr); }
>+    // 17.12.3.4, resumption
>+    void operator() () const { resume (); }
>+    void resume () const { __builtin_coro_resume (_M_fr_ptr); }
>+    void destroy () const { __builtin_coro_destroy (_M_fr_ptr); }
>+
>+  protected:
>+    void *_M_fr_ptr;
>+  };
>+
>+  // 17.12.3.6 Comparison operators
>+  /// [coroutine.handle.compare]
>+  constexpr bool operator== (coroutine_handle<> __a,
>+			     coroutine_handle<> __b) noexcept
>+  {
>+    return __a.address () == __b.address ();
>+  }
>+
>+#if _COROUTINES_USE_SPACESHIP
>+  constexpr strong_ordering
>+  operator<=> (coroutine_handle<> __a, coroutine_handle<> __b) noexcept;
>+#else
>+  // These are from the TS to enable operation with std=c++14,17.
>+  constexpr bool operator!= (coroutine_handle<> __a,
>+			     coroutine_handle<> __b) noexcept
>+  {
>+    return !(__a == __b);
>+  }
>+
>+  constexpr bool operator< (coroutine_handle<> __a,
>+			    coroutine_handle<> __b) noexcept
>+  {
>+    return less<void *> () (__a.address (), __b.address ());
>+  }
>+
>+  constexpr bool operator> (coroutine_handle<> __a,
>+			    coroutine_handle<> __b) noexcept
>+  {
>+    return __b < __a;
>+  }
>+
>+  constexpr bool operator<= (coroutine_handle<> __a,
>+			     coroutine_handle<> __b) noexcept
>+  {
>+    return !(__a > __b);
>+  }
>+
>+  constexpr bool operator>= (coroutine_handle<> __a,
>+			     coroutine_handle<> __b) noexcept
>+  {
>+    return !(__a < __b);
>+  }
>+#endif
>+
>+  template <class _Promise> struct coroutine_handle : coroutine_handle<>

s/class/typename/ in the template-head please.

>+  {
>+    // 17.12.3.1, construct/reset
>+    using coroutine_handle<>::coroutine_handle;
>+    static coroutine_handle from_promise (_Promise &p)
>+    {
>+      coroutine_handle __self;
>+      __self._M_fr_ptr
>+	= __builtin_coro_promise ((char *) &p, __alignof(_Promise), true);
>+      return __self;
>+    }
>+    coroutine_handle &operator= (decltype (nullptr)) noexcept
>+    {
>+      coroutine_handle<>::operator= (nullptr);
>+      return *this;
>+    }
>+    // 17.12.3.2, export/import
>+    constexpr static coroutine_handle from_address (void *__a)
>+    {
>+      coroutine_handle __self;
>+      __self._M_fr_ptr = __a;
>+      return __self;
>+    }
>+    // 17.12.3.5, promise accesss
>+    _Promise &promise () const
>+    {
>+      void *__t
>+	= __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false);
>+      return *static_cast<_Promise *> (__t);
>+    }
>+  };
>+
>+  /// [coroutine.noop]
>+  struct noop_coroutine_promise
>+  {
>+  };
>+
>+  void __dummy_resume_destroy () __attribute__ ((__weak__));
>+  void __dummy_resume_destroy () {}
>+
>+  struct __noop_coro_frame
>+  {
>+    void (*__r) () = __dummy_resume_destroy;
>+    void (*__d) () = __dummy_resume_destroy;
>+    struct noop_coroutine_promise __p;
>+  } __noop_coro_fr __attribute__ ((__weak__));
>+
>+  // 17.12.4.1 Class noop_coroutine_promise
>+  /// [coroutine.promise.noop]
>+  template <>
>+  class coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>

The primary template was declared as a struct but this is a class. It
doesn't really matter, but let's keep it consistent to avoid annoying
-Wmismatched-tags warnings from Clang.

>+  {
>+    using _Promise = noop_coroutine_promise;
>+
>+  public:
>+    // 17.12.4.2.1, observers
>+    constexpr explicit operator bool () const noexcept { return true; }
>+    constexpr bool done () const noexcept { return false; }
>+
>+    // 17.12.4.2.2, resumption
>+    void operator() () const noexcept {}
>+    void resume () const noexcept {}
>+    void destroy () const noexcept {}
>+
>+    // 17.12.4.2.3, promise access
>+    _Promise &promise () const
>+    {
>+      return *static_cast<_Promise *> (
>+	__builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false));
>+    }
>+
>+    // 17.12.4.2.4, address
>+    // constexpr void* address() const noexcept;
>+  private:
>+    friend coroutine_handle<noop_coroutine_promise> noop_coroutine () noexcept;
>+
>+    coroutine_handle () noexcept { this->_M_fr_ptr = (void *) &__noop_coro_fr; }
>+  };
>+
>+  using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
>+
>+  inline noop_coroutine_handle noop_coroutine () noexcept
>+  {
>+    return noop_coroutine_handle ();
>+  }
>+
>+  // 17.12.5 Trivial awaitables
>+  /// [coroutine.trivial.awaitables]
>+  struct suspend_always
>+  {
>+    bool await_ready () { return false; }
>+    void await_suspend (coroutine_handle<>) {}
>+    void await_resume () {}
>+  };
>+
>+  struct suspend_never
>+  {
>+    bool await_ready () { return true; }
>+    void await_suspend (coroutine_handle<>) {}
>+    void await_resume () {}
>+  };
>+
>+  } // namespace __n4835
>+
>+#else
>+#error "the coroutine header requires -fcoroutines"
>+#endif
>+
>+  _GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std_GLIBCXX_VISIBILITY(default)

No need for the _GLIBCXX... part here.

>+
>+#endif // C++14 (we are allowing use from at least this)
>+
>+#endif // _GLIBCXX_EXPERIMENTAL_COROUTINE
>-- 
>2.14.3
>
>
Iain Sandoe Jan. 9, 2020, 7:43 p.m. UTC | #2
Hi Jonathan,

thanks for the review - hopefully the attached addresses both those
and the whitespace differences we discussed off-line.

I’m attaching the header as a textfile since it’s a new one, perhaps
that will make it easier to review the whitespace stuff.

thanks
Iain

Jonathan Wakely <jwakely@redhat.com> wrote:

> On 09/01/20 12:39 +0000, Iain Sandoe wrote:

>> +#ifndef _GLIBCXX_EXPERIMENTAL_COROUTINE
>> +#define _GLIBCXX_EXPERIMENTAL_COROUTINE 1
> 
> Did you mean to leave EXPERIMENTAL in this macro?
no, dropped.
>> 
>> +  template <typename _R, typename...> struct coroutine_traits
> 
> _R isn't in our list of identifiers to avoid, but it's uncomfortably
> close to some of them. We generally try to avoid single-letter names.
> Please use something like _Ret or _Res instead.

used “_Result".

>> \+    constexpr coroutine_handle (decltype (nullptr) __h) noexcept
> 
> std::nullptr_t is defined in <bits/c++config.h> so you could use that
> here.
done.

>> +    {}
> 
> New line after this function body please.

I’ve been through an added a newline after each body.

>> +    coroutine_handle &operator= (decltype (nullptr)) noexcept
> 
> Libstdc++ coding standards differ from the rest of GCC. We group the
> ptr-declarator with the type, not the name, and there's no space
> before the parens, so:
> 
>    coroutine_handle& operator=(nullptr_t) noexcept

Whitespace fixes applied throughout.

>> +} // namespace std_GLIBCXX_VISIBILITY(default)
> 
> No need for the _GLIBCXX... part here.

indeed, that was a typo.
// <coroutine> -*- C++ -*-

// Copyright (C) 2019-2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
// any later version.

// This library 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.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file include/coroutine
 *  This is a Standard C++ Library header.
 */

#ifndef _GLIBCXX_COROUTINE
#define _GLIBCXX_COROUTINE 1

#pragma GCC system_header

// It is very likely that earlier versions would work, but they are untested.
#if __cplusplus >= 201402L

#include <bits/c++config.h>

/**
 * @defgroup coroutines Coroutines
 *
 * Components for supporting coroutine implementations.
 */

#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
#  include <compare>
#  define _COROUTINES_USE_SPACESHIP 1
#else
#  include <bits/stl_function.h> // for std::less
#  define _COROUTINES_USE_SPACESHIP 0
#endif

namespace std _GLIBCXX_VISIBILITY (default)
{
  _GLIBCXX_BEGIN_NAMESPACE_VERSION

#if __cpp_coroutines
  inline namespace __n4835 {

  // 17.12.2 coroutine traits
  /// [coroutine.traits]
  /// [coroutine.traits.primary]
  template <typename _Result, typename...>
    struct coroutine_traits
    {
       using promise_type = typename _Result::promise_type;
    };

  // 17.12.3 Class template coroutine_handle
  /// [coroutine.handle]
  template <typename _Promise = void>
    struct coroutine_handle;

  template <> struct
    coroutine_handle<void>
    {
    public:
      // 17.12.3.1, construct/reset
      constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {}

      constexpr coroutine_handle(std::nullptr_t __h) noexcept
	: _M_fr_ptr(__h)
      {}

      coroutine_handle& operator=(std::nullptr_t) noexcept
      {
	_M_fr_ptr = nullptr;
	return *this;
      }

    public:
      // 17.12.3.2, export/import
      constexpr void* address() const noexcept { return _M_fr_ptr; }

      constexpr static coroutine_handle from_address(void* __a) noexcept
      {
	coroutine_handle __self;
	__self._M_fr_ptr = __a;
	return __self;
      }

    public:
      // 17.12.3.3, observers
      constexpr explicit operator bool() const noexcept
      {
	return bool(_M_fr_ptr);
      }

      bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); }

      // 17.12.3.4, resumption
      void operator()() const { resume(); }

      void resume() const { __builtin_coro_resume(_M_fr_ptr); }

      void destroy() const { __builtin_coro_destroy(_M_fr_ptr); }

    protected:
      void* _M_fr_ptr;
  };

  // 17.12.3.6 Comparison operators
  /// [coroutine.handle.compare]
  constexpr bool operator==(coroutine_handle<> __a,
			    coroutine_handle<> __b) noexcept
  {
    return __a.address() == __b.address();
  }

#if _COROUTINES_USE_SPACESHIP
  constexpr strong_ordering
  operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept;
#else
  // These are to enable operation with std=c++14,17.
  constexpr bool operator!=(coroutine_handle<> __a,
			    coroutine_handle<> __b) noexcept
  {
    return !(__a == __b);
  }

  constexpr bool operator<(coroutine_handle<> __a,
			   coroutine_handle<> __b) noexcept
  {
    return less<void*>()(__a.address(), __b.address());
  }

  constexpr bool operator>(coroutine_handle<> __a,
			   coroutine_handle<> __b) noexcept
  {
    return __b < __a;
  }

  constexpr bool operator<=(coroutine_handle<> __a,
			    coroutine_handle<> __b) noexcept
  {
    return !(__a > __b);
  }

  constexpr bool operator>=(coroutine_handle<> __a,
			    coroutine_handle<> __b) noexcept
  {
    return !(__a < __b);
  }
#endif

  template <typename _Promise>
    struct coroutine_handle : coroutine_handle<>
    {
      // 17.12.3.1, construct/reset
      using coroutine_handle<>::coroutine_handle;

      static coroutine_handle from_promise(_Promise& p)
      {
	coroutine_handle __self;
	__self._M_fr_ptr
	  = __builtin_coro_promise((char*) &p, __alignof(_Promise), true);
	return __self;
      }

      coroutine_handle& operator=(std::nullptr_t) noexcept
      {
	coroutine_handle<>::operator=(nullptr);
	return *this;
      }

    // 17.12.3.2, export/import
    constexpr static coroutine_handle from_address(void* __a)
    {
      coroutine_handle __self;
      __self._M_fr_ptr = __a;
      return __self;
    }

    // 17.12.3.5, promise accesss
    _Promise& promise() const
    {
      void* __t
	= __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false);
      return *static_cast<_Promise*>(__t);
    }
  };

  /// [coroutine.noop]
  struct noop_coroutine_promise
  {
  };

  void __dummy_resume_destroy() __attribute__((__weak__));
  void __dummy_resume_destroy() {}

  struct __noop_coro_frame
  {
    void (*__r)() = __dummy_resume_destroy;
    void (*__d)() = __dummy_resume_destroy;
    struct noop_coroutine_promise __p;
  } __noop_coro_fr __attribute__((__weak__));

  // 17.12.4.1 Class noop_coroutine_promise
  /// [coroutine.promise.noop]
  template <>
    struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>
    {
      using _Promise = noop_coroutine_promise;

    public:
      // 17.12.4.2.1, observers
      constexpr explicit operator bool() const noexcept { return true; }

      constexpr bool done() const noexcept { return false; }

      // 17.12.4.2.2, resumption
      void operator()() const noexcept {}

      void resume() const noexcept {}

      void destroy() const noexcept {}

      // 17.12.4.2.3, promise access
      _Promise& promise() const
      {
	return *static_cast<_Promise*>(
	  __builtin_coro_promise(this->_M_fr_ptr, __alignof(_Promise), false));
      }

      // 17.12.4.2.4, address
    private:
      friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;

      coroutine_handle() noexcept { this->_M_fr_ptr = (void*) &__noop_coro_fr; }
    };

  using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;

  inline noop_coroutine_handle noop_coroutine() noexcept
  {
    return noop_coroutine_handle();
  }

  // 17.12.5 Trivial awaitables
  /// [coroutine.trivial.awaitables]
  struct suspend_always
  {
    bool await_ready() { return false; }

    void await_suspend(coroutine_handle<>) {}

    void await_resume() {}
  };

  struct suspend_never
  {
    bool await_ready() { return true; }

    void await_suspend(coroutine_handle<>) {}

    void await_resume() {}
  };

  } // namespace __n4835

#else
#error "the coroutine header requires -fcoroutines"
#endif

  _GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // C++14 (we are allowing use from at least this)

#endif // _GLIBCXX_COROUTINE
====
    
    This provides the interfaces mandated by the standard and implements
    the interaction with the coroutine frame by means of inline use of
    builtins expanded at compile-time.  There should be a 1:1 correspondence
    with the standard sections which are cross-referenced.
    
    There is no runtime content.
    
    At this stage we have the content in an inline namespace "__n4835" for
    the current CD.
    
    Squashed commits:
    
    r278724 - Address review comments, GNU naming conventions
    r278778 - Address review comments, update doxygen group info.
    r279817 - Update copyright year.
    r279845 - Address review comments, move coroutine header to std.
    r280038 - Correct pathname in the edit header.
    
    libstdc++-v3/ChangeLog:
    
    2020-01-09  Iain Sandoe  <iain@sandoe.co.uk>
    
            * include/Makefile.am: Add coroutine to the std set.
            * include/Makefile.in: Regenerated.
            * include/std/coroutine: New file.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index b38defcafb..ad4404793b 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -38,6 +38,7 @@ std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
 	${std_srcdir}/filesystem \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea6..f8b5645224 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -382,6 +382,7 @@ std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
 	${std_srcdir}/filesystem \
diff --git a/libstdc++-v3/include/std/coroutine b/libstdc++-v3/include/std/coroutine
new file mode 100644
index 0000000000..3c3c7d7f50
--- /dev/null
+++ b/libstdc++-v3/include/std/coroutine
@@ -0,0 +1,290 @@
+// <coroutine> -*- C++ -*-
+
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/coroutine
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_COROUTINE
+#define _GLIBCXX_COROUTINE 1
+
+#pragma GCC system_header
+
+// It is very likely that earlier versions would work, but they are untested.
+#if __cplusplus >= 201402L
+
+#include <bits/c++config.h>
+
+/**
+ * @defgroup coroutines Coroutines
+ *
+ * Components for supporting coroutine implementations.
+ */
+
+#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
+#  include <compare>
+#  define _COROUTINES_USE_SPACESHIP 1
+#else
+#  include <bits/stl_function.h> // for std::less
+#  define _COROUTINES_USE_SPACESHIP 0
+#endif
+
+namespace std _GLIBCXX_VISIBILITY (default)
+{
+  _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#if __cpp_coroutines
+  inline namespace __n4835 {
+
+  // 17.12.2 coroutine traits
+  /// [coroutine.traits]
+  /// [coroutine.traits.primary]
+  template <typename _Result, typename...>
+    struct coroutine_traits
+    {
+       using promise_type = typename _Result::promise_type;
+    };
+
+  // 17.12.3 Class template coroutine_handle
+  /// [coroutine.handle]
+  template <typename _Promise = void>
+    struct coroutine_handle;
+
+  template <> struct
+    coroutine_handle<void>
+    {
+    public:
+      // 17.12.3.1, construct/reset
+      constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {}
+
+      constexpr coroutine_handle(std::nullptr_t __h) noexcept
+	: _M_fr_ptr(__h)
+      {}
+
+      coroutine_handle& operator=(std::nullptr_t) noexcept
+      {
+	_M_fr_ptr = nullptr;
+	return *this;
+      }
+
+    public:
+      // 17.12.3.2, export/import
+      constexpr void* address() const noexcept { return _M_fr_ptr; }
+
+      constexpr static coroutine_handle from_address(void* __a) noexcept
+      {
+	coroutine_handle __self;
+	__self._M_fr_ptr = __a;
+	return __self;
+      }
+
+    public:
+      // 17.12.3.3, observers
+      constexpr explicit operator bool() const noexcept
+      {
+	return bool(_M_fr_ptr);
+      }
+
+      bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); }
+
+      // 17.12.3.4, resumption
+      void operator()() const { resume(); }
+
+      void resume() const { __builtin_coro_resume(_M_fr_ptr); }
+
+      void destroy() const { __builtin_coro_destroy(_M_fr_ptr); }
+
+    protected:
+      void* _M_fr_ptr;
+  };
+
+  // 17.12.3.6 Comparison operators
+  /// [coroutine.handle.compare]
+  constexpr bool operator==(coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return __a.address() == __b.address();
+  }
+
+#if _COROUTINES_USE_SPACESHIP
+  constexpr strong_ordering
+  operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept;
+#else
+  // These are to enable operation with std=c++14,17.
+  constexpr bool operator!=(coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return !(__a == __b);
+  }
+
+  constexpr bool operator<(coroutine_handle<> __a,
+			   coroutine_handle<> __b) noexcept
+  {
+    return less<void*>()(__a.address(), __b.address());
+  }
+
+  constexpr bool operator>(coroutine_handle<> __a,
+			   coroutine_handle<> __b) noexcept
+  {
+    return __b < __a;
+  }
+
+  constexpr bool operator<=(coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return !(__a > __b);
+  }
+
+  constexpr bool operator>=(coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return !(__a < __b);
+  }
+#endif
+
+  template <typename _Promise>
+    struct coroutine_handle : coroutine_handle<>
+    {
+      // 17.12.3.1, construct/reset
+      using coroutine_handle<>::coroutine_handle;
+
+      static coroutine_handle from_promise(_Promise& p)
+      {
+	coroutine_handle __self;
+	__self._M_fr_ptr
+	  = __builtin_coro_promise((char*) &p, __alignof(_Promise), true);
+	return __self;
+      }
+
+      coroutine_handle& operator=(std::nullptr_t) noexcept
+      {
+	coroutine_handle<>::operator=(nullptr);
+	return *this;
+      }
+
+    // 17.12.3.2, export/import
+    constexpr static coroutine_handle from_address(void* __a)
+    {
+      coroutine_handle __self;
+      __self._M_fr_ptr = __a;
+      return __self;
+    }
+
+    // 17.12.3.5, promise accesss
+    _Promise& promise() const
+    {
+      void* __t
+	= __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false);
+      return *static_cast<_Promise*>(__t);
+    }
+  };
+
+  /// [coroutine.noop]
+  struct noop_coroutine_promise
+  {
+  };
+
+  void __dummy_resume_destroy() __attribute__((__weak__));
+  void __dummy_resume_destroy() {}
+
+  struct __noop_coro_frame
+  {
+    void (*__r)() = __dummy_resume_destroy;
+    void (*__d)() = __dummy_resume_destroy;
+    struct noop_coroutine_promise __p;
+  } __noop_coro_fr __attribute__((__weak__));
+
+  // 17.12.4.1 Class noop_coroutine_promise
+  /// [coroutine.promise.noop]
+  template <>
+    struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>
+    {
+      using _Promise = noop_coroutine_promise;
+
+    public:
+      // 17.12.4.2.1, observers
+      constexpr explicit operator bool() const noexcept { return true; }
+
+      constexpr bool done() const noexcept { return false; }
+
+      // 17.12.4.2.2, resumption
+      void operator()() const noexcept {}
+
+      void resume() const noexcept {}
+
+      void destroy() const noexcept {}
+
+      // 17.12.4.2.3, promise access
+      _Promise& promise() const
+      {
+	return *static_cast<_Promise*>(
+	  __builtin_coro_promise(this->_M_fr_ptr, __alignof(_Promise), false));
+      }
+
+      // 17.12.4.2.4, address
+    private:
+      friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
+
+      coroutine_handle() noexcept { this->_M_fr_ptr = (void*) &__noop_coro_fr; }
+    };
+
+  using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
+
+  inline noop_coroutine_handle noop_coroutine() noexcept
+  {
+    return noop_coroutine_handle();
+  }
+
+  // 17.12.5 Trivial awaitables
+  /// [coroutine.trivial.awaitables]
+  struct suspend_always
+  {
+    bool await_ready() { return false; }
+
+    void await_suspend(coroutine_handle<>) {}
+
+    void await_resume() {}
+  };
+
+  struct suspend_never
+  {
+    bool await_ready() { return true; }
+
+    void await_suspend(coroutine_handle<>) {}
+
+    void await_resume() {}
+  };
+
+  } // namespace __n4835
+
+#else
+#error "the coroutine header requires -fcoroutines"
+#endif
+
+  _GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++14 (we are allowing use from at least this)
+
+#endif // _GLIBCXX_COROUTINE
Jonathan Wakely Jan. 9, 2020, 8:20 p.m. UTC | #3
On 09/01/20 19:43 +0000, Iain Sandoe wrote:
>Hi Jonathan,
>
>thanks for the review - hopefully the attached addresses both those
>and the whitespace differences we discussed off-line.
>
>I’m attaching the header as a textfile since it’s a new one, perhaps
>that will make it easier to review the whitespace stuff.
>
>thanks
>Iain
>
>Jonathan Wakely <jwakely@redhat.com> wrote:
>
>> On 09/01/20 12:39 +0000, Iain Sandoe wrote:
>
>>> +#ifndef _GLIBCXX_EXPERIMENTAL_COROUTINE
>>> +#define _GLIBCXX_EXPERIMENTAL_COROUTINE 1
>>
>> Did you mean to leave EXPERIMENTAL in this macro?
>no, dropped.
>>>
>>> +  template <typename _R, typename...> struct coroutine_traits
>>
>> _R isn't in our list of identifiers to avoid, but it's uncomfortably
>> close to some of them. We generally try to avoid single-letter names.
>> Please use something like _Ret or _Res instead.
>
>used “_Result".
>
>>> \+    constexpr coroutine_handle (decltype (nullptr) __h) noexcept
>>
>> std::nullptr_t is defined in <bits/c++config.h> so you could use that
>> here.
>done.
>
>>> +    {}
>>
>> New line after this function body please.
>
>I’ve been through an added a newline after each body.
>
>>> +    coroutine_handle &operator= (decltype (nullptr)) noexcept
>>
>> Libstdc++ coding standards differ from the rest of GCC. We group the
>> ptr-declarator with the type, not the name, and there's no space
>> before the parens, so:
>>
>>    coroutine_handle& operator=(nullptr_t) noexcept
>
>Whitespace fixes applied throughout.
>
>>> +} // namespace std_GLIBCXX_VISIBILITY(default)
>>
>> No need for the _GLIBCXX... part here.
>
>indeed, that was a typo.
>

>// <coroutine> -*- C++ -*-
>
>// Copyright (C) 2019-2020 Free Software Foundation, Inc.
>//
>// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
>// any later version.
>
>// This library 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.
>
>// Under Section 7 of GPL version 3, you are granted additional
>// permissions described in the GCC Runtime Library Exception, version
>// 3.1, as published by the Free Software Foundation.
>
>// You should have received a copy of the GNU General Public License and
>// a copy of the GCC Runtime Library Exception along with this program;
>// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>// <http://www.gnu.org/licenses/>.
>
>/** @file include/coroutine
> *  This is a Standard C++ Library header.
> */
>
>#ifndef _GLIBCXX_COROUTINE
>#define _GLIBCXX_COROUTINE 1
>
>#pragma GCC system_header
>
>// It is very likely that earlier versions would work, but they are untested.
>#if __cplusplus >= 201402L
>
>#include <bits/c++config.h>
>
>/**
> * @defgroup coroutines Coroutines
> *
> * Components for supporting coroutine implementations.
> */
>
>#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
>#  include <compare>
>#  define _COROUTINES_USE_SPACESHIP 1
>#else
>#  include <bits/stl_function.h> // for std::less
>#  define _COROUTINES_USE_SPACESHIP 0
>#endif
>
>namespace std _GLIBCXX_VISIBILITY (default)
>{
>  _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
>#if __cpp_coroutines
>  inline namespace __n4835 {
>
>  // 17.12.2 coroutine traits
>  /// [coroutine.traits]
>  /// [coroutine.traits.primary]
>  template <typename _Result, typename...>
>    struct coroutine_traits
>    {
>       using promise_type = typename _Result::promise_type;
>    };
>
>  // 17.12.3 Class template coroutine_handle
>  /// [coroutine.handle]
>  template <typename _Promise = void>
>    struct coroutine_handle;
>
>  template <> struct
>    coroutine_handle<void>
>    {
>    public:
>      // 17.12.3.1, construct/reset
>      constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {}
>
>      constexpr coroutine_handle(std::nullptr_t __h) noexcept
>	: _M_fr_ptr(__h)
>      {}
>
>      coroutine_handle& operator=(std::nullptr_t) noexcept
>      {
>	_M_fr_ptr = nullptr;
>	return *this;
>      }
>
>    public:
>      // 17.12.3.2, export/import
>      constexpr void* address() const noexcept { return _M_fr_ptr; }
>
>      constexpr static coroutine_handle from_address(void* __a) noexcept
>      {
>	coroutine_handle __self;
>	__self._M_fr_ptr = __a;
>	return __self;
>      }
>
>    public:
>      // 17.12.3.3, observers
>      constexpr explicit operator bool() const noexcept
>      {
>	return bool(_M_fr_ptr);
>      }
>
>      bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); }
>
>      // 17.12.3.4, resumption
>      void operator()() const { resume(); }
>
>      void resume() const { __builtin_coro_resume(_M_fr_ptr); }
>
>      void destroy() const { __builtin_coro_destroy(_M_fr_ptr); }
>
>    protected:
>      void* _M_fr_ptr;
>  };
>
>  // 17.12.3.6 Comparison operators
>  /// [coroutine.handle.compare]
>  constexpr bool operator==(coroutine_handle<> __a,
>			    coroutine_handle<> __b) noexcept
>  {
>    return __a.address() == __b.address();
>  }
>
>#if _COROUTINES_USE_SPACESHIP
>  constexpr strong_ordering
>  operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept;

I think this needs to be defined, not just declared:

   { return std::compare_three_way()(__a.address(), __b.address()); }


OK for trunk (assuming it still works with that change).
diff mbox series

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index b38defcafb..ad4404793b 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -38,6 +38,7 @@  std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
 	${std_srcdir}/filesystem \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea6..f8b5645224 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -382,6 +382,7 @@  std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
 	${std_srcdir}/filesystem \
diff --git a/libstdc++-v3/include/std/coroutine b/libstdc++-v3/include/std/coroutine
new file mode 100644
index 0000000000..9eaffaba12
--- /dev/null
+++ b/libstdc++-v3/include/std/coroutine
@@ -0,0 +1,269 @@ 
+// <coroutine> -*- C++ -*-
+
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/coroutine
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_EXPERIMENTAL_COROUTINE
+#define _GLIBCXX_EXPERIMENTAL_COROUTINE 1
+
+#pragma GCC system_header
+
+// It is very likely that earlier versions would work, but they are untested.
+#if __cplusplus >= 201402L
+
+#include <bits/c++config.h>
+
+/**
+ * @defgroup coroutines Coroutines
+ *
+ * Components for supporting coroutine implementations.
+ */
+
+#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
+#  include <compare>
+#  define _COROUTINES_USE_SPACESHIP 1
+#else
+#  include <bits/stl_function.h>
+#  define _COROUTINES_USE_SPACESHIP 0
+#endif
+
+namespace std _GLIBCXX_VISIBILITY (default)
+{
+  _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#if __cpp_coroutines
+  inline namespace __n4835 {
+
+  // 17.12.2 coroutine traits
+  /// [coroutine.traits]
+  /// [coroutine.traits.primary]
+  template <typename _R, typename...> struct coroutine_traits
+  {
+    using promise_type = typename _R::promise_type;
+  };
+
+  // 17.12.3 Class template coroutine_handle
+  /// [coroutine.handle]
+  template <typename _Promise = void> struct coroutine_handle;
+
+  template <> struct coroutine_handle<void>
+  {
+  public:
+    // 17.12.3.1, construct/reset
+    constexpr coroutine_handle () noexcept : _M_fr_ptr (0) {}
+    constexpr coroutine_handle (decltype (nullptr) __h) noexcept
+      : _M_fr_ptr (__h)
+    {}
+    coroutine_handle &operator= (decltype (nullptr)) noexcept
+    {
+      _M_fr_ptr = nullptr;
+      return *this;
+    }
+
+  public:
+    // 17.12.3.2, export/import
+    constexpr void *address () const noexcept { return _M_fr_ptr; }
+    constexpr static coroutine_handle from_address (void *__a) noexcept
+    {
+      coroutine_handle __self;
+      __self._M_fr_ptr = __a;
+      return __self;
+    }
+
+  public:
+    // 17.12.3.3, observers
+    constexpr explicit operator bool () const noexcept
+    {
+      return bool(_M_fr_ptr);
+    }
+    bool done () const noexcept { return __builtin_coro_done (_M_fr_ptr); }
+    // 17.12.3.4, resumption
+    void operator() () const { resume (); }
+    void resume () const { __builtin_coro_resume (_M_fr_ptr); }
+    void destroy () const { __builtin_coro_destroy (_M_fr_ptr); }
+
+  protected:
+    void *_M_fr_ptr;
+  };
+
+  // 17.12.3.6 Comparison operators
+  /// [coroutine.handle.compare]
+  constexpr bool operator== (coroutine_handle<> __a,
+			     coroutine_handle<> __b) noexcept
+  {
+    return __a.address () == __b.address ();
+  }
+
+#if _COROUTINES_USE_SPACESHIP
+  constexpr strong_ordering
+  operator<=> (coroutine_handle<> __a, coroutine_handle<> __b) noexcept;
+#else
+  // These are from the TS to enable operation with std=c++14,17.
+  constexpr bool operator!= (coroutine_handle<> __a,
+			     coroutine_handle<> __b) noexcept
+  {
+    return !(__a == __b);
+  }
+
+  constexpr bool operator< (coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return less<void *> () (__a.address (), __b.address ());
+  }
+
+  constexpr bool operator> (coroutine_handle<> __a,
+			    coroutine_handle<> __b) noexcept
+  {
+    return __b < __a;
+  }
+
+  constexpr bool operator<= (coroutine_handle<> __a,
+			     coroutine_handle<> __b) noexcept
+  {
+    return !(__a > __b);
+  }
+
+  constexpr bool operator>= (coroutine_handle<> __a,
+			     coroutine_handle<> __b) noexcept
+  {
+    return !(__a < __b);
+  }
+#endif
+
+  template <class _Promise> struct coroutine_handle : coroutine_handle<>
+  {
+    // 17.12.3.1, construct/reset
+    using coroutine_handle<>::coroutine_handle;
+    static coroutine_handle from_promise (_Promise &p)
+    {
+      coroutine_handle __self;
+      __self._M_fr_ptr
+	= __builtin_coro_promise ((char *) &p, __alignof(_Promise), true);
+      return __self;
+    }
+    coroutine_handle &operator= (decltype (nullptr)) noexcept
+    {
+      coroutine_handle<>::operator= (nullptr);
+      return *this;
+    }
+    // 17.12.3.2, export/import
+    constexpr static coroutine_handle from_address (void *__a)
+    {
+      coroutine_handle __self;
+      __self._M_fr_ptr = __a;
+      return __self;
+    }
+    // 17.12.3.5, promise accesss
+    _Promise &promise () const
+    {
+      void *__t
+	= __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false);
+      return *static_cast<_Promise *> (__t);
+    }
+  };
+
+  /// [coroutine.noop]
+  struct noop_coroutine_promise
+  {
+  };
+
+  void __dummy_resume_destroy () __attribute__ ((__weak__));
+  void __dummy_resume_destroy () {}
+
+  struct __noop_coro_frame
+  {
+    void (*__r) () = __dummy_resume_destroy;
+    void (*__d) () = __dummy_resume_destroy;
+    struct noop_coroutine_promise __p;
+  } __noop_coro_fr __attribute__ ((__weak__));
+
+  // 17.12.4.1 Class noop_coroutine_promise
+  /// [coroutine.promise.noop]
+  template <>
+  class coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>
+  {
+    using _Promise = noop_coroutine_promise;
+
+  public:
+    // 17.12.4.2.1, observers
+    constexpr explicit operator bool () const noexcept { return true; }
+    constexpr bool done () const noexcept { return false; }
+
+    // 17.12.4.2.2, resumption
+    void operator() () const noexcept {}
+    void resume () const noexcept {}
+    void destroy () const noexcept {}
+
+    // 17.12.4.2.3, promise access
+    _Promise &promise () const
+    {
+      return *static_cast<_Promise *> (
+	__builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false));
+    }
+
+    // 17.12.4.2.4, address
+    // constexpr void* address() const noexcept;
+  private:
+    friend coroutine_handle<noop_coroutine_promise> noop_coroutine () noexcept;
+
+    coroutine_handle () noexcept { this->_M_fr_ptr = (void *) &__noop_coro_fr; }
+  };
+
+  using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
+
+  inline noop_coroutine_handle noop_coroutine () noexcept
+  {
+    return noop_coroutine_handle ();
+  }
+
+  // 17.12.5 Trivial awaitables
+  /// [coroutine.trivial.awaitables]
+  struct suspend_always
+  {
+    bool await_ready () { return false; }
+    void await_suspend (coroutine_handle<>) {}
+    void await_resume () {}
+  };
+
+  struct suspend_never
+  {
+    bool await_ready () { return true; }
+    void await_suspend (coroutine_handle<>) {}
+    void await_resume () {}
+  };
+
+  } // namespace __n4835
+
+#else
+#error "the coroutine header requires -fcoroutines"
+#endif
+
+  _GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std_GLIBCXX_VISIBILITY(default)
+
+#endif // C++14 (we are allowing use from at least this)
+
+#endif // _GLIBCXX_EXPERIMENTAL_COROUTINE