coroutine_handle<void>
{
public:
- // 17.12.3.1, construct/reset
+ // [coroutine.handle.con], construct/reset
constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {}
constexpr coroutine_handle(std::nullptr_t __h) noexcept
}
public:
- // 17.12.3.2, export/import
+ // [coroutine.handle.export.import], export/import
constexpr void* address() const noexcept { return _M_fr_ptr; }
constexpr static coroutine_handle from_address(void* __a) noexcept
}
public:
- // 17.12.3.3, observers
+ // [coroutine.handle.observers], 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
+ // [coroutine.handle.resumption], resumption
void operator()() const { resume(); }
void resume() const { __builtin_coro_resume(_M_fr_ptr); }
void* _M_fr_ptr;
};
- // 17.12.3.6 Comparison operators
- /// [coroutine.handle.compare]
- constexpr bool operator==(coroutine_handle<> __a,
- coroutine_handle<> __b) noexcept
+ // [coroutine.handle.compare], comparison operators
+
+ 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
- { return std::compare_three_way()(__a.address(), __b.address()); }
+ {
+ return std::compare_three_way()(__a.address(), __b.address());
+ }
#else
// These are to enable operation with std=c++14,17.
- constexpr bool operator!=(coroutine_handle<> __a,
- coroutine_handle<> __b) noexcept
+ constexpr bool
+ operator!=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept
{
return !(__a == __b);
}
- constexpr bool operator<(coroutine_handle<> __a,
- coroutine_handle<> __b) noexcept
+ 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
+ constexpr bool
+ operator>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept
{
return __b < __a;
}
- constexpr bool operator<=(coroutine_handle<> __a,
- coroutine_handle<> __b) noexcept
+ constexpr bool
+ operator<=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept
{
return !(__a > __b);
}
- constexpr bool operator>=(coroutine_handle<> __a,
- coroutine_handle<> __b) noexcept
+ constexpr bool
+ operator>=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept
{
return !(__a < __b);
}
#endif
template <typename _Promise>
- struct coroutine_handle : coroutine_handle<>
+ struct coroutine_handle
{
- // 17.12.3.1, construct/reset
- using coroutine_handle<>::coroutine_handle;
+ // [coroutine.handle.con], construct/reset
- static coroutine_handle from_promise(_Promise& p)
+ constexpr coroutine_handle() noexcept { }
+
+ constexpr coroutine_handle(nullptr_t) noexcept { }
+
+ static coroutine_handle
+ from_promise(_Promise& __p)
{
coroutine_handle __self;
__self._M_fr_ptr
- = __builtin_coro_promise((char*) &p, __alignof(_Promise), true);
+ = __builtin_coro_promise((char*) &__p, __alignof(_Promise), true);
return __self;
}
- coroutine_handle& operator=(std::nullptr_t) noexcept
+ coroutine_handle& operator=(nullptr_t) noexcept
{
- coroutine_handle<>::operator=(nullptr);
+ _M_fr_ptr = 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;
- }
+ // [coroutine.handle.export.import], export/import
- // 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);
- }
- };
+ constexpr void* address() const noexcept { return _M_fr_ptr; }
+
+ constexpr static coroutine_handle from_address(void* __a)
+ {
+ coroutine_handle __self;
+ __self._M_fr_ptr = __a;
+ return __self;
+ }
+
+ // [coroutine.handle.conv], conversion
+ constexpr operator coroutine_handle<>() const noexcept
+ { return coroutine_handle<>::from_address(address()); }
+
+ // [coroutine.handle.observers], observers
+ constexpr explicit operator bool() const noexcept
+ {
+ return bool(_M_fr_ptr);
+ }
+
+ bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); }
+
+ // [coroutine.handle.resumption], resumption
+ void operator()() const { resume(); }
+
+ void resume() const { __builtin_coro_resume(_M_fr_ptr); }
+
+ void destroy() const { __builtin_coro_destroy(_M_fr_ptr); }
+
+ // [coroutine.handle.promise], promise access
+ _Promise& promise() const
+ {
+ void* __t
+ = __builtin_coro_promise (_M_fr_ptr, __alignof(_Promise), false);
+ return *static_cast<_Promise*>(__t);
+ }
+
+ private:
+ void* _M_fr_ptr = nullptr;
+ };
/// [coroutine.noop]
struct noop_coroutine_promise
// 17.12.4.1 Class noop_coroutine_promise
/// [coroutine.promise.noop]
template <>
- struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>
+ struct coroutine_handle<noop_coroutine_promise>
{
- using _Promise = noop_coroutine_promise;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3460. Unimplementable noop_coroutine_handle guarantees
+ // [coroutine.handle.noop.conv], conversion
+ constexpr operator coroutine_handle<>() const noexcept
+ { return coroutine_handle<>::from_address(address()); }
- public:
- // 17.12.4.2.1, observers
+ // [coroutine.handle.noop.observers], observers
constexpr explicit operator bool() const noexcept { return true; }
constexpr bool done() const noexcept { return false; }
- // 17.12.4.2.2, resumption
+ // [coroutine.handle.noop.resumption], 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));
- }
+ // [coroutine.handle.noop.promise], promise access
+ noop_coroutine_promise& promise() const noexcept
+ { return __noop_coro_fr.__p; }
+
+ // [coroutine.handle.noop.address], address
+ constexpr void* address() const noexcept { return _M_fr_ptr; }
- // 17.12.4.2.4, address
private:
- friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
+ friend coroutine_handle noop_coroutine() noexcept;
+
+ coroutine_handle() = default;
- coroutine_handle() noexcept { this->_M_fr_ptr = (void*) &__noop_coro_fr; }
+ void* _M_fr_ptr = (void*) &__noop_coro_fr;
};
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
--- /dev/null
+// Copyright (C) 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <coroutine>
+
+void
+test01()
+{
+ // LWG 3460. Unimplementable noop_coroutine_handle guarantees
+
+ static_assert( std::is_convertible_v<std::noop_coroutine_handle&,
+ std::coroutine_handle<>> );
+ static_assert( ! std::is_convertible_v<std::noop_coroutine_handle&,
+ std::coroutine_handle<>&> );
+ static_assert( ! std::is_assignable_v<std::noop_coroutine_handle&,
+ std::coroutine_handle<>> );
+
+ std::noop_coroutine_handle h = std::noop_coroutine();
+ std::coroutine_handle<> h2 = h;
+ h2(); // no-op
+ h2.resume(); // no-op
+ h2.destroy(); // no-op
+}
+
+void
+test02()
+{
+ // LWG 3469. Precondition of coroutine_handle::promise may be insufficient
+
+ struct P1 { };
+ struct P2 { };
+
+ static_assert( ! std::is_assignable_v<std::coroutine_handle<P1>&,
+ std::coroutine_handle<>> );
+ static_assert( ! std::is_assignable_v<std::coroutine_handle<P1>&,
+ std::coroutine_handle<P2>> );
+}