Index: libcxx/docs/Status/SpaceshipProjects.csv =================================================================== --- libcxx/docs/Status/SpaceshipProjects.csv +++ libcxx/docs/Status/SpaceshipProjects.csv @@ -9,7 +9,6 @@ | `weak_order `_ | `partial_order `_",None,Arthur O'Dwyer,|In Progress| | `[alg.three.way] `_,| `lexicographical_compare_three_way `_,[comparisons.three.way],Christopher Di Bella,|In Progress| -| `[coroutine.handle.compare] `_,| coroutine_handle,[comparisons.three.way],Unassigned,|Not Started| | `[pairs.spec] `_,| `pair `_,[expos.only.func],Kent Ross,|In Progress| | `[syserr.errcat.nonvirtuals] `_,| error_category,[comparisons.three.way],Unassigned,|Not Started| | `[syserr.compare] `_,"| error_code 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 @@ -45,13 +45,13 @@ */ +#include <__debug> +#include <__functional/hash.h> +#include +#include #include #include #include -#include -#include // for hash -#include -#include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -65,10 +65,22 @@ # endif #endif +#if _LIBCPP_STD_VER > 11 + #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 {}; @@ -85,234 +97,259 @@ { }; +// [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) {} - - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} - - _LIBCPP_INLINE_VISIBILITY - coroutine_handle& operator=(nullptr_t) _NOEXCEPT { - __handle_ = nullptr; - return *this; - } +// [coroutine.handle.con], construct/reset +_LIBCPP_HIDE_FROM_ABI +constexpr coroutine_handle() noexcept {} - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } +_LIBCPP_HIDE_FROM_ABI +constexpr coroutine_handle(nullptr_t) noexcept {} - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } +_LIBCPP_HIDE_FROM_ABI +coroutine_handle& operator=(nullptr_t) noexcept { + __handle_ = nullptr; + return *this; +} - _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 +static constexpr 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 - bool done() const { - _LIBCPP_ASSERT(__is_suspended(), - "done() can only be called on suspended coroutines"); - return __builtin_coro_done(__handle_); +_LIBCPP_HIDE_FROM_ABI +bool done() const { + _LIBCPP_ASSERT(__is_suspended(), "done() can be called only 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 be called only 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)), 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()); } + + // [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 be called only on suspended coroutines"); + return __builtin_coro_done(__handle_); + } + + // [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_); } - 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 be called only on suspended coroutines"); + __builtin_coro_destroy(__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.promise], promise access + _LIBCPP_HIDE_FROM_ABI + _Promise& promise() const { + return *static_cast<_Promise*>(__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); } - _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; +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()); } + + // [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_, alignof(noop_coroutine_promise), false)); + } - _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; } - - _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(); -} -#endif // __has_builtin(__builtin_coro_noop) +// [coroutine.noop.coroutine] +inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); } +// [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 + constexpr bool await_ready() const noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI + constexpr void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI + constexpr 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 + constexpr bool await_ready() const noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI + constexpr void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI + constexpr void await_resume() const noexcept {} }; _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES @@ -322,13 +359,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());} + _LIBCPP_HIDE_FROM_ABI + size_t operator()(const __arg_type& __v) const noexcept { return hash()(__v.address()); } }; _LIBCPP_END_NAMESPACE_STD +#endif // _LIBCPP_STD_VER > 11 #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,7 @@ // 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*)nullptr); + C::from_address((char*)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 @@ -21,29 +21,26 @@ #include "test_macros.h" -#if __has_builtin(__builtin_coro_noop) - namespace coro = std::experimental::coroutines_v1; - static_assert(std::is_same, coro::noop_coroutine_handle>::value, ""); static_assert(std::is_same::value, ""); // 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**) @@ -65,14 +62,9 @@ h.promise(); assert(h.address() == base.address()); + assert(h==base); assert(h.address() != nullptr); assert(coro::coroutine_handle<>::from_address(h.address()) == base); return 0; -} - -#else - -int main(int, char**) { return 0; } - -#endif // __has_builtin(__builtin_coro_noop) +} \ No newline at end of file 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(), ""); } } Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.pass.cpp @@ -31,6 +31,15 @@ return true; } +template +constexpr bool test_trivial_awaitable_constexpr(bool expected) { + T t; + assert(t.await_ready() == expected); + t.await_suspend(nullptr); + t.await_resume(); + return true; +} + int main(int, char**) { using H = coro::coroutine_handle<>; @@ -65,6 +74,9 @@ static_assert(std::is_trivially_copyable::value, ""); static_assert(check_suspend_constexpr(), ""); } + { + static_assert(test_trivial_awaitable_constexpr(false)); + } { // suppress unused warnings for the global constexpr test variable ((void)constexpr_sa); Index: libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.pass.cpp =================================================================== --- libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.pass.cpp +++ libcxx/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.pass.cpp @@ -32,6 +32,14 @@ return true; } +template +constexpr bool test_trivial_awaitable_constexpr(bool expected) { + T t; + assert(t.await_ready() == expected); + t.await_suspend(nullptr); + t.await_resume(); + return true; +} int main(int, char**) { @@ -67,6 +75,9 @@ static_assert(std::is_trivially_copyable::value, ""); static_assert(check_suspend_constexpr(), ""); } + { + static_assert(test_trivial_awaitable_constexpr(true)); + } { // suppress unused warnings for the global constexpr test variable ((void)constexpr_sn); Index: libcxx/utils/generate_header_inclusion_tests.py =================================================================== --- libcxx/utils/generate_header_inclusion_tests.py +++ libcxx/utils/generate_header_inclusion_tests.py @@ -29,7 +29,7 @@ "chrono": ["compare"], "cinttypes": ["cstdint"], "complex.h": ["complex"], - # TODO "coroutine": ["compare"], + "coroutine": ["compare"], "deque": ["compare", "initializer_list"], "filesystem": ["compare"], "forward_list": ["compare", "initializer_list"],