Add <experimental/coroutine>

This patch adds the library portions of the coroutines PDTS,
which should now be supported by Clang.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@303836 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2017-05-25 04:36:24 +00:00
parent 8392d4940d
commit 737c3bf25e
25 changed files with 1317 additions and 0 deletions

View File

@@ -452,6 +452,11 @@ add_compile_flags_if_supported(-nostdinc++)
# the dylib when get ODR used by another function. # the dylib when get ODR used by another function.
add_compile_flags_if_supported(-fvisibility-inlines-hidden) add_compile_flags_if_supported(-fvisibility-inlines-hidden)
if (LIBCXX_CONFIGURE_IDE)
# This simply allows IDE to process <experimental/coroutine>
add_compile_flags_if_supported(-fcoroutines-ts)
endif()
# Let the library headers know they are currently being used to build the # Let the library headers know they are currently being used to build the
# library. # library.
add_definitions(-D_LIBCPP_BUILDING_LIBRARY) add_definitions(-D_LIBCPP_BUILDING_LIBRARY)

View File

@@ -44,6 +44,13 @@
#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \ #define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
} } _LIBCPP_END_NAMESPACE_EXPERIMENTAL } } _LIBCPP_END_NAMESPACE_EXPERIMENTAL
#define _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES \
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL inline namespace coroutines_v1 {
#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES \
} _LIBCPP_END_NAMESPACE_EXPERIMENTAL
#define _VSTD_CORO _VSTD_EXPERIMENTAL::coroutines_v1
#define _VSTD_FS ::std::experimental::filesystem::v1 #define _VSTD_FS ::std::experimental::filesystem::v1

View File

