forked from OSchip/llvm-project
[libcxx] [Coroutine] Conform Coroutine Implementation
Since coroutine is merged in C++ standard and the support for coroutine seems relatively stable. It's the time to move the implementation of coroutine out of the experimental directory and the std::experimental namespace. This patch creates header <coroutine> with conformed implementation with C++ standard. To avoid breaking user's code too fast, the <experimental/coroutine> header is remained. Note that <experimental/coroutine> is deprecated and it would be removed in LLVM15. Reviewed By: Quuxplusone, ldionne Differential Revision: https://reviews.llvm.org/D109433
This commit is contained in:
parent
1585b13024
commit
2e6ae1d3f2
libcxx
docs
include
test
libcxx
diagnostics/detail.headers/coroutine
coroutine_handle.module.verify.cppcoroutine_traits.module.verify.cppnoop_coroutine_handle.module.verify.cpptrivial_awaitables.module.verify.cpp
double_include.sh.cppinclusions
min_max_macros.compile.pass.cppno_assert_include.compile.pass.cppstd
experimental/language.support/support.coroutines/end.to.end
language.support
support.coroutines
coroutine.handle
coroutine.handle.capacity
coroutine.handle.compare
coroutine.handle.completion
coroutine.handle.con
coroutine.handle.export
coroutine.handle.hash
coroutine.handle.noop
coroutine.handle.prom
coroutine.handle.resumption
void_handle.pass.cppcoroutine.traits
coroutine.trivial.awaitables
end.to.end
support.limits/support.limits.general
support
utils
|
@ -224,7 +224,7 @@ Status
|
|||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_vector`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_coroutine`` *unimplemented*
|
||||
``__cpp_lib_coroutine`` ``201902L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_destroying_delete`` ``201806L``
|
||||
------------------------------------------------- -----------------
|
||||
|
|
|
@ -292,7 +292,7 @@
|
|||
"`3388 <https://wg21.link/LWG3388>`__","``view``\ iterator types have ill-formed ``<=>``\ operators","Prague","","","|ranges|"
|
||||
"`3389 <https://wg21.link/LWG3389>`__","A move-only iterator still does not have a ``counted_iterator``\ ","Prague","","","|ranges|"
|
||||
"`3390 <https://wg21.link/LWG3390>`__","``make_move_iterator()``\ cannot be used to construct a ``move_iterator``\ for a move-only iterator","Prague","","","|ranges|"
|
||||
"`3393 <https://wg21.link/LWG3393>`__","Missing/incorrect feature test macro for coroutines","Prague","",""
|
||||
"`3393 <https://wg21.link/LWG3393>`__","Missing/incorrect feature test macro for coroutines","Prague","|Complete|","14.0"
|
||||
"`3395 <https://wg21.link/LWG3395>`__","Definition for three-way comparison needs to be updated (US 152)","Prague","","","|spaceship|"
|
||||
"`3396 <https://wg21.link/LWG3396>`__","Clarify point of reference for ``source_location::current()``\ (DE 169)","Prague","",""
|
||||
"`3397 <https://wg21.link/LWG3397>`__","``ranges::basic_istream_view::iterator``\ should not provide ``iterator_category``\ ","Prague","","","|ranges|"
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -9,7 +9,7 @@ Section,Description,Dependencies,Assignee,Complete
|
|||
| `weak_order <https://reviews.llvm.org/D107036>`_
|
||||
| `partial_order <https://reviews.llvm.org/D107036>`_",None,Arthur O'Dwyer,|In Progress|
|
||||
| `[alg.three.way] <https://wg21.link/alg.three.way>`_,| `lexicographical_compare_three_way <https://reviews.llvm.org/D80902>`_,[comparisons.three.way],Christopher Di Bella,|In Progress|
|
||||
| `[coroutine.handle.compare] <https://wg21.link/coroutine.handle.compare>`_,| coroutine_handle,[comparisons.three.way],Unassigned,|Not Started|
|
||||
| `[coroutine.handle.compare] <https://wg21.link/coroutine.handle.compare>`_,| coroutine_handle,[comparisons.three.way],Unassigned,|Complete|
|
||||
| `[pairs.spec] <https://wg21.link/pairs.spec>`_,| `pair <https://reviews.llvm.org/D107721>`_,[expos.only.func],Kent Ross,|Complete|
|
||||
| `[syserr.errcat.nonvirtuals] <https://wg21.link/syserr.errcat.nonvirtuals>`_,| error_category,[comparisons.three.way],Unassigned,|Not Started|
|
||||
| `[syserr.compare] <https://wg21.link/syserr.compare>`_,"| error_code
|
||||
|
|
|
|
@ -131,6 +131,10 @@ set(files
|
|||
__concepts/swappable.h
|
||||
__concepts/totally_ordered.h
|
||||
__config
|
||||
__coroutine/coroutine_handle.h
|
||||
__coroutine/coroutine_traits.h
|
||||
__coroutine/noop_coroutine_handle.h
|
||||
__coroutine/trivial_awaitables.h
|
||||
__debug
|
||||
__errc
|
||||
__format/format_arg.h
|
||||
|
@ -323,6 +327,7 @@ set(files
|
|||
complex.h
|
||||
concepts
|
||||
condition_variable
|
||||
coroutine
|
||||
csetjmp
|
||||
csignal
|
||||
cstdarg
|
||||
|
|
|
@ -1273,8 +1273,8 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
|
|||
#define _LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS
|
||||
#endif // _LIBCPP_ENABLE_CXX20_REMOVED_FEATURES
|
||||
|
||||
#if !defined(__cpp_coroutines) || __cpp_coroutines < 201703L
|
||||
#define _LIBCPP_HAS_NO_COROUTINES
|
||||
#if !defined(__cpp_impl_coroutine) || __cpp_impl_coroutine < 201902L
|
||||
#define _LIBCPP_HAS_NO_CXX20_COROUTINES
|
||||
#endif
|
||||
|
||||
#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201907L
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___COROUTINE_COROUTINE_HANDLE_H
|
||||
#define _LIBCPP___COROUTINE_COROUTINE_HANDLE_H
|
||||
|
||||
#include <__config>
|
||||
#include <__debug>
|
||||
#include <__functional/hash.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <compare>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
// [coroutine.handle]
|
||||
template <class _Promise = void>
|
||||
struct _LIBCPP_TEMPLATE_VIS coroutine_handle;
|
||||
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
|
||||
public:
|
||||
// [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
|
||||
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||
__handle_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// [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;
|
||||
}
|
||||
|
||||
// [coroutine.handle.observers], observers
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return __handle_ != nullptr;
|
||||
}
|
||||
|
||||
_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_);
|
||||
}
|
||||
|
||||
_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 {
|
||||
// FIXME actually implement a check for if the coro is suspended.
|
||||
return __handle_ != nullptr;
|
||||
}
|
||||
|
||||
void* __handle_ = nullptr;
|
||||
};
|
||||
|
||||
// [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_HIDE_FROM_ABI
|
||||
constexpr bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||
return less<void*>()(__x.address(), __y.address());
|
||||
}
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||
return __y < __x;
|
||||
}
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||
return !(__x > __y);
|
||||
}
|
||||
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 compare_three_way()(__x.address(), __y.address());
|
||||
}
|
||||
|
||||
#endif // defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR)
|
||||
|
||||
template <class _Promise>
|
||||
struct _LIBCPP_TEMPLATE_VIS coroutine_handle {
|
||||
public:
|
||||
// [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_HIDE_FROM_ABI
|
||||
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||
__handle_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// [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;
|
||||
}
|
||||
|
||||
// [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_ != nullptr;
|
||||
}
|
||||
|
||||
_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_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
void destroy() const {
|
||||
_LIBCPP_ASSERT(__is_suspended(), "destroy() can be called only 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_, alignof(_Promise), false));
|
||||
}
|
||||
|
||||
private:
|
||||
bool __is_suspended() const {
|
||||
// FIXME actually implement a check for if the coro is suspended.
|
||||
return __handle_ != nullptr;
|
||||
}
|
||||
void* __handle_ = nullptr;
|
||||
};
|
||||
|
||||
// [coroutine.handle.hash]
|
||||
template <class _Tp>
|
||||
struct hash<coroutine_handle<_Tp>> {
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept { return hash<void*>()(__v.address()); }
|
||||
};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // __LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
#endif // _LIBCPP___COROUTINE_COROUTINE_HANDLE_H
|
|
@ -0,0 +1,53 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___COROUTINE_COROUTINE_TRAITS_H
|
||||
#define _LIBCPP___COROUTINE_COROUTINE_TRAITS_H
|
||||
|
||||
#include <__config>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
// [coroutine.traits]
|
||||
// [coroutine.traits.primary]
|
||||
// The header <coroutine> defined 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<R, ArgTypes...>
|
||||
// has the following publicly accessible memebr:
|
||||
//
|
||||
// using promise_type = typename R::promise_type;
|
||||
//
|
||||
// Otherwise, coroutine_traits<R, ArgTypes...> has no members.
|
||||
template <class _Tp, class = void>
|
||||
struct __coroutine_traits_sfinae {};
|
||||
|
||||
template <class _Tp>
|
||||
struct __coroutine_traits_sfinae<
|
||||
_Tp, typename __void_t<typename _Tp::promise_type>::type>
|
||||
{
|
||||
using promise_type = typename _Tp::promise_type;
|
||||
};
|
||||
|
||||
template <class _Ret, class... _Args>
|
||||
struct coroutine_traits
|
||||
: public __coroutine_traits_sfinae<_Ret>
|
||||
{
|
||||
};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // __LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
#endif // _LIBCPP___COROUTINE_COROUTINE_TRAITS_H
|
|
@ -0,0 +1,86 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H
|
||||
#define _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H
|
||||
|
||||
#include <__config>
|
||||
#include <__coroutine/coroutine_handle.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if __has_builtin(__builtin_coro_noop)
|
||||
// [coroutine.noop]
|
||||
// [coroutine.promise.noop]
|
||||
struct noop_coroutine_promise {};
|
||||
|
||||
// [coroutine.handle.noop]
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise> {
|
||||
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<noop_coroutine_promise*>(
|
||||
__builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false));
|
||||
}
|
||||
|
||||
// [coroutine.handle.noop.address], address
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr void* address() const noexcept { return __handle_; }
|
||||
|
||||
private:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept {
|
||||
this->__handle_ = __builtin_coro_noop();
|
||||
}
|
||||
|
||||
void* __handle_ = nullptr;
|
||||
};
|
||||
|
||||
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
|
||||
|
||||
// [coroutine.noop.coroutine]
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); }
|
||||
|
||||
#endif // __has_builtin(__builtin_coro_noop)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // __LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
#endif // _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H
|
|
@ -0,0 +1,46 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H
|
||||
#define __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H
|
||||
|
||||
#include <__config>
|
||||
#include <__coroutine/coroutine_handle.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
// [coroutine.trivial.awaitables]
|
||||
struct suspend_never {
|
||||
_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_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_STD
|
||||
|
||||
#endif // __LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CXX20_COROUTINES)
|
||||
|
||||
#endif // __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H
|
|
@ -0,0 +1,52 @@
|
|||
// -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP_COROUTINE
|
||||
#define _LIBCPP_COROUTINE
|
||||
|
||||
/**
|
||||
coroutine synopsis
|
||||
|
||||
namespace std {
|
||||
// [coroutine.traits]
|
||||
template <class R, class... ArgTypes>
|
||||
struct coroutine_traits;
|
||||
// [coroutine.handle]
|
||||
template <class Promise = void>
|
||||
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 <class T> struct hash;
|
||||
template <class P> struct hash<coroutine_handle<P>>;
|
||||
// [coroutine.noop]
|
||||
struct noop_coroutine_promise;
|
||||
template<> struct coroutine_handle<noop_coroutine_promise>;
|
||||
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
|
||||
noop_coroutine_handle noop_coroutine() noexcept;
|
||||
// [coroutine.trivial.awaitables]
|
||||
struct suspend_never;
|
||||
struct suspend_always;
|
||||
} // namespace std
|
||||
|
||||
*/
|
||||
|
||||
#include <__config>
|
||||
#include <__coroutine/coroutine_handle.h>
|
||||
#include <__coroutine/noop_coroutine_handle.h>
|
||||
#include <__coroutine/coroutine_traits.h>
|
||||
#include <__coroutine/trivial_awaitables.h>
|
||||
#include <version>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#endif // _LIBCPP_COROUTINE
|
|
@ -45,6 +45,10 @@
|
|||
#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
|
||||
} } _LIBCPP_END_NAMESPACE_EXPERIMENTAL
|
||||
|
||||
#if !defined(__cpp_coroutines) || __cpp_coroutines < 201703L
|
||||
#define _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
#endif
|
||||
|
||||
#define _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES \
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL inline namespace coroutines_v1 {
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ template <class P> struct hash<coroutine_handle<P>>;
|
|||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#ifdef _LIBCPP_HAS_NO_COROUTINES
|
||||
#ifdef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
# if defined(_LIBCPP_WARNING)
|
||||
_LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
|
||||
# else
|
||||
|
@ -65,7 +65,7 @@ template <class P> struct hash<coroutine_handle<P>>;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_COROUTINES
|
||||
#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
|
||||
|
||||
|
@ -329,6 +329,6 @@ struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
|
|||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
|
||||
#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
|
||||
|
||||
#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
|
||||
|
|
|
@ -417,6 +417,19 @@ module std [system] {
|
|||
header "condition_variable"
|
||||
export *
|
||||
}
|
||||
module coroutine {
|
||||
requires coroutines
|
||||
header "coroutine"
|
||||
export compare
|
||||
export *
|
||||
|
||||
module __coroutine {
|
||||
module coroutine_handle { private header "__coroutine/coroutine_handle.h" }
|
||||
module coroutine_traits { private header "__coroutine/coroutine_traits.h" }
|
||||
module trivial_awaitables { private header "__coroutine/trivial_awaitables.h" }
|
||||
module noop_coroutine_handle { private header "__coroutine/noop_coroutine_handle.h" }
|
||||
}
|
||||
}
|
||||
module deque {
|
||||
header "deque"
|
||||
export initializer_list
|
||||
|
|
|
@ -305,7 +305,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
|||
# define __cpp_lib_constexpr_tuple 201811L
|
||||
# define __cpp_lib_constexpr_utility 201811L
|
||||
// # define __cpp_lib_constexpr_vector 201907L
|
||||
// # define __cpp_lib_coroutine 201902L
|
||||
# define __cpp_lib_coroutine 201902L
|
||||
# if _LIBCPP_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L
|
||||
# define __cpp_lib_destroying_delete 201806L
|
||||
# endif
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__coroutine/coroutine_handle.h'}}
|
||||
#include <__coroutine/coroutine_handle.h>
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__coroutine/coroutine_traits.h'}}
|
||||
#include <__coroutine/coroutine_traits.h>
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__coroutine/noop_coroutine_handle.h'}}
|
||||
#include <__coroutine/noop_coroutine_handle.h>
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__coroutine/trivial_awaitables.h'}}
|
||||
#include <__coroutine/trivial_awaitables.h>
|
|
@ -62,6 +62,9 @@
|
|||
#include <complex.h>
|
||||
#include <concepts>
|
||||
#include <condition_variable>
|
||||
#ifndef _LIBCPP_HAS_NO_CXX20_COROUTINES
|
||||
# include <coroutine>
|
||||
#endif
|
||||
#include <csetjmp>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
|
@ -205,7 +208,7 @@
|
|||
// experimental headers
|
||||
#if __cplusplus >= 201103L
|
||||
# include <experimental/algorithm>
|
||||
# if defined(__cpp_coroutines)
|
||||
# ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
# include <experimental/coroutine>
|
||||
# endif
|
||||
# include <experimental/deque>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// WARNING: This test was generated by generate_header_inclusion_tests.py
|
||||
// and should not be edited manually.
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// Test that <coroutine> includes all the other headers it's supposed to.
|
||||
|
||||
#include <coroutine>
|
||||
#include "test_macros.h"
|
||||
|
||||
#if !defined(_LIBCPP_COROUTINE)
|
||||
# error "<coroutine> was expected to define _LIBCPP_COROUTINE"
|
||||
#endif
|
||||
#if TEST_STD_VER > 17 && !defined(_LIBCPP_COMPARE)
|
||||
# error "<coroutine> should include <compare> in C++20 and later"
|
||||
#endif
|
|
@ -88,6 +88,10 @@ TEST_MACROS();
|
|||
TEST_MACROS();
|
||||
#include <condition_variable>
|
||||
TEST_MACROS();
|
||||
#ifndef _LIBCPP_HAS_NO_CXX20_COROUTINES
|
||||
# include <coroutine>
|
||||
TEST_MACROS();
|
||||
#endif
|
||||
#include <csetjmp>
|
||||
TEST_MACROS();
|
||||
#include <csignal>
|
||||
|
@ -321,7 +325,7 @@ TEST_MACROS();
|
|||
#if __cplusplus >= 201103L
|
||||
# include <experimental/algorithm>
|
||||
TEST_MACROS();
|
||||
# if defined(__cpp_coroutines)
|
||||
# ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
# include <experimental/coroutine>
|
||||
TEST_MACROS();
|
||||
# endif
|
||||
|
|
|
@ -57,6 +57,9 @@
|
|||
#include <complex.h>
|
||||
#include <concepts>
|
||||
#include <condition_variable>
|
||||
#ifndef _LIBCPP_HAS_NO_CXX20_COROUTINES
|
||||
# include <coroutine>
|
||||
#endif
|
||||
#include <csetjmp>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
|
@ -200,7 +203,7 @@
|
|||
// experimental headers
|
||||
#if __cplusplus >= 201103L
|
||||
# include <experimental/algorithm>
|
||||
# if defined(__cpp_coroutines)
|
||||
# ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
|
||||
# include <experimental/coroutine>
|
||||
# endif
|
||||
# include <experimental/deque>
|
||||
|
|
|
@ -16,19 +16,76 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "coroutine_types.h"
|
||||
|
||||
using namespace std::experimental;
|
||||
|
||||
template <typename Ty> struct generator {
|
||||
struct promise_type {
|
||||
Ty current_value;
|
||||
std::experimental::suspend_always yield_value(Ty value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
std::experimental::suspend_always initial_suspend() { return {}; }
|
||||
std::experimental::suspend_always final_suspend() noexcept { return {}; }
|
||||
generator get_return_object() { return generator{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
struct iterator {
|
||||
std::experimental::coroutine_handle<promise_type> _Coro;
|
||||
bool _Done;
|
||||
|
||||
iterator(std::experimental::coroutine_handle<promise_type> Coro, bool Done)
|
||||
: _Coro(Coro), _Done(Done) {}
|
||||
|
||||
iterator &operator++() {
|
||||
_Coro.resume();
|
||||
_Done = _Coro.done();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator const &_Right) const {
|
||||
return _Done == _Right._Done;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
|
||||
|
||||
Ty const &operator*() const { return _Coro.promise().current_value; }
|
||||
|
||||
Ty const *operator->() const { return &(operator*()); }
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
p.resume();
|
||||
return {p, p.done()};
|
||||
}
|
||||
|
||||
iterator end() { return {p, true}; }
|
||||
|
||||
generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
|
||||
|
||||
~generator() {
|
||||
if (p)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit generator(promise_type *p)
|
||||
: p(std::experimental::coroutine_handle<promise_type>::from_promise(*p)) {}
|
||||
|
||||
std::experimental::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
struct minig {
|
||||
struct promise_type {
|
||||
int current_value;
|
||||
suspend_always yield_value(int value) {
|
||||
std::experimental::suspend_always yield_value(int value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
suspend_always initial_suspend() { return {}; }
|
||||
suspend_always final_suspend() noexcept { return {}; }
|
||||
std::experimental::suspend_always initial_suspend() { return {}; }
|
||||
std::experimental::suspend_always final_suspend() noexcept { return {}; }
|
||||
minig get_return_object() { return minig{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
|
@ -49,9 +106,9 @@ struct minig {
|
|||
|
||||
private:
|
||||
explicit minig(promise_type *p)
|
||||
: p(coroutine_handle<promise_type>::from_promise(*p)) {}
|
||||
: p(std::experimental::coroutine_handle<promise_type>::from_promise(*p)) {}
|
||||
|
||||
coroutine_handle<promise_type> p;
|
||||
std::experimental::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// constexpr explicit operator bool() const noexcept
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
constexpr bool do_test() {
|
||||
static_assert(std::is_nothrow_constructible<bool, C>::value, "");
|
||||
static_assert(!std::is_convertible<C, bool>::value, "");
|
||||
{
|
||||
constexpr C c;
|
||||
static_assert(bool(c) == false, "");
|
||||
}
|
||||
{ // null case
|
||||
const C c = {};
|
||||
ASSERT_NOEXCEPT(bool(c));
|
||||
assert(c.address() == nullptr);
|
||||
assert(bool(c) == false);
|
||||
}
|
||||
{ // non-null case
|
||||
char dummy = 42;
|
||||
C c = C::from_address((void*)&dummy);
|
||||
assert(c.address() == &dummy);
|
||||
assert(bool(c) == true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test<std::coroutine_handle<>>();
|
||||
do_test<std::coroutine_handle<int>>();
|
||||
static_assert(do_test<std::coroutine_handle<>>());
|
||||
static_assert(do_test<std::coroutine_handle<int>>());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
void do_test(int *LHSVal, int *RHSVal) {
|
||||
const C LHS = C::from_address(LHSVal);
|
||||
const C RHS = C::from_address(RHSVal);
|
||||
const bool ExpectIsEqual = (LHSVal == RHSVal);
|
||||
assert((LHS == RHS) == ExpectIsEqual);
|
||||
assert((RHS == LHS) == ExpectIsEqual);
|
||||
assert((LHS != RHS) == !ExpectIsEqual);
|
||||
assert((RHS != LHS) == !ExpectIsEqual);
|
||||
{
|
||||
static_assert(noexcept(LHS == RHS), "");
|
||||
static_assert(noexcept(LHS != RHS), "");
|
||||
ASSERT_SAME_TYPE(decltype(LHS == RHS), bool);
|
||||
ASSERT_SAME_TYPE(decltype(LHS != RHS), bool);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int i;
|
||||
std::pair<int *, int *> const TestCases[] = {
|
||||
{nullptr, nullptr},
|
||||
{&i, &i},
|
||||
{nullptr, &i},
|
||||
{&i, nullptr}
|
||||
};
|
||||
for (auto& TC : TestCases) {
|
||||
do_test<std::coroutine_handle<>>(TC.first, TC.second);
|
||||
do_test<std::coroutine_handle<int>>(TC.first, TC.second);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
void do_test(int *LHSVal, int *RHSVal) {
|
||||
const C LHS = C::from_address(LHSVal);
|
||||
const C RHS = C::from_address(RHSVal);
|
||||
assert((LHS < RHS) == (LHSVal < RHSVal));
|
||||
assert((RHS < LHS) == (RHSVal < LHSVal));
|
||||
assert((LHS > RHS) == (LHSVal > RHSVal));
|
||||
assert((RHS > LHS) == (RHSVal > LHSVal));
|
||||
assert((LHS <= RHS) == (LHSVal <= RHSVal));
|
||||
assert((RHS <= LHS) == (RHSVal <= LHSVal));
|
||||
assert((LHS >= RHS) == (LHSVal >= RHSVal));
|
||||
assert((RHS >= LHS) == (RHSVal >= LHSVal));
|
||||
{
|
||||
static_assert(noexcept(LHS < RHS), "");
|
||||
static_assert(noexcept(LHS > RHS), "");
|
||||
static_assert(noexcept(LHS <= RHS), "");
|
||||
static_assert(noexcept(LHS >= RHS), "");
|
||||
ASSERT_SAME_TYPE(decltype(LHS < RHS), bool);
|
||||
ASSERT_SAME_TYPE(decltype(LHS > RHS), bool);
|
||||
ASSERT_SAME_TYPE(decltype(LHS <= RHS), bool);
|
||||
ASSERT_SAME_TYPE(decltype(LHS >= RHS), bool);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int i;
|
||||
std::pair<int *, int *> const TestCases[] = {
|
||||
{nullptr, nullptr},
|
||||
{&i, &i},
|
||||
{nullptr, &i},
|
||||
{&i, nullptr}
|
||||
};
|
||||
for (auto& TC : TestCases) {
|
||||
do_test<std::coroutine_handle<>>(TC.first, TC.second);
|
||||
do_test<std::coroutine_handle<int>>(TC.first, TC.second);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// bool done() const
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Promise>
|
||||
void do_test(std::coroutine_handle<Promise> const& H) {
|
||||
// FIXME Add a runtime test
|
||||
{
|
||||
ASSERT_SAME_TYPE(decltype(H.done()), bool);
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(H.done());
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test(std::coroutine_handle<>{});
|
||||
do_test(std::coroutine_handle<int>{});
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// coroutine_handle& operator=(nullptr_t) noexcept
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
void do_test() {
|
||||
int dummy = 42;
|
||||
void* dummy_h = &dummy;
|
||||
{
|
||||
static_assert(std::is_nothrow_assignable<C&, std::nullptr_t>::value, "");
|
||||
static_assert(!std::is_assignable<C&, void*>::value, "");
|
||||
}
|
||||
{
|
||||
C c = C::from_address(dummy_h);
|
||||
assert(c.address() == &dummy);
|
||||
c = nullptr;
|
||||
assert(c.address() == nullptr);
|
||||
c = nullptr;
|
||||
assert(c.address() == nullptr);
|
||||
}
|
||||
{
|
||||
C c;
|
||||
C& cr = (c = nullptr);
|
||||
assert(&c == &cr);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test<std::coroutine_handle<>>();
|
||||
do_test<std::coroutine_handle<int>>();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// constexpr coroutine_handle() noexcept
|
||||
// constexpr coroutine_handle(nullptr_t) noexcept
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
constexpr bool do_test() {
|
||||
static_assert(std::is_nothrow_constructible<C>::value, "");
|
||||
static_assert(std::is_nothrow_constructible<C, std::nullptr_t>::value, "");
|
||||
{
|
||||
C c;
|
||||
assert(c.address() == nullptr);
|
||||
}
|
||||
{
|
||||
C c = C(nullptr);
|
||||
assert(c.address() == nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test<std::coroutine_handle<>>();
|
||||
do_test<std::coroutine_handle<int>>();
|
||||
static_assert(do_test<std::coroutine_handle<>>());
|
||||
static_assert(do_test<std::coroutine_handle<int>>());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// constexpr void* address() const noexcept
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
constexpr bool do_test() {
|
||||
{
|
||||
constexpr C c; ((void)c);
|
||||
static_assert(c.address() == nullptr, "");
|
||||
}
|
||||
{
|
||||
const C c = {}; ((void)c);
|
||||
ASSERT_NOEXCEPT(c.address());
|
||||
ASSERT_SAME_TYPE(decltype(c.address()), void*);
|
||||
assert(c.address() == nullptr);
|
||||
}
|
||||
{
|
||||
char dummy = 42;
|
||||
C c = C::from_address((void*)&dummy);
|
||||
assert(c.address() == &dummy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test<std::coroutine_handle<>>();
|
||||
do_test<std::coroutine_handle<int>>();
|
||||
static_assert(do_test<std::coroutine_handle<>>());
|
||||
static_assert(do_test<std::coroutine_handle<int>>());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// static coroutine_handle from_address(void*) noexcept
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
void do_test() {
|
||||
{
|
||||
C c = C::from_address(nullptr);
|
||||
static_assert(noexcept(C::from_address(nullptr)), "");
|
||||
static_assert(std::is_same<decltype(C::from_address(nullptr)), C>::value, "");
|
||||
assert(c.address() == nullptr);
|
||||
}
|
||||
{
|
||||
char dummy = 42;
|
||||
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();
|
||||
std::coroutine_handle<> c2 = std::coroutine_handle<>::from_address(p);
|
||||
assert(c2 == c);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test<std::coroutine_handle<>>();
|
||||
do_test<std::coroutine_handle<int>>();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// namespace std {
|
||||
// template <class P> struct hash<coroutine_handle<P>>;
|
||||
// }
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class C>
|
||||
void do_test(int *LHSVal, int *RHSVal) {
|
||||
const size_t ExpectLHS = std::hash<void*>{}((LHSVal));
|
||||
const size_t ExpectRHS = std::hash<void*>{}((RHSVal));
|
||||
const C LHS = C::from_address((LHSVal));
|
||||
const C RHS = C::from_address((RHSVal));
|
||||
const std::hash<C> h;
|
||||
|
||||
LIBCPP_ASSERT(h(LHS) == ExpectLHS);
|
||||
LIBCPP_ASSERT(h(RHS) == ExpectRHS);
|
||||
assert((h(LHS) == h(RHS)) == (LHSVal == RHSVal));
|
||||
{
|
||||
ASSERT_SAME_TYPE(decltype(h(LHS)), size_t);
|
||||
ASSERT_NOEXCEPT(std::hash<C>{}(LHS));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int i, j;
|
||||
std::pair<int *, int *> const TestCases[] = {
|
||||
{nullptr, nullptr},
|
||||
{nullptr, &i},
|
||||
{&i, &i},
|
||||
{&i, &j}
|
||||
};
|
||||
for (auto& TC : TestCases) {
|
||||
do_test<std::coroutine_handle<>>(TC.first, TC.second);
|
||||
do_test<std::coroutine_handle<int>>(TC.first, TC.second);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: ubsan
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
// struct noop_coroutine_promise;
|
||||
// using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
|
||||
// noop_coroutine_handle noop_coroutine() noexcept;
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
#if __has_builtin(__builtin_coro_noop)
|
||||
|
||||
static_assert(std::is_same<std::coroutine_handle<std::noop_coroutine_promise>, std::noop_coroutine_handle>::value, "");
|
||||
static_assert(std::is_same<decltype(std::noop_coroutine()), std::noop_coroutine_handle>::value, "");
|
||||
|
||||
// template <> struct coroutine_handle<noop_coroutine_promise> : coroutine_handle<>
|
||||
// {
|
||||
// // [coroutine.handle.noop.observers], observers
|
||||
// constexpr explicit operator bool() const noexcept;
|
||||
// constexpr bool done() const noexcept;
|
||||
|
||||
// // [coroutine.handle.noop.resumption], resumption
|
||||
// constexpr void operator()() const noexcept;
|
||||
// constexpr void resume() const noexcept;
|
||||
// constexpr void destroy() const noexcept;
|
||||
|
||||
// // [coroutine.handle.noop.promise], promise access
|
||||
// noop_coroutine_promise& promise() const noexcept;
|
||||
|
||||
// // [coroutine.handle.noop.address], address
|
||||
// constexpr void* address() const noexcept;
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
auto h = std::noop_coroutine();
|
||||
std::coroutine_handle<> base = h;
|
||||
|
||||
assert(h);
|
||||
assert(base);
|
||||
|
||||
assert(!h.done());
|
||||
assert(!base.done());
|
||||
|
||||
h.resume();
|
||||
h.destroy();
|
||||
h();
|
||||
static_assert(h.done() == false, "");
|
||||
static_assert(h, "");
|
||||
|
||||
h.promise();
|
||||
assert(h.address() == base.address());
|
||||
assert(h==base);
|
||||
assert(h.address() != nullptr);
|
||||
assert(std::coroutine_handle<>::from_address(h.address()) == base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int, char**) { return 0; }
|
||||
|
||||
#endif // __has_builtin(__builtin_coro_noop)
|
|
@ -0,0 +1,83 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise>
|
||||
// struct coroutine_handle<Promise>;
|
||||
|
||||
// Promise& promise() const
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct MyCoro {
|
||||
struct promise_type {
|
||||
void unhandled_exception() {}
|
||||
void return_void() {}
|
||||
std::suspend_never initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
MyCoro get_return_object() {
|
||||
do_runtime_test();
|
||||
return {};
|
||||
}
|
||||
void do_runtime_test() {
|
||||
// Test that a coroutine_handle<const T> can be created from a const
|
||||
// promise_type and that it represents the same coroutine as
|
||||
// coroutine_handle<T>
|
||||
using CH = std::coroutine_handle<promise_type>;
|
||||
using CCH = std::coroutine_handle<const promise_type>;
|
||||
const auto &cthis = *this;
|
||||
CH h = CH::from_promise(*this);
|
||||
CCH h2 = CCH::from_promise(*this);
|
||||
CCH h3 = CCH::from_promise(cthis);
|
||||
assert(&h.promise() == this);
|
||||
assert(&h2.promise() == this);
|
||||
assert(&h3.promise() == this);
|
||||
assert(h.address() == h2.address());
|
||||
assert(h2.address() == h3.address());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
MyCoro do_runtime_test() {
|
||||
co_await std::suspend_never{};
|
||||
}
|
||||
|
||||
template <class Promise>
|
||||
void do_test(std::coroutine_handle<Promise>&& H) {
|
||||
|
||||
// FIXME Add a runtime test
|
||||
{
|
||||
ASSERT_SAME_TYPE(decltype(H.promise()), Promise&);
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(H.promise());
|
||||
}
|
||||
{
|
||||
auto const& CH = H;
|
||||
ASSERT_SAME_TYPE(decltype(CH.promise()), Promise&);
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(CH.promise());
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test(std::coroutine_handle<int>{});
|
||||
do_test(std::coroutine_handle<const int>{});
|
||||
do_runtime_test();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// void destroy() const
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class H>
|
||||
auto has_destroy_imp(H&& h, int) -> decltype(h.destroy(), std::true_type{});
|
||||
template <class H>
|
||||
auto has_destroy_imp(H&&, long) -> std::false_type;
|
||||
|
||||
template <class H>
|
||||
constexpr bool has_destroy() {
|
||||
return decltype(has_destroy_imp(std::declval<H>(), 0))::value;
|
||||
}
|
||||
|
||||
template <class Promise>
|
||||
void do_test(std::coroutine_handle<Promise>&& H) {
|
||||
using HType = std::coroutine_handle<Promise>;
|
||||
// FIXME Add a runtime test
|
||||
{
|
||||
ASSERT_SAME_TYPE(decltype(H.destroy()), void);
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(H.destroy());
|
||||
static_assert(has_destroy<HType&>(), "");
|
||||
static_assert(has_destroy<HType&&>(), "");
|
||||
}
|
||||
{
|
||||
static_assert(has_destroy<HType const&>(), "");
|
||||
static_assert(has_destroy<HType const&&>(), "");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test(std::coroutine_handle<>{});
|
||||
do_test(std::coroutine_handle<int>{});
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// template <class Promise = void>
|
||||
// struct coroutine_handle;
|
||||
|
||||
// void operator()() const
|
||||
// void resume() const
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class H>
|
||||
auto has_resume_imp(H&& h, int) -> decltype(h.resume(), std::true_type{});
|
||||
template <class H>
|
||||
auto has_resume_imp(H&&, long) -> std::false_type;
|
||||
|
||||
template <class H>
|
||||
constexpr bool has_resume() {
|
||||
return decltype(has_resume_imp(std::declval<H>(), 0))::value;
|
||||
}
|
||||
|
||||
|
||||
template <class H>
|
||||
auto has_call_operator_imp(H&& h, int) -> decltype(h(), std::true_type{});
|
||||
template <class H>
|
||||
auto has_call_operator_imp(H&&, long) -> std::false_type;
|
||||
|
||||
template <class H>
|
||||
constexpr bool has_call_operator() {
|
||||
return decltype(has_call_operator_imp(std::declval<H>(), 0))::value;
|
||||
}
|
||||
|
||||
template <class Promise>
|
||||
void do_test(std::coroutine_handle<Promise>&& H) {
|
||||
using HType = std::coroutine_handle<Promise>;
|
||||
// FIXME Add a runtime test
|
||||
{
|
||||
ASSERT_SAME_TYPE(decltype(H.resume()), void);
|
||||
ASSERT_SAME_TYPE(decltype(H()), void);
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(H.resume());
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(H());
|
||||
static_assert(has_resume<HType&>(), "");
|
||||
static_assert(has_resume<HType&&>(), "");
|
||||
static_assert(has_call_operator<HType&>(), "");
|
||||
static_assert(has_call_operator<HType&&>(), "");
|
||||
}
|
||||
{
|
||||
static_assert(has_resume<HType const&>(), "");
|
||||
static_assert(has_resume<HType const&&>(), "");
|
||||
static_assert(has_call_operator<HType const&>(), "");
|
||||
static_assert(has_call_operator<HType const&&>(), "");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
do_test(std::coroutine_handle<>{});
|
||||
do_test(std::coroutine_handle<int>{});
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct A {
|
||||
using promise_type = A*;
|
||||
};
|
||||
|
||||
struct B {};
|
||||
struct C {};
|
||||
|
||||
template <>
|
||||
struct std::coroutine_traits<A, int> {
|
||||
using promise_type = int*;
|
||||
};
|
||||
template <class ...Args>
|
||||
struct std::coroutine_traits<B, Args...> {
|
||||
using promise_type = B*;
|
||||
};
|
||||
template <>
|
||||
struct std::coroutine_traits<C> {
|
||||
using promise_type = void;
|
||||
};
|
||||
|
||||
template <class Expect, class T, class ...Args>
|
||||
void check_type() {
|
||||
using P = typename std::coroutine_traits<T, Args...>::promise_type ;
|
||||
static_assert(std::is_same<P, Expect>::value, "");
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
check_type<A*, A>();
|
||||
check_type<int*, A, int>();
|
||||
check_type<B*, B>();
|
||||
check_type<void, C>();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T, class = typename T::promise_type>
|
||||
constexpr bool has_promise_type(int) { return true; }
|
||||
template <class>
|
||||
constexpr bool has_promise_type(long) { return false; }
|
||||
template <class T>
|
||||
constexpr bool has_promise_type() { return has_promise_type<T>(0); }
|
||||
|
||||
struct A {
|
||||
using promise_type = A*;
|
||||
};
|
||||
|
||||
struct B {};
|
||||
struct C {};
|
||||
struct D {
|
||||
private:
|
||||
using promise_type = void;
|
||||
};
|
||||
struct E {};
|
||||
|
||||
template <>
|
||||
struct std::coroutine_traits<A, int> {
|
||||
using promise_type = int*;
|
||||
};
|
||||
template <class ...Args>
|
||||
struct std::coroutine_traits<B, Args...> {
|
||||
using promise_type = B*;
|
||||
};
|
||||
template <>
|
||||
struct std::coroutine_traits<C> {
|
||||
using promise_type = void;
|
||||
};
|
||||
|
||||
template <class Expect, class T, class ...Args>
|
||||
void check_type() {
|
||||
using Traits = std::coroutine_traits<T, Args...>;
|
||||
static_assert(has_promise_type<Traits>(), "");
|
||||
static_assert(std::is_same<typename Traits::promise_type, Expect>::value, "");
|
||||
}
|
||||
|
||||
template <class T, class ...Args>
|
||||
void check_no_type() {
|
||||
using Traits = std::coroutine_traits<T, Args...>;
|
||||
static_assert(!has_promise_type<Traits>(), "");
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
check_type<A*, A>();
|
||||
check_type<int*, A, int>();
|
||||
check_type<B*, B>();
|
||||
check_type<void, C>();
|
||||
}
|
||||
{
|
||||
check_no_type<D>();
|
||||
check_no_type<E>();
|
||||
check_no_type<C, int>();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
TEST_SAFE_STATIC std::suspend_always safe_sa;
|
||||
|
||||
constexpr bool check_suspend_constexpr() {
|
||||
std::suspend_always s{};
|
||||
const std::suspend_always scopy(s);
|
||||
std::suspend_always smove(std::move(s));
|
||||
s = scopy;
|
||||
s = std::move(smove);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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**)
|
||||
{
|
||||
std::coroutine_handle<> h{};
|
||||
std::suspend_always s{};
|
||||
std::suspend_always const& cs = s;
|
||||
{
|
||||
ASSERT_NOEXCEPT(s.await_ready());
|
||||
static_assert(std::is_same<decltype(s.await_ready()), bool>::value, "");
|
||||
assert(s.await_ready() == false);
|
||||
assert(cs.await_ready() == false);
|
||||
}
|
||||
{
|
||||
ASSERT_NOEXCEPT(s.await_suspend(h));
|
||||
static_assert(std::is_same<decltype(s.await_suspend(h)), void>::value, "");
|
||||
s.await_suspend(h);
|
||||
cs.await_suspend(h);
|
||||
}
|
||||
{
|
||||
ASSERT_NOEXCEPT(s.await_resume());
|
||||
static_assert(std::is_same<decltype(s.await_resume()), void>::value, "");
|
||||
s.await_resume();
|
||||
cs.await_resume();
|
||||
}
|
||||
{
|
||||
static_assert(std::is_nothrow_default_constructible<std::suspend_always>::value, "");
|
||||
static_assert(std::is_nothrow_copy_constructible<std::suspend_always>::value, "");
|
||||
static_assert(std::is_nothrow_move_constructible<std::suspend_always>::value, "");
|
||||
static_assert(std::is_nothrow_copy_assignable<std::suspend_always>::value, "");
|
||||
static_assert(std::is_nothrow_move_assignable<std::suspend_always>::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::suspend_always>::value, "");
|
||||
static_assert(check_suspend_constexpr(), "");
|
||||
}
|
||||
{
|
||||
static_assert(test_trivial_awaitable_constexpr<std::suspend_always>(false));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// Test that the type 'std::suspend_never' is in the correct namespace
|
||||
|
||||
TEST_SAFE_STATIC std::suspend_never safe_sn;
|
||||
constexpr std::suspend_never constexpr_sn;
|
||||
|
||||
constexpr bool check_suspend_constexpr() {
|
||||
std::suspend_never s{};
|
||||
const std::suspend_never scopy(s); ((void)scopy);
|
||||
std::suspend_never smove(std::move(s)); ((void)smove);
|
||||
s = scopy;
|
||||
s = std::move(smove);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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 = std::coroutine_handle<>;
|
||||
using S = std::suspend_never;
|
||||
H h{};
|
||||
S s{};
|
||||
S const& cs = s;
|
||||
{
|
||||
LIBCPP_STATIC_ASSERT(noexcept(s.await_ready()), "");
|
||||
static_assert(std::is_same<decltype(s.await_ready()), bool>::value, "");
|
||||
assert(s.await_ready() == true);
|
||||
assert(cs.await_ready() == true);
|
||||
}
|
||||
{
|
||||
LIBCPP_STATIC_ASSERT(noexcept(s.await_suspend(h)), "");
|
||||
static_assert(std::is_same<decltype(s.await_suspend(h)), void>::value, "");
|
||||
s.await_suspend(h);
|
||||
cs.await_suspend(h);
|
||||
}
|
||||
{
|
||||
LIBCPP_STATIC_ASSERT(noexcept(s.await_resume()), "");
|
||||
static_assert(std::is_same<decltype(s.await_resume()), void>::value, "");
|
||||
s.await_resume();
|
||||
cs.await_resume();
|
||||
}
|
||||
{
|
||||
static_assert(std::is_nothrow_default_constructible<std::suspend_never>::value, "");
|
||||
static_assert(std::is_nothrow_copy_constructible<std::suspend_never>::value, "");
|
||||
static_assert(std::is_nothrow_move_constructible<std::suspend_never>::value, "");
|
||||
static_assert(std::is_nothrow_copy_assignable<std::suspend_never>::value, "");
|
||||
static_assert(std::is_nothrow_move_assignable<std::suspend_never>::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::suspend_never>::value, "");
|
||||
static_assert(check_suspend_constexpr(), "");
|
||||
}
|
||||
{
|
||||
static_assert(test_trivial_awaitable_constexpr<std::suspend_never>(true));
|
||||
}
|
||||
{
|
||||
// suppress unused warnings for the global constexpr test variable
|
||||
((void)constexpr_sn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct coro_t {
|
||||
struct promise_type {
|
||||
coro_t get_return_object() {
|
||||
std::coroutine_handle<promise_type>{};
|
||||
return {};
|
||||
}
|
||||
std::suspend_never initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
void return_void() {}
|
||||
static void unhandled_exception() {}
|
||||
};
|
||||
};
|
||||
|
||||
struct B {
|
||||
~B() {}
|
||||
bool await_ready() { return true; }
|
||||
B await_resume() { return {}; }
|
||||
template <typename F> void await_suspend(F) {}
|
||||
};
|
||||
|
||||
|
||||
struct A {
|
||||
~A() {}
|
||||
bool await_ready() { return true; }
|
||||
int await_resume() { return 42; }
|
||||
template <typename F> void await_suspend(F) {}
|
||||
};
|
||||
|
||||
int last_value = -1;
|
||||
void set_value(int x) {
|
||||
last_value = x;
|
||||
}
|
||||
|
||||
coro_t f(int n) {
|
||||
if (n == 0) {
|
||||
set_value(0);
|
||||
co_return;
|
||||
}
|
||||
int val = co_await A{};
|
||||
((void)val);
|
||||
set_value(42);
|
||||
}
|
||||
|
||||
coro_t g() { B val = co_await B{}; }
|
||||
|
||||
int main(int, char**) {
|
||||
last_value = -1;
|
||||
f(0);
|
||||
assert(last_value == 0);
|
||||
f(1);
|
||||
assert(last_value == 42);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// See https://llvm.org/PR33271
|
||||
// UNSUPPORTED: ubsan
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct coro_t {
|
||||
struct promise_type {
|
||||
coro_t get_return_object() {
|
||||
return std::coroutine_handle<promise_type>::from_promise(*this);
|
||||
}
|
||||
std::suspend_never initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
coro_t(std::coroutine_handle<promise_type> hh) : h(hh) {}
|
||||
std::coroutine_handle<promise_type> h;
|
||||
};
|
||||
|
||||
struct NoSuspend {
|
||||
bool await_ready() { return false; }
|
||||
void await_resume() {}
|
||||
template <typename F> bool await_suspend(F) { return false; }
|
||||
};
|
||||
|
||||
struct DoSuspend {
|
||||
bool await_ready() { return false; }
|
||||
void await_resume() {}
|
||||
template <typename F> bool await_suspend(F) { return true; }
|
||||
};
|
||||
|
||||
bool f_started, f_resumed = false;
|
||||
coro_t f() {
|
||||
f_started = true;
|
||||
co_await DoSuspend{};
|
||||
f_resumed = true;
|
||||
}
|
||||
|
||||
bool g_started, g_resumed = false;
|
||||
coro_t g() {
|
||||
g_started = true;
|
||||
co_await NoSuspend{};
|
||||
g_resumed = true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
assert(!f_started && !f_resumed && !g_started && !g_resumed);
|
||||
auto fret = f();
|
||||
assert(f_started && !f_resumed);
|
||||
fret.h.destroy();
|
||||
assert(f_started && !f_resumed);
|
||||
g();
|
||||
assert(g_started && g_resumed);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct error_tag { };
|
||||
|
||||
template <typename T, typename Error = int>
|
||||
struct expected {
|
||||
|
||||
struct Data {
|
||||
Data() : val(), error() { }
|
||||
Data(T v, Error e) : val(v), error(e) { }
|
||||
T val;
|
||||
Error error;
|
||||
};
|
||||
std::shared_ptr<Data> data;
|
||||
|
||||
expected(T val) : data(std::make_shared<Data>(val, Error())) {}
|
||||
expected(error_tag, Error error) : data(std::make_shared<Data>(T(), error)) {}
|
||||
expected(std::shared_ptr<Data> p) : data(p) {}
|
||||
|
||||
struct promise_type {
|
||||
std::shared_ptr<Data> data;
|
||||
expected get_return_object() { data = std::make_shared<Data>(); return {data}; }
|
||||
std::suspend_never initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
void return_value(T v) { data->val = v; data->error = {}; }
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
bool await_ready() { return !data->error; }
|
||||
T await_resume() { return data->val; }
|
||||
void await_suspend(std::coroutine_handle<promise_type> h) {
|
||||
h.promise().data->error = data->error;
|
||||
h.destroy();
|
||||
}
|
||||
|
||||
T const& value() { return data->val; }
|
||||
Error const& error() { return data->error; }
|
||||
};
|
||||
|
||||
expected<int> g() { return {0}; }
|
||||
expected<int> h() { return {error_tag{}, 42}; }
|
||||
|
||||
extern "C" void print(int);
|
||||
|
||||
bool f1_started, f1_resumed = false;
|
||||
expected<int> f1() {
|
||||
f1_started = true;
|
||||
(void)(co_await g());
|
||||
f1_resumed = true;
|
||||
co_return 100;
|
||||
}
|
||||
|
||||
bool f2_started, f2_resumed = false;
|
||||
expected<int> f2() {
|
||||
f2_started = true;
|
||||
(void)(co_await h());
|
||||
f2_resumed = true;
|
||||
co_return 200;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
auto c1 = f1();
|
||||
assert(f1_started && f1_resumed);
|
||||
assert(c1.value() == 100);
|
||||
assert(c1.error() == 0);
|
||||
|
||||
auto c2 = f2();
|
||||
assert(f2_started && !f2_resumed);
|
||||
assert(c2.value() == 0);
|
||||
assert(c2.error() == 42);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int alive = 0;
|
||||
int ctor_called = 0;
|
||||
int dtor_called = 0;
|
||||
void reset() {
|
||||
assert(alive == 0);
|
||||
alive = 0;
|
||||
ctor_called = 0;
|
||||
dtor_called = 0;
|
||||
}
|
||||
struct Noisy {
|
||||
Noisy() { ++alive; ++ctor_called; }
|
||||
~Noisy() { --alive; ++dtor_called; }
|
||||
Noisy(Noisy const&) = delete;
|
||||
};
|
||||
|
||||
struct Bug {
|
||||
bool await_ready() { return true; }
|
||||
void await_suspend(std::coroutine_handle<>) {}
|
||||
Noisy await_resume() { return {}; }
|
||||
};
|
||||
struct coro2 {
|
||||
struct promise_type {
|
||||
std::suspend_never initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
coro2 get_return_object() { return {}; }
|
||||
void return_void() {}
|
||||
Bug yield_value(int) { return {}; }
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
};
|
||||
|
||||
// Checks that destructors are correctly invoked for the object returned by
|
||||
// coawait.
|
||||
coro2 a() {
|
||||
reset();
|
||||
{
|
||||
auto x = co_await Bug{};
|
||||
assert(alive == 1);
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 0);
|
||||
((void)x);
|
||||
}
|
||||
assert(alive == 0);
|
||||
assert(dtor_called == 1);
|
||||
}
|
||||
|
||||
coro2 b() {
|
||||
reset();
|
||||
{
|
||||
co_await Bug{};
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 1);
|
||||
assert(alive == 0);
|
||||
}
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 1);
|
||||
assert(alive == 0);
|
||||
|
||||
}
|
||||
|
||||
coro2 c() {
|
||||
reset();
|
||||
{
|
||||
auto x = co_yield 42;
|
||||
assert(alive == 1);
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 0);
|
||||
}
|
||||
assert(alive == 0);
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 1);
|
||||
}
|
||||
|
||||
coro2 d() {
|
||||
reset();
|
||||
{
|
||||
co_yield 42;
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 1);
|
||||
assert(alive == 0);
|
||||
}
|
||||
assert(alive == 0);
|
||||
assert(ctor_called == 1);
|
||||
assert(dtor_called == 1);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
a();
|
||||
b();
|
||||
c();
|
||||
d();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
// See https://llvm.org/PR33271
|
||||
// UNSUPPORTED: ubsan
|
||||
|
||||
#include <coroutine>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename Ty> struct generator {
|
||||
struct promise_type {
|
||||
Ty current_value;
|
||||
std::suspend_always yield_value(Ty value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
std::suspend_always initial_suspend() { return {}; }
|
||||
std::suspend_always final_suspend() noexcept { return {}; }
|
||||
generator get_return_object() { return generator{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
struct iterator {
|
||||
std::coroutine_handle<promise_type> Coro_;
|
||||
bool Done_;
|
||||
|
||||
iterator(std::coroutine_handle<promise_type> Coro, bool Done)
|
||||
: Coro_(Coro), Done_(Done) {}
|
||||
|
||||
iterator &operator++() {
|
||||
Coro_.resume();
|
||||
Done_ = Coro_.done();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator const &_Right) const {
|
||||
return Done_ == _Right.Done_;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
|
||||
|
||||
Ty const &operator*() const { return Coro_.promise().current_value; }
|
||||
|
||||
Ty const *operator->() const { return &(operator*()); }
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
p.resume();
|
||||
return {p, p.done()};
|
||||
}
|
||||
|
||||
iterator end() { return {p, true}; }
|
||||
|
||||
generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
|
||||
|
||||
~generator() {
|
||||
if (p)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit generator(promise_type *promise)
|
||||
: p(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
|
||||
|
||||
std::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
struct minig {
|
||||
struct promise_type {
|
||||
int current_value;
|
||||
std::suspend_always yield_value(int value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
std::suspend_always initial_suspend() { return {}; }
|
||||
std::suspend_always final_suspend() noexcept { return {}; }
|
||||
minig get_return_object() { return minig{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
bool move_next() {
|
||||
p.resume();
|
||||
return !p.done();
|
||||
}
|
||||
int current_value() { return p.promise().current_value; }
|
||||
|
||||
minig(minig &&rhs) : p(rhs.p) { rhs.p = nullptr; }
|
||||
|
||||
~minig() {
|
||||
if (p)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit minig(promise_type *promise)
|
||||
: p(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
|
||||
|
||||
std::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
|
||||
minig mini_count(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
co_yield i;
|
||||
}
|
||||
}
|
||||
|
||||
generator<int> count(int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
co_yield i;
|
||||
}
|
||||
|
||||
generator<int> range(int from, int n) {
|
||||
for (int i = from; i < n; ++i)
|
||||
co_yield i;
|
||||
}
|
||||
|
||||
void test_count() {
|
||||
const std::vector<int> expect = {0, 1, 2, 3, 4};
|
||||
std::vector<int> got;
|
||||
for (auto x : count(5))
|
||||
got.push_back(x);
|
||||
assert(expect == got);
|
||||
}
|
||||
|
||||
void test_range() {
|
||||
int sum = 0;
|
||||
for (auto v: range(1, 20))
|
||||
sum += v;
|
||||
assert(sum == 190);
|
||||
}
|
||||
|
||||
void test_mini_generator() {
|
||||
int sum = 0;
|
||||
auto g = mini_count(5);
|
||||
while (g.move_next()) {
|
||||
sum += g.current_value();
|
||||
}
|
||||
assert(sum == 10);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test_count();
|
||||
test_range();
|
||||
test_mini_generator();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <cassert>
|
||||
#include <coroutine>
|
||||
#include <memory>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
bool cancel = false;
|
||||
|
||||
struct goroutine
|
||||
{
|
||||
static int const N = 10;
|
||||
static int count;
|
||||
static std::coroutine_handle<> stack[N];
|
||||
|
||||
static void schedule(std::coroutine_handle<>& rh)
|
||||
{
|
||||
assert(count < N);
|
||||
stack[count++] = rh;
|
||||
rh = nullptr;
|
||||
}
|
||||
|
||||
~goroutine() {}
|
||||
|
||||
static void run_one()
|
||||
{
|
||||
assert(count > 0);
|
||||
stack[--count]();
|
||||
}
|
||||
|
||||
struct promise_type
|
||||
{
|
||||
std::suspend_never initial_suspend() {
|
||||
return {};
|
||||
}
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
void return_void() {}
|
||||
goroutine get_return_object() {
|
||||
return{};
|
||||
}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
};
|
||||
int goroutine::count;
|
||||
std::coroutine_handle<> goroutine::stack[N];
|
||||
|
||||
std::coroutine_handle<goroutine::promise_type> workaround;
|
||||
|
||||
class channel;
|
||||
|
||||
struct push_awaiter {
|
||||
channel* ch;
|
||||
bool await_ready() {return false; }
|
||||
void await_suspend(std::coroutine_handle<> rh);
|
||||
void await_resume() {}
|
||||
};
|
||||
|
||||
struct pull_awaiter {
|
||||
channel * ch;
|
||||
|
||||
bool await_ready();
|
||||
void await_suspend(std::coroutine_handle<> rh);
|
||||
int await_resume();
|
||||
};
|
||||
|
||||
class channel
|
||||
{
|
||||
using T = int;
|
||||
|
||||
friend struct push_awaiter;
|
||||
friend struct pull_awaiter;
|
||||
|
||||
T const* pvalue = nullptr;
|
||||
std::coroutine_handle<> reader = nullptr;
|
||||
std::coroutine_handle<> writer = nullptr;
|
||||
public:
|
||||
push_awaiter push(T const& value)
|
||||
{
|
||||
assert(pvalue == nullptr);
|
||||
assert(!writer);
|
||||
pvalue = &value;
|
||||
|
||||
return { this };
|
||||
}
|
||||
|
||||
pull_awaiter pull()
|
||||
{
|
||||
assert(!reader);
|
||||
|
||||
return { this };
|
||||
}
|
||||
|
||||
void sync_push(T const& value)
|
||||
{
|
||||
assert(!pvalue);
|
||||
pvalue = &value;
|
||||
assert(reader);
|
||||
reader();
|
||||
assert(!pvalue);
|
||||
reader = nullptr;
|
||||
}
|
||||
|
||||
auto sync_pull()
|
||||
{
|
||||
while (!pvalue) goroutine::run_one();
|
||||
auto result = *pvalue;
|
||||
pvalue = nullptr;
|
||||
if (writer)
|
||||
{
|
||||
auto wr = writer;
|
||||
writer = nullptr;
|
||||
wr();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
void push_awaiter::await_suspend(std::coroutine_handle<> rh)
|
||||
{
|
||||
ch->writer = rh;
|
||||
if (ch->reader) goroutine::schedule(ch->reader);
|
||||
}
|
||||
|
||||
|
||||
bool pull_awaiter::await_ready() {
|
||||
return !!ch->writer;
|
||||
}
|
||||
void pull_awaiter::await_suspend(std::coroutine_handle<> rh) {
|
||||
ch->reader = rh;
|
||||
}
|
||||
int pull_awaiter::await_resume() {
|
||||
auto result = *ch->pvalue;
|
||||
ch->pvalue = nullptr;
|
||||
if (ch->writer) {
|
||||
//goroutine::schedule(ch->writer);
|
||||
auto wr = ch->writer;
|
||||
ch->writer = nullptr;
|
||||
wr();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
goroutine pusher(channel& left, channel& right)
|
||||
{
|
||||
for (;;) {
|
||||
auto val = co_await left.pull();
|
||||
co_await right.push(val + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const int N = 100;
|
||||
channel c[N + 1];
|
||||
|
||||
int main(int, char**) {
|
||||
for (int i = 0; i < N; ++i)
|
||||
pusher(c[i], c[i + 1]);
|
||||
|
||||
c[0].sync_push(0);
|
||||
int result = c[N].sync_pull();
|
||||
|
||||
assert(result == 100);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// This file tests, multishot, movable std::function like thing using coroutine
|
||||
// for compile-time type erasure and unerasure.
|
||||
template <typename R> struct func {
|
||||
struct Input {R a, b;};
|
||||
|
||||
struct promise_type {
|
||||
Input* I;
|
||||
R result;
|
||||
func get_return_object() { return {this}; }
|
||||
std::suspend_always initial_suspend() { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
void return_void() {}
|
||||
template <typename F>
|
||||
std::suspend_always yield_value(F&& f) {
|
||||
result = f(I->a, I->b);
|
||||
return {};
|
||||
}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
R operator()(Input I) {
|
||||
h.promise().I = &I;
|
||||
h.resume();
|
||||
R result = h.promise().result;
|
||||
return result;
|
||||
};
|
||||
|
||||
func() {}
|
||||
func(func &&rhs) : h(rhs.h) { rhs.h = nullptr; }
|
||||
func(func const &) = delete;
|
||||
|
||||
func &operator=(func &&rhs) {
|
||||
if (this != &rhs) {
|
||||
if (h)
|
||||
h.destroy();
|
||||
h = rhs.h;
|
||||
rhs.h = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename F> static func Create(F f) {
|
||||
for (;;) {
|
||||
co_yield f;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F> func(F f) : func(Create(f)) {}
|
||||
|
||||
~func() {
|
||||
if (h)
|
||||
h.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
func(promise_type *promise)
|
||||
: h(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
|
||||
std::coroutine_handle<promise_type> h;
|
||||
};
|
||||
|
||||
int Do(int acc, int n, func<int> f) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
acc = f({acc, i});
|
||||
return acc;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
int result = Do(1, 10, [](int a, int b) {return a + b;});
|
||||
assert(result == 46);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-coroutines
|
||||
|
||||
#include <coroutine>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// This file tests, one shot, movable std::function like thing using coroutine
|
||||
// for compile-time type erasure and unerasure.
|
||||
|
||||
template <typename R> struct func {
|
||||
struct promise_type {
|
||||
R result;
|
||||
func get_return_object() { return {this}; }
|
||||
std::suspend_always initial_suspend() { return {}; }
|
||||
std::suspend_always final_suspend() noexcept { return {}; }
|
||||
void return_value(R v) { result = v; }
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
R operator()() {
|
||||
h.resume();
|
||||
R result = h.promise().result;
|
||||
h.destroy();
|
||||
h = nullptr;
|
||||
return result;
|
||||
};
|
||||
|
||||
func() {}
|
||||
func(func &&rhs) : h(rhs.h) { rhs.h = nullptr; }
|
||||
func(func const &) = delete;
|
||||
|
||||
func &operator=(func &&rhs) {
|
||||
if (this != &rhs) {
|
||||
if (h)
|
||||
h.destroy();
|
||||
h = rhs.h;
|
||||
rhs.h = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename F> static func Create(F f) { co_return f(); }
|
||||
|
||||
template <typename F> func(F f) : func(Create(f)) {}
|
||||
|
||||
~func() {
|
||||
if (h)
|
||||
h.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
func(promise_type *promise)
|
||||
: h(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
|
||||
std::coroutine_handle<promise_type> h;
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
func<int> f = func<int>::Create([]() { return 44; });
|
||||
assert(f() == 44);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// WARNING: This test was generated by generate_feature_test_macro_components.py
|
||||
// and should not be edited manually.
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
// <coroutine>
|
||||
|
||||
// Test the feature test macros defined by <coroutine>
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_coroutine 201902L [C++20]
|
||||
*/
|
||||
|
||||
#include <coroutine>
|
||||
#include "test_macros.h"
|
||||
|
||||
#if TEST_STD_VER < 14
|
||||
|
||||
# ifdef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should not be defined before c++20"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER == 14
|
||||
|
||||
# ifdef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should not be defined before c++20"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER == 17
|
||||
|
||||
# ifdef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should not be defined before c++20"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER == 20
|
||||
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++20"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 20
|
||||
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++2b"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 20
|
||||
|
||||
int main(int, char**) { return 0; }
|
|
@ -2462,17 +2462,11 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++20"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++20"
|
||||
# endif
|
||||
|
||||
# if TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L
|
||||
|
@ -3613,17 +3607,11 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++2b"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_coroutine
|
||||
# error "__cpp_lib_coroutine should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_coroutine != 201902L
|
||||
# error "__cpp_lib_coroutine should have the value 201902L in c++2b"
|
||||
# endif
|
||||
|
||||
# if TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L
|
||||
|
|
|
@ -1,74 +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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SUPPORT_COROUTINE_TYPES_H
|
||||
#define SUPPORT_COROUTINE_TYPES_H
|
||||
|
||||
#include <experimental/coroutine>
|
||||
|
||||
template <typename Ty> struct generator {
|
||||
struct promise_type {
|
||||
Ty current_value;
|
||||
std::experimental::suspend_always yield_value(Ty value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
std::experimental::suspend_always initial_suspend() { return {}; }
|
||||
std::experimental::suspend_always final_suspend() noexcept { return {}; }
|
||||
generator get_return_object() { return generator{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
struct iterator {
|
||||
std::experimental::coroutine_handle<promise_type> _Coro;
|
||||
bool _Done;
|
||||
|
||||
iterator(std::experimental::coroutine_handle<promise_type> Coro, bool Done)
|
||||
: _Coro(Coro), _Done(Done) {}
|
||||
|
||||
iterator &operator++() {
|
||||
_Coro.resume();
|
||||
_Done = _Coro.done();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator const &_Right) const {
|
||||
return _Done == _Right._Done;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
|
||||
|
||||
Ty const &operator*() const { return _Coro.promise().current_value; }
|
||||
|
||||
Ty const *operator->() const { return &(operator*()); }
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
p.resume();
|
||||
return {p, p.done()};
|
||||
}
|
||||
|
||||
iterator end() { return {p, true}; }
|
||||
|
||||
generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
|
||||
|
||||
~generator() {
|
||||
if (p)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit generator(promise_type *p)
|
||||
: p(std::experimental::coroutine_handle<promise_type>::from_promise(*p)) {}
|
||||
|
||||
std::experimental::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
#endif // SUPPORT_COROUTINE_TYPES_H
|
|
@ -258,7 +258,6 @@ feature_test_macros = [ add_version_header(x) for x in [
|
|||
"name": "__cpp_lib_coroutine",
|
||||
"values": { "c++20": 201902 },
|
||||
"headers": ["coroutine"],
|
||||
"unimplemented": True,
|
||||
}, {
|
||||
"name": "__cpp_lib_destroying_delete",
|
||||
"values": { "c++20": 201806 },
|
||||
|
|
|
@ -29,7 +29,7 @@ mandatory_inclusions = {
|
|||
"chrono": ["compare"],
|
||||
"cinttypes": ["cstdint"],
|
||||
"complex.h": ["complex"],
|
||||
# TODO "coroutine": ["compare"],
|
||||
"coroutine": ["compare"],
|
||||
"deque": ["compare", "initializer_list"],
|
||||
"filesystem": ["compare"],
|
||||
"forward_list": ["compare", "initializer_list"],
|
||||
|
|
|
@ -55,7 +55,8 @@ header_markup = {
|
|||
"cwchar": ["ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS"],
|
||||
"wchar.h": ["ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS"],
|
||||
|
||||
"experimental/coroutine": ["if defined(__cpp_coroutines)"],
|
||||
"experimental/coroutine": ["ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES"],
|
||||
"coroutine": ["ifndef _LIBCPP_HAS_NO_CXX20_COROUTINES"],
|
||||
"experimental/regex": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"],
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ DEFAULT_FEATURES = [
|
|||
Feature(name='fdelayed-template-parsing', when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')),
|
||||
Feature(name='libcpp-no-structured-bindings', when=lambda cfg: '__cpp_structured_bindings' not in featureTestMacros(cfg)),
|
||||
Feature(name='libcpp-no-concepts', when=lambda cfg: featureTestMacros(cfg).get('__cpp_concepts', 0) < 201907),
|
||||
Feature(name='libcpp-no-coroutines', when=lambda cfg: featureTestMacros(cfg).get('__cpp_impl_coroutine', 0) < 201902),
|
||||
Feature(name='has-fobjc-arc', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and
|
||||
sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms.
|
||||
Feature(name='objective-c++', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')),
|
||||
|
|
Loading…
Reference in New Issue