Index: libcxx/include/experimental/coroutine =================================================================== --- libcxx/include/experimental/coroutine +++ libcxx/include/experimental/coroutine @@ -5,6 +5,7 @@ // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// TODO: Move coroutine components out of experimental namespace //===----------------------------------------------------------------------===// #ifndef _LIBCPP_EXPERIMENTAL_COROUTINE @@ -13,31 +14,30 @@ /** experimental/coroutine synopsis -// C++next - namespace std { namespace experimental { inline namespace coroutines_v1 { - // 18.11.1 coroutine traits +// [coroutine.traits] template -class coroutine_traits; -// 18.11.2 coroutine handle + struct coroutine_traits; +// [coroutine.handle] template -class coroutine_handle; -// 18.11.2.7 comparison operators: -bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -bool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -bool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -bool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -bool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; -// 18.11.3 trivial awaitables -struct suspend_never; -struct suspend_always; -// 18.11.2.8 hash support: + struct coroutine_handle; +// [coroutine.handle.compare] +constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; +constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept; +// [coroutine.handle.hash] template struct hash; template struct hash>; +// [coroutine.noop] +struct noop_coroutine_promise; +template<> struct coroutine_handle; +using noop_coroutine_handle = coroutine_handle; +noop_coroutine_handle noop_coroutine() noexcept; +// [coroutine.trivial.awaitables] +struct suspend_never; +struct suspend_always; } // namespace coroutines_v1 } // namespace experimental @@ -49,7 +49,8 @@ #include #include #include -#include // for hash +#include <__functional/hash.h> +#include <__compare/ordering.h> #include #include <__debug> @@ -65,10 +66,24 @@ # endif #endif +#if _LIBCPP_STD_VER < 14 +# error "Coroutine could only be used with standard greater than 11." +#endif + #ifndef _LIBCPP_HAS_NO_COROUTINES _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES +// [coroutine.traits] +// [coroutine.traits.primary] +// The header defines the primary template coroutine_­traits such that +// if ArgTypes is a parameter pack of types and if the qualified-id R​::​promise_­type +// is valid and denotes a type ([temp.deduct]), then coroutine_­traits +// has the following publicly accessible member: +// +// using promise_type = typename R::promise_type; +// +// Otherwise, coroutine_­traits has no members. template struct __coroutine_traits_sfinae {}; @@ -76,7 +91,7 @@ struct __coroutine_traits_sfinae< _Tp, typename __void_t::type> { - using promise_type = typename _Tp::promise_type; + using promise_type = typename _Tp::promise_type; }; template @@ -85,234 +100,284 @@ { }; +// [coroutine.handle] template -class _LIBCPP_TEMPLATE_VIS coroutine_handle; +struct _LIBCPP_TEMPLATE_VIS coroutine_handle; template <> -class _LIBCPP_TEMPLATE_VIS coroutine_handle { +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { public: - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} + // [coroutine.handle.con], construct/reset + _LIBCPP_HIDE_FROM_ABI + constexpr coroutine_handle() noexcept {} - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI + constexpr coroutine_handle(nullptr_t) noexcept {} - _LIBCPP_INLINE_VISIBILITY - coroutine_handle& operator=(nullptr_t) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI + coroutine_handle& operator=(nullptr_t) noexcept { __handle_ = nullptr; return *this; } - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } - - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } - - _LIBCPP_INLINE_VISIBILITY - void operator()() { resume(); } + // [coroutine.handle.export.import], export/import + _LIBCPP_HIDE_FROM_ABI + constexpr void* address() const noexcept { return __handle_; } - _LIBCPP_INLINE_VISIBILITY - void resume() { - _LIBCPP_ASSERT(__is_suspended(), - "resume() can only be called on suspended coroutines"); - _LIBCPP_ASSERT(!done(), - "resume() has undefined behavior when the coroutine is done"); - __builtin_coro_resume(__handle_); + _LIBCPP_HIDE_FROM_ABI + constexpr static coroutine_handle from_address(void* __addr) noexcept { + coroutine_handle __tmp; + __tmp.__handle_ = __addr; + return __tmp; } - _LIBCPP_INLINE_VISIBILITY - void destroy() { - _LIBCPP_ASSERT(__is_suspended(), - "destroy() can only be called on suspended coroutines"); - __builtin_coro_destroy(__handle_); - } + // [coroutine.handle.observers], observers + _LIBCPP_HIDE_FROM_ABI + constexpr explicit operator bool() const noexcept { return __handle_; } - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI bool done() const { - _LIBCPP_ASSERT(__is_suspended(), - "done() can only be called on suspended coroutines"); - return __builtin_coro_done(__handle_); + _LIBCPP_ASSERT(__is_suspended(), + "done() can only be called on suspended coroutines"); + return __builtin_coro_done(__handle_); } -public: - _LIBCPP_INLINE_VISIBILITY - static coroutine_handle from_address(void* __addr) _NOEXCEPT { - coroutine_handle __tmp; - __tmp.__handle_ = __addr; - return __tmp; - } + // [coroutine.handle.resumption], resumption + _LIBCPP_HIDE_FROM_ABI + void operator()() const { resume(); } - // FIXME: Should from_address(nullptr) be allowed? - _LIBCPP_INLINE_VISIBILITY - static coroutine_handle from_address(nullptr_t) _NOEXCEPT { - return coroutine_handle(nullptr); + _LIBCPP_HIDE_FROM_ABI + void resume() const { + _LIBCPP_ASSERT(__is_suspended(), + "resume() can be called only on suspended coroutines"); + _LIBCPP_ASSERT(!done(), + "resume() has undefined behavior when the coroutine is done"); + __builtin_coro_resume(__handle_); } - template - static coroutine_handle from_address(_Tp*) { - static_assert(_CallIsValid, - "coroutine_handle::from_address cannot be called with " - "non-void pointers"); + _LIBCPP_HIDE_FROM_ABI + void destroy() const { + _LIBCPP_ASSERT(__is_suspended(), + "destroy() can only be called on suspended coroutines"); + __builtin_coro_destroy(__handle_); } private: - bool __is_suspended() const _NOEXCEPT { - // FIXME actually implement a check for if the coro is suspended. - return __handle_; - } + bool __is_suspended() const noexcept { + // FIXME actually implement a check for if the coro is suspended. + return __handle_; + } - template friend class coroutine_handle; - void* __handle_; + void* __handle_ = nullptr; }; -// 18.11.2.7 comparison operators: -inline _LIBCPP_INLINE_VISIBILITY -bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { +// [coroutine.handle.compare] +#if defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return __x.address() == __y.address(); } -inline _LIBCPP_INLINE_VISIBILITY -bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { - return !(__x == __y); -} -inline _LIBCPP_INLINE_VISIBILITY -bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return less()(__x.address(), __y.address()); } -inline _LIBCPP_INLINE_VISIBILITY -bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return __y < __x; } -inline _LIBCPP_INLINE_VISIBILITY -bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return !(__x > __y); } -inline _LIBCPP_INLINE_VISIBILITY -bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return !(__x < __y); } +#else + +inline _LIBCPP_HIDE_FROM_ABI +constexpr bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { + return __x.address() == __y.address(); +} +inline _LIBCPP_HIDE_FROM_ABI +constexpr strong_ordering operator<=>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { + return __x.address() <=> __y.address(); +} + +#endif // defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + template -class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { - using _Base = coroutine_handle<>; +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { public: -#ifndef _LIBCPP_CXX03_LANG - // 18.11.2.1 construct/reset - using coroutine_handle<>::coroutine_handle; -#else - _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} - _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} -#endif - _LIBCPP_INLINE_VISIBILITY - coroutine_handle& operator=(nullptr_t) _NOEXCEPT { - _Base::operator=(nullptr); - return *this; + // [coroutine.handle.con], construct/reset + _LIBCPP_HIDE_FROM_ABI + constexpr coroutine_handle() noexcept = default; + + _LIBCPP_HIDE_FROM_ABI + constexpr coroutine_handle(nullptr_t) noexcept {} + + _LIBCPP_HIDE_FROM_ABI + static coroutine_handle from_promise(_Promise& __promise) { + using _RawPromise = typename remove_cv<_Promise>::type ; + coroutine_handle __tmp; + __tmp.__handle_ = __builtin_coro_promise( + _VSTD::addressof(const_cast<_RawPromise&>(__promise)), + _LIBCPP_ALIGNOF(_Promise), true); + return __tmp; } - _LIBCPP_INLINE_VISIBILITY - _Promise& promise() const { - return *static_cast<_Promise*>( - __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); + _LIBCPP_HIDE_FROM_ABI + coroutine_handle& operator=(nullptr_t) noexcept { + __handle_ = nullptr; + return *this; } -public: - _LIBCPP_INLINE_VISIBILITY - static coroutine_handle from_address(void* __addr) _NOEXCEPT { + // [coroutine.handle.export.import], export/import + _LIBCPP_HIDE_FROM_ABI + constexpr void* address() const noexcept { return __handle_;} + + _LIBCPP_HIDE_FROM_ABI + static constexpr coroutine_handle from_address(void* __addr) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __addr; return __tmp; } - // NOTE: this overload isn't required by the standard but is needed so - // the deleted _Promise* overload doesn't make from_address(nullptr) - // ambiguous. - // FIXME: should from_address work with nullptr? - _LIBCPP_INLINE_VISIBILITY - static coroutine_handle from_address(nullptr_t) _NOEXCEPT { - return coroutine_handle(nullptr); + // [coroutine.handle.conv], conversion + _LIBCPP_HIDE_FROM_ABI + constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(address()); } - template - static coroutine_handle from_address(_Tp*) { - static_assert(_CallIsValid, - "coroutine_handle::from_address cannot be called with " - "non-void pointers"); + // [coroutine.handle.observers], observers + _LIBCPP_HIDE_FROM_ABI + constexpr explicit operator bool() const noexcept { return __handle_; } + + _LIBCPP_HIDE_FROM_ABI + bool done() const { + _LIBCPP_ASSERT(__is_suspended(), + "done() can only be called on suspended coroutines"); + return __builtin_coro_done(__handle_); } - template - static coroutine_handle from_address(_Promise*) { - static_assert(_CallIsValid, - "coroutine_handle::from_address cannot be used with " - "pointers to the coroutine's promise type; use 'from_promise' instead"); + // [coroutine.handle.resumption], resumption + _LIBCPP_HIDE_FROM_ABI + void operator()() const { resume(); } + + _LIBCPP_HIDE_FROM_ABI + void resume() const { + _LIBCPP_ASSERT(__is_suspended(), + "resume() can be called only on suspended coroutines"); + _LIBCPP_ASSERT(!done(), + "resume() has undefined behavior when the coroutine is done"); + __builtin_coro_resume(__handle_); } - _LIBCPP_INLINE_VISIBILITY - static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { - typedef typename remove_cv<_Promise>::type _RawPromise; - coroutine_handle __tmp; - __tmp.__handle_ = __builtin_coro_promise( - _VSTD::addressof(const_cast<_RawPromise&>(__promise)), - _LIBCPP_ALIGNOF(_Promise), true); - return __tmp; + _LIBCPP_HIDE_FROM_ABI + void destroy() const { + _LIBCPP_ASSERT(__is_suspended(), + "destroy() can only be called on suspended coroutines"); + __builtin_coro_destroy(__handle_); + } + + // [coroutine.handle.promise], promise access + _LIBCPP_HIDE_FROM_ABI + _Promise& promise() const { + return *static_cast<_Promise*>( + __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); + } + +private: + bool __is_suspended() const noexcept { + // FIXME actually implement a check for if the coro is suspended. + return __handle_; } + void* __handle_ = nullptr; }; -#if __has_builtin(__builtin_coro_noop) +#if !__has_builtin(__builtin_coro_noop) +# error "Require __builtin_coro_noop to support noop_coroutine" +#endif + +// [coroutine.noop] +// [coroutine.promise.noop] struct noop_coroutine_promise {}; +// [coroutine.handle.noop] template <> -class _LIBCPP_TEMPLATE_VIS coroutine_handle - : public coroutine_handle<> { - using _Base = coroutine_handle<>; - using _Promise = noop_coroutine_promise; +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { public: + // [coroutine.handle.noop.conv], conversion + _LIBCPP_HIDE_FROM_ABI + constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(address()); + } - _LIBCPP_INLINE_VISIBILITY - _Promise& promise() const { - return *static_cast<_Promise*>( - __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); - } - - _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } - _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } + // [coroutine.handle.noop.observers], observers + _LIBCPP_HIDE_FROM_ABI + constexpr explicit operator bool() const noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI + constexpr bool done() const noexcept { return false; } + + // [coroutine.handle.noop.resumption], resumption + _LIBCPP_HIDE_FROM_ABI + constexpr void operator()() const noexcept {} + _LIBCPP_HIDE_FROM_ABI + constexpr void resume() const noexcept {} + _LIBCPP_HIDE_FROM_ABI + constexpr void destroy() const noexcept {} + + // [coroutine.handle.noop.promise], promise access + _LIBCPP_HIDE_FROM_ABI + noop_coroutine_promise& promise() const noexcept { + return *static_cast( + __builtin_coro_promise(this->__handle_, + _LIBCPP_ALIGNOF(noop_coroutine_promise), + false)); + } - _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {} - _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {} - _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {} + // [coroutine.handle.noop.address], address + _LIBCPP_HIDE_FROM_ABI + constexpr void* address() const noexcept {return __handle_; } private: - _LIBCPP_INLINE_VISIBILITY - friend coroutine_handle noop_coroutine() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI + friend coroutine_handle noop_coroutine() noexcept; + + _LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept { + this->__handle_ = __builtin_coro_noop(); + } - _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { - this->__handle_ = __builtin_coro_noop(); - } + void *__handle_ = nullptr; }; using noop_coroutine_handle = coroutine_handle; -inline _LIBCPP_INLINE_VISIBILITY -noop_coroutine_handle noop_coroutine() _NOEXCEPT { - return noop_coroutine_handle(); +// [coroutine.noop.coroutine] +inline _LIBCPP_HIDE_FROM_ABI +noop_coroutine_handle noop_coroutine() noexcept { + return noop_coroutine_handle(); } -#endif // __has_builtin(__builtin_coro_noop) +// [coroutine.trivial.awaitables] struct suspend_never { - _LIBCPP_INLINE_VISIBILITY - bool await_ready() const _NOEXCEPT { return true; } - _LIBCPP_INLINE_VISIBILITY - void await_suspend(coroutine_handle<>) const _NOEXCEPT {} - _LIBCPP_INLINE_VISIBILITY - void await_resume() const _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI + bool await_ready() const noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI + void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI + void await_resume() const noexcept {} }; struct suspend_always { - _LIBCPP_INLINE_VISIBILITY - bool await_ready() const _NOEXCEPT { return false; } - _LIBCPP_INLINE_VISIBILITY - void await_suspend(coroutine_handle<>) const _NOEXCEPT {} - _LIBCPP_INLINE_VISIBILITY - void await_resume() const _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI + bool await_ready() const noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI + void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI + void await_resume() const noexcept {} }; _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES @@ -321,14 +386,13 @@ template struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { - using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; - _LIBCPP_INLINE_VISIBILITY - size_t operator()(__arg_type const& __v) const _NOEXCEPT - {return hash()(__v.address());} + using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; + _LIBCPP_HIDE_FROM_ABI + size_t operator()(const __arg_type& __v) const noexcept { return hash()(__v.address()); } }; _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_COROUTINES) -#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ +#endif // _LIBCPP_EXPERIMENTAL_COROUTINE Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp @@ -14,8 +14,8 @@ // template // struct coroutine_handle; -// bool operator==(coroutine_handle<>, coroutine_handle<>) noexcept -// bool operator!=(coroutine_handle<>, coroutine_handle<>) noexcept +// constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; + #include #include Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp @@ -14,10 +14,7 @@ // template // struct coroutine_handle; -// bool operator<(coroutine_handle<>, coroutine_handle<>) noexcept -// bool operator>(coroutine_handle<>, coroutine_handle<>) noexcept -// bool operator>=(coroutine_handle<>, coroutine_handle<>) noexcept -// bool operator<=(coroutine_handle<>, coroutine_handle<>) noexcept +// constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept; #include #include Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.fail.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.fail.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11 -// - -// template -// struct coroutine_handle; - -// static coroutine_handle from_address(void*) noexcept - -// Test that `from_address` is explicitly ill-formed when called with a typed -// pointer. The user cannot possibly have a typed pointer to the coroutine. -// FIXME: This behavior is an extension, and should upstreamed into the TS or -// the test removed if the TS changes are rejected. - -#include -#include -#include - -namespace coro = std::experimental; - -int main(int, char**) -{ - { - using H = coro::coroutine_handle<>; - // expected-error@experimental/coroutine:* 3 {{coroutine_handle::from_address cannot be called with non-void pointers}} - H::from_address((int*)nullptr); // expected-note {{requested here}} - H::from_address((const void*)nullptr); // expected-note {{requested here}} - H::from_address((const char*)nullptr); // expected-note {{requested here}} - } - { - using H = coro::coroutine_handle; - // expected-error@experimental/coroutine:* 1 {{static_assert failed "coroutine_handle::from_address cannot be used with pointers to the coroutine's promise type; use 'from_promise' instead"}} - H::from_address((const char*)nullptr); // expected-note {{requested here}} - // expected-error@experimental/coroutine:* 1 {{coroutine_handle::from_address cannot be called with non-void pointers}} - H::from_address((int*)nullptr); // expected-note {{requested here}} - } - - return 0; -} Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.pass.cpp @@ -29,7 +29,6 @@ { C c = C::from_address(nullptr); static_assert(noexcept(C::from_address(nullptr)), ""); - // FIXME: Should the return type not be 'C'? static_assert(std::is_same::value, ""); assert(c.address() == nullptr); } @@ -38,6 +37,18 @@ C c = C::from_address((void*)&dummy); assert(c.address() == &dummy); } + { + C::from_address((int*)nullptr); + C::from_address((void* const)nullptr); + C::from_address((char* const)nullptr); + } + { + char dummy = 42; + C c = C::from_address(&dummy); + int *p = (int*)c.address(); + coro::coroutine_handle<> c2 = coro::coroutine_handle<>::from_address(p); + assert (c2 == c); + } } int main(int, char**) Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.noop/noop_coroutine.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.noop/noop_coroutine.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.noop/noop_coroutine.pass.cpp @@ -31,19 +31,19 @@ // template <> struct coroutine_handle : coroutine_handle<> // { -// // 18.11.2.7 noop observers +// // [coroutine.handle.noop.observers], observers // constexpr explicit operator bool() const noexcept; // constexpr bool done() const noexcept; -// // 18.11.2.8 noop resumption +// // [coroutine.handle.noop.resumption], resumption // constexpr void operator()() const noexcept; // constexpr void resume() const noexcept; // constexpr void destroy() const noexcept; -// // 18.11.2.9 noop promise access +// // [coroutine.handle.noop.promise], promise access // noop_coroutine_promise& promise() const noexcept; -// // 18.11.2.10 noop address +// // [coroutine.handle.noop.address], address // constexpr void* address() const noexcept; int main(int, char**) Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.pass.cpp @@ -14,7 +14,7 @@ // template // struct coroutine_handle; -// void destroy() +// void destroy() const #include #include @@ -48,8 +48,8 @@ static_assert(has_destroy(), ""); } { - static_assert(!has_destroy(), ""); - static_assert(!has_destroy(), ""); + static_assert(has_destroy(), ""); + static_assert(has_destroy(), ""); } } Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.pass.cpp @@ -14,8 +14,8 @@ // template // struct coroutine_handle; -// void operator()() -// void resume() +// void operator()() const +// void resume() const #include #include @@ -65,10 +65,10 @@ static_assert(has_call_operator(), ""); } { - static_assert(!has_resume(), ""); - static_assert(!has_resume(), ""); - static_assert(!has_call_operator(), ""); - static_assert(!has_call_operator(), ""); + static_assert(has_resume(), ""); + static_assert(has_resume(), ""); + static_assert(has_call_operator(), ""); + static_assert(has_call_operator(), ""); } }