@@ -0,0 +1,260 @@
// -*- C++ -*-
//===----------------------------- coroutine -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
#define _LIBCPP_EXPERIMENTAL_COROUTINE
/**
experimental/coroutine synopsis
// C++next
namespace std {
namespace experimental {
inline namespace coroutines_v1 {
// 18.11.1 coroutine traits
template <typename R, typename... ArgTypes>
class coroutine_traits;
// 18.11.2 coroutine handle
template <typename Promise = void>
class coroutine_handle;
// 18.11.2.7 comparison operators:
bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept;
bool operator!=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept;
bool operator<=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
bool operator>=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
bool operator>(coroutine_handle<> x, coroutine_handle<> y) noexcept;
// 18.11.3 trivial awaitables
struct suspend_never;
struct suspend_always;
// 18.11.2.8 hash support:
template <class T> struct hash;
template <class P> struct hash<coroutine_handle<P>>;
} // namespace coroutines_v1
} // namespace experimental
} // namespace std
*/
#include <experimental/__config>
#include <new>
#include <type_traits>
#include <functional>
#include <memory> // for hash<T*>
#include <cstddef>
#include <cassert>
#include <__debug>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#ifndef __cpp_coroutines
# if defined(_LIBCPP_WARNING)
_LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
# else
# warning <experimental/coroutine> cannot be used with this compiler
# endif
#endif
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
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 <typename _Ret, typename... _Args>
struct _LIBCPP_TEMPLATE_VIS coroutine_traits
: public __coroutine_traits_sfinae<_Ret>
{
};
template <typename Promise = void>
class _LIBCPP_TEMPLATE_VIS coroutine_handle;
#if defined(__cpp_coroutines)
template <>
class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
public:
_LIBCPP_ALWAYS_INLINE
constexpr coroutine_handle() noexcept : __handle_(nullptr) {}
_LIBCPP_ALWAYS_INLINE
constexpr coroutine_handle(nullptr_t) noexcept : __handle_(nullptr) {}
_LIBCPP_ALWAYS_INLINE
coroutine_handle& operator=(nullptr_t) noexcept {
__handle_ = nullptr;
return *this;
}
_LIBCPP_ALWAYS_INLINE
constexpr void* address() const noexcept { return __handle_; }
_LIBCPP_ALWAYS_INLINE
constexpr explicit operator bool() const noexcept { return __handle_; }
_LIBCPP_ALWAYS_INLINE
void operator()() const { resume(); }
_LIBCPP_ALWAYS_INLINE
void resume() const {
_LIBCPP_ASSERT(__is_suspended(),
"resume() can only be called on suspended coroutines");
_LIBCPP_ASSERT(!done(),
"resume() has undefined behavior when the coroutine is done");
__builtin_coro_resume(__handle_);
}
_LIBCPP_ALWAYS_INLINE
void destroy() const {
_LIBCPP_ASSERT(__is_suspended(),
"destroy() can only be called on suspended coroutines");
__builtin_coro_destroy(__handle_);
}
_LIBCPP_ALWAYS_INLINE
bool done() const {
_LIBCPP_ASSERT(__is_suspended(),
"done() can only be called on suspended coroutines");
return __builtin_coro_done(__handle_);
}
public:
_LIBCPP_ALWAYS_INLINE
static coroutine_handle from_address(void* __addr) noexcept {
coroutine_handle __tmp;
__tmp.__handle_ = __addr;
return __tmp;
}
private:
bool __is_suspended() const noexcept {
// FIXME actually implement a check for if the coro is suspended.
return __handle_;
}
template <class _PromiseT> friend class coroutine_handle;
void* __handle_;
};
// 18.11.2.7 comparison operators:
inline _LIBCPP_ALWAYS_INLINE
bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return __x.address() == __y.address();
}
inline _LIBCPP_ALWAYS_INLINE
bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return !(__x == __y);
}
inline _LIBCPP_ALWAYS_INLINE
bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return less<void*>()(__x.address(), __y.address());
}
inline _LIBCPP_ALWAYS_INLINE
bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return __y < __x;
}
inline _LIBCPP_ALWAYS_INLINE
bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return !(__x > __y);
}
inline _LIBCPP_ALWAYS_INLINE
bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
return !(__x < __y);
}
template <typename _Promise>
class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
using _Base = coroutine_handle<>;
public:
// 18.11.2.1 construct/reset
using coroutine_handle<>::coroutine_handle;
_LIBCPP_INLINE_VISIBILITY
coroutine_handle& operator=(nullptr_t) noexcept {
_Base::operator=(nullptr);
return *this;
}
_LIBCPP_INLINE_VISIBILITY
_Promise& promise() {
return *reinterpret_cast<_Promise*>(
__builtin_coro_promise(this->__handle_, alignof(_Promise), false));
}
_LIBCPP_INLINE_VISIBILITY
_Promise const& promise() const {
return *reinterpret_cast<_Promise const*>(
__builtin_coro_promise(this->__handle_, alignof(_Promise), false));
}
public:
_LIBCPP_ALWAYS_INLINE
static coroutine_handle from_address(void* __addr) noexcept {
coroutine_handle __tmp;
__tmp.__handle_ = __addr;
return __tmp;
}
_LIBCPP_ALWAYS_INLINE
static coroutine_handle from_promise(_Promise& __promise) noexcept {
coroutine_handle __tmp;
__tmp.__handle_ = __builtin_coro_promise(_VSTD::addressof(__promise),
alignof(_Promise), true);
return __tmp;
}
};
#endif // defined(__cpp_coroutines)
struct _LIBCPP_TYPE_VIS suspend_never {
_LIBCPP_ALWAYS_INLINE
bool await_ready() const noexcept { return true; }
_LIBCPP_ALWAYS_INLINE
void await_suspend(coroutine_handle<>) const noexcept {}
_LIBCPP_ALWAYS_INLINE
void await_resume() const noexcept {}
};
struct _LIBCPP_TYPE_VIS suspend_always {
_LIBCPP_ALWAYS_INLINE
bool await_ready() const noexcept { return false; }
_LIBCPP_ALWAYS_INLINE
void await_suspend(coroutine_handle<>) const noexcept {}
_LIBCPP_ALWAYS_INLINE
void await_resume() const noexcept {}
};
_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp>
struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
_LIBCPP_INLINE_VISIBILITY
size_t operator()(__arg_type const& __v) const noexcept
{return hash<void*>{}(__v.address());}
};
_LIBCPP_END_NAMESPACE_STD
#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */

View File

@@ -501,6 +501,10 @@ module std [system] {
header "experimental/chrono" header "experimental/chrono"
export * export *
} }
module coroutine {
header "experimental/coroutine"
export *
}
module deque { module deque {
header "experimental/deque" header "experimental/deque"
export * export *

View File

@@ -137,6 +137,9 @@
#include <experimental/algorithm> #include <experimental/algorithm>
#include <experimental/any> #include <experimental/any>
#include <experimental/chrono> #include <experimental/chrono>
#if defined(__cpp_coroutines)
#include <experimental/coroutine>
#endif
#include <experimental/deque> #include <experimental/deque>
#include <experimental/dynarray> #include <experimental/dynarray>
#include <experimental/filesystem> #include <experimental/filesystem>

View File

@@ -0,0 +1,25 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
#include <experimental/coroutine>
#ifndef _LIBCPP_VERSION
#error _LIBCPP_VERSION must be defined
#endif
int main()
{
}

View File

@@ -0,0 +1,62 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// constexpr explicit operator bool() const noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class C>
void do_test() {
static_assert(std::is_nothrow_constructible<bool, C>::value, "");
static_assert(!std::is_convertible<C, bool>::value, "");
{
constexpr C c; ((void)c);
static_assert(bool(c) == false, "");
}
{ // null case
const C c = {}; ((void)c);
ASSERT_NOEXCEPT(bool(c));
if (c)
assert(false);
else
assert(true);
assert(c.address() == nullptr);
assert(bool(c) == false);
}
{ // non-null case
int dummy = 42;
C c = C::from_address(&dummy);
assert(c.address() == &dummy);
assert(bool(c) == true);
}
}
int main()
{
do_test<coro::coroutine_handle<>>();
do_test<coro::coroutine_handle<int>>();
}

View File

@@ -0,0 +1,64 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// bool operator==(coroutine_handle<>, coroutine_handle<>) noexcept
// bool operator!=(coroutine_handle<>, coroutine_handle<>) noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class C>
void do_test(uintptr_t LHSVal, uintptr_t RHSVal) {
const C LHS = C::from_address(reinterpret_cast<void*>(LHSVal));
const C RHS = C::from_address(reinterpret_cast<void*>(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()
{
std::pair<uintptr_t, uintptr_t> const TestCases[] = {
{0, 0},
{16, 16},
{0, 16},
{16, 0}
};
for (auto& TC : TestCases) {
do_test<coro::coroutine_handle<>>(TC.first, TC.second);
do_test<coro::coroutine_handle<int>>(TC.first, TC.second);
}
}

View File

@@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// bool operator<(coroutine_handle<>, coroutine_handle<>) noexcept
// bool operator>(coroutine_handle<>, coroutine_handle<>) noexcept
// bool operator>=(coroutine_handle<>, coroutine_handle<>) noexcept
// bool operator<=(coroutine_handle<>, coroutine_handle<>) noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class C>
void do_test(uintptr_t LHSVal, uintptr_t RHSVal) {
const C LHS = C::from_address(reinterpret_cast<void*>(LHSVal));
const C RHS = C::from_address(reinterpret_cast<void*>(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()
{
std::pair<uintptr_t, uintptr_t> const TestCases[] = {
{0, 0},
{16, 16},
{0, 16},
{16, 0}
};
for (auto& TC : TestCases) {
do_test<coro::coroutine_handle<>>(TC.first, TC.second);
do_test<coro::coroutine_handle<int>>(TC.first, TC.second);
}
}

View File

@@ -0,0 +1,48 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// bool done() const
#include <experimental/coroutine>
#include <type_traits>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class Promise>
void do_test(coro::coroutine_handle<Promise> const& H) {
// FIXME Add a runtime test
{
ASSERT_SAME_TYPE(decltype(H.done()), bool);
ASSERT_NOT_NOEXCEPT(H.done());
}
}
int main()
{
do_test(coro::coroutine_handle<>{});
do_test(coro::coroutine_handle<int>{});
}

View File

@@ -0,0 +1,58 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// coroutine_handle& operator=(nullptr_t) noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
namespace coro = std::experimental;
template <class C>
void do_test() {
int dummy = 42;
void* dummy_h = &dummy;
{
C c; ((void)c);
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()
{
do_test<coro::coroutine_handle<>>();
do_test<coro::coroutine_handle<int>>();
}

View File

@@ -0,0 +1,57 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// constexpr coroutine_handle() noexcept
// constexpr coroutine_handle(nullptr_t) noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
namespace coro = std::experimental;
template <class C>
void do_test() {
{
constexpr C c;
static_assert(std::is_nothrow_default_constructible<C>::value, "");
static_assert(c.address() == nullptr, "");
}
{
constexpr C c(nullptr);
static_assert(std::is_nothrow_constructible<C, std::nullptr_t>::value, "");
static_assert(c.address() == nullptr, "");
}
{
C c;
assert(c.address() == nullptr);
}
{
C c(nullptr);
assert(c.address() == nullptr);
}
}
int main()
{
do_test<coro::coroutine_handle<>>();
do_test<coro::coroutine_handle<int>>();
}

View File

@@ -0,0 +1,55 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// constexpr void* address() const noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class C>
void 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);
}
{
int dummy = 42;
C c = C::from_address(&dummy);
assert(c.address() == &dummy);
}
}
int main()
{
do_test<coro::coroutine_handle<>>();
do_test<coro::coroutine_handle<int>>();
}

View File

@@ -0,0 +1,50 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// static coroutine_handle from_address(void*) noexcept
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
namespace coro = std::experimental;
template <class C>
void do_test() {
{
C c = C::from_address(nullptr);
static_assert(noexcept(C::from_address(nullptr)), "");
// FIXME: Should the return type not be 'C'?
static_assert(std::is_same<decltype(C::from_address(nullptr)), C>::value, "");
assert(c.address() == nullptr);
}
{
int dummy = 42;
C c = C::from_address(&dummy);
assert(c.address() == &dummy);
}
}
int main()
{
do_test<coro::coroutine_handle<>>();
do_test<coro::coroutine_handle<int>>();
}

View File

@@ -0,0 +1,67 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// namespace std {
// template <class P> struct hash<experimental::coroutine_handle<P>>;
// }
#include <experimental/coroutine>
#include <type_traits>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class C>
void do_test(uintptr_t LHSVal, uintptr_t RHSVal) {
const size_t ExpectLHS = std::hash<void*>{}(reinterpret_cast<void*>(LHSVal));
const size_t ExpectRHS = std::hash<void*>{}(reinterpret_cast<void*>(RHSVal));
const C LHS = C::from_address(reinterpret_cast<void*>(LHSVal));
const C RHS = C::from_address(reinterpret_cast<void*>(RHSVal));
const std::hash<C> h;
// FIXME: libc++'s implementation hash's the result of LHS.address(), so we
// expect that value. However this is not required.
assert(h(LHS) == ExpectLHS);
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()
{
std::pair<uintptr_t, uintptr_t> const TestCases[] = {
{0, 0},
{0, 8},
{8, 8},
{8, 16}
};
for (auto& TC : TestCases) {
do_test<coro::coroutine_handle<>>(TC.first, TC.second);
do_test<coro::coroutine_handle<int>>(TC.first, TC.second);
}
}

View File

@@ -0,0 +1,54 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise>
// struct coroutine_handle<Promise>;
// Promise& promise()
// Promise const& promise() const
#include <experimental/coroutine>
#include <type_traits>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class Promise>
void do_test(coro::coroutine_handle<Promise>&& H) {
// FIXME Add a runtime test
{
ASSERT_SAME_TYPE(decltype(H.promise()), Promise&);
ASSERT_NOT_NOEXCEPT(H.promise());
}
{
auto const& CH = H;
ASSERT_SAME_TYPE(decltype(CH.promise()), Promise const&);
ASSERT_NOT_NOEXCEPT(CH.promise());
}
}
int main()
{
do_test(coro::coroutine_handle<int>{});
}

View File

@@ -0,0 +1,48 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// void destroy() const
#include <experimental/coroutine>
#include <type_traits>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class Promise>
void do_test(coro::coroutine_handle<Promise> const& H) {
// FIXME Add a runtime test
{
ASSERT_SAME_TYPE(decltype(H.destroy()), void);
ASSERT_NOT_NOEXCEPT(H.destroy());
}
}
int main()
{
do_test(coro::coroutine_handle<>{});
do_test(coro::coroutine_handle<int>{});
}

View File

@@ -0,0 +1,51 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// template <class Promise = void>
// struct coroutine_handle;
// void operator()() const
// void resume() const
#include <experimental/coroutine>
#include <type_traits>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
template <class Promise>
void do_test(coro::coroutine_handle<Promise> const& H) {
// FIXME Add a runtime test
{
ASSERT_SAME_TYPE(decltype(H.resume()), void);
ASSERT_SAME_TYPE(decltype(H()), void);
ASSERT_NOT_NOEXCEPT(H.resume());
ASSERT_NOT_NOEXCEPT(H());
}
}
int main()
{
do_test(coro::coroutine_handle<>{});
do_test(coro::coroutine_handle<int>{});
}

View File

@@ -0,0 +1,55 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
#include <experimental/coroutine>
namespace coro = std::experimental;
struct A {
using promise_type = A*;
};
struct B {};
struct C {};
namespace std { namespace experimental {
template <>
struct coroutine_traits<::A, int> {
using promise_type = int*;
};
template <class ...Args>
struct coroutine_traits<::B, Args...> {
using promise_type = B*;
};
template <>
struct coroutine_traits<::C> {
using promise_type = void;
};
}}
template <class Expect, class T, class ...Args>
void check_type() {
using P = typename coro::coroutine_traits<T, Args...>::promise_type ;
static_assert(std::is_same<P, Expect>::value, "");
};
int main()
{
check_type<A*, A>();
check_type<int*, A, int>();
check_type<B*, B>();
check_type<void, C>();
}

View File

@@ -0,0 +1,81 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
#include <experimental/coroutine>
namespace coro = std::experimental;
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 {};
namespace std { namespace experimental {
template <>
struct coroutine_traits<::A, int> {
using promise_type = int*;
};
template <class ...Args>
struct coroutine_traits<::B, Args...> {
using promise_type = B*;
};
template <>
struct coroutine_traits<::C> {
using promise_type = void;
};
}}
template <class Expect, class T, class ...Args>
void check_type() {
using Traits = coro::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 = coro::coroutine_traits<T, Args...>;
static_assert(!has_promise_type<Traits>(), "");
}
int main()
{
{
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>();
}
}

View File

@@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
using SuspendT = std::experimental::coroutines_v1::suspend_always;
TEST_SAFE_STATIC SuspendT safe_sa;
constexpr SuspendT constexpr_sa;
constexpr bool check_suspend_constexpr() {
SuspendT s{};
const SuspendT scopy(s); ((void)scopy);
SuspendT smove(std::move(s)); ((void)smove);
s = scopy;
s = std::move(smove);
return true;
}
int main()
{
using H = coro::coroutine_handle<>;
using S = SuspendT;
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() == false);
assert(cs.await_ready() == false);
}
{
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<S>::value, "");
static_assert(std::is_nothrow_copy_constructible<S>::value, "");
static_assert(std::is_nothrow_move_constructible<S>::value, "");
static_assert(std::is_nothrow_copy_assignable<S>::value, "");
static_assert(std::is_nothrow_move_assignable<S>::value, "");
static_assert(std::is_trivially_copyable<S>::value, "");
static_assert(check_suspend_constexpr(), "");
}
}

View File

@@ -0,0 +1,75 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
#include <experimental/coroutine>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
namespace coro = std::experimental;
// Test that the type is in the correct namespace
using SuspendT = std::experimental::coroutines_v1::suspend_never;
TEST_SAFE_STATIC SuspendT safe_sn;
constexpr SuspendT constexpr_sn;
constexpr bool check_suspend_constexpr() {
SuspendT s{};
const SuspendT scopy(s); ((void)scopy);
SuspendT smove(std::move(s)); ((void)smove);
s = scopy;
s = std::move(smove);
return true;
}
int main()
{
using H = coro::coroutine_handle<>;
using S = SuspendT;
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<S>::value, "");
static_assert(std::is_nothrow_copy_constructible<S>::value, "");
static_assert(std::is_nothrow_move_constructible<S>::value, "");
static_assert(std::is_nothrow_copy_assignable<S>::value, "");
static_assert(std::is_nothrow_move_assignable<S>::value, "");
static_assert(std::is_trivially_copyable<S>::value, "");
static_assert(check_suspend_constexpr(), "");
}
}

View File

@@ -0,0 +1,31 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11
// REQUIRES: fcoroutines-ts
// RUN: %build -fcoroutines-ts
// RUN: %run
// <experimental/coroutine>
// Test that <experimental/coroutine> includes <new>
#include <experimental/coroutine>
int main(){
// std::nothrow is not implicitly defined by the compiler when the include is
// missing, unlike other parts of <new>. Therefore we use std::nothrow to
// test for #include <new>
(void)std::nothrow;
}

View File

@@ -154,6 +154,12 @@
#define TEST_NORETURN [[noreturn]] #define TEST_NORETURN [[noreturn]]
#endif #endif
#if defined(_LIBCPP_SAFE_STATIC)
#define TEST_SAFE_STATIC _LIBCPP_SAFE_STATIC
#else
#define TEST_SAFE_STATIC
#endif
#if TEST_STD_VER < 11 #if TEST_STD_VER < 11
#define ASSERT_NOEXCEPT(...) #define ASSERT_NOEXCEPT(...)
#define ASSERT_NOT_NOEXCEPT(...) #define ASSERT_NOT_NOEXCEPT(...)

View File

@@ -142,6 +142,7 @@ class Configuration(object):
self.configure_sanitizer() self.configure_sanitizer()
self.configure_coverage() self.configure_coverage()
self.configure_modules() self.configure_modules()
self.configure_coroutines()
self.configure_substitutions() self.configure_substitutions()
self.configure_features() self.configure_features()
@@ -954,6 +955,10 @@ class Configuration(object):
self.cxx.flags += ['-g', '--coverage'] self.cxx.flags += ['-g', '--coverage']
self.cxx.compile_flags += ['-O0'] self.cxx.compile_flags += ['-O0']
def configure_coroutines(self):
if self.cxx.hasCompileFlag('-fcoroutines-ts'):
self.config.available_features.add('fcoroutines-ts')
def configure_modules(self): def configure_modules(self):
modules_flags = ['-fmodules'] modules_flags = ['-fmodules']
if platform.system() != 'Darwin': if platform.system() != 'Darwin':