diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c25a0a0e40a..33d888b807da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -452,6 +452,11 @@ add_compile_flags_if_supported(-nostdinc++) # the dylib when get ODR used by another function. add_compile_flags_if_supported(-fvisibility-inlines-hidden) +if (LIBCXX_CONFIGURE_IDE) + # This simply allows IDE to process + add_compile_flags_if_supported(-fcoroutines-ts) +endif() + # Let the library headers know they are currently being used to build the # library. add_definitions(-D_LIBCPP_BUILDING_LIBRARY) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index c425c31ea095..730ee7e164a6 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -41,7 +41,15 @@ if (LIBCXX_SUPPORTS_NODEFAULTLIBS_FLAG) if (MINGW) # Mingw64 requires quite a few "C" runtime libraries in order for basic # programs to link successfully with -nodefaultlibs. - list(APPEND CMAKE_REQUIRED_LIBRARIES mingw32 gcc gcc_eh mingwex msvcrt gcc) + if (LIBCXX_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBCXX_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) endif() if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") diff --git a/include/__config b/include/__config index 4ad700e234c2..32e542bd1fd7 100644 --- a/include/__config +++ b/include/__config @@ -1126,6 +1126,10 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( # define _LIBCPP_HAS_NO_IS_AGGREGATE #endif +#if !defined(__cpp_coroutines) || __cpp_coroutines < 201703L +# define _LIBCPP_HAS_NO_COROUTINES +#endif + #endif // __cplusplus // Decide whether to use availability macros. diff --git a/include/__threading_support b/include/__threading_support index 385fff32b350..afd7cb506492 100644 --- a/include/__threading_support +++ b/include/__threading_support @@ -27,7 +27,7 @@ # include # include #elif defined(_LIBCPP_HAS_THREAD_API_WIN32) -#include +#include #include #include #include <__undef_min_max> diff --git a/include/algorithm b/include/algorithm index 08ca23ff6168..7ea4474a1bb4 100644 --- a/include/algorithm +++ b/include/algorithm @@ -35,6 +35,9 @@ template Function for_each(InputIterator first, InputIterator last, Function f); +template + InputIterator for_each_n(InputIterator first, Size n, Function f); // C++17 + template InputIterator find(InputIterator first, InputIterator last, const T& value); @@ -961,6 +964,26 @@ for_each(_InputIterator __first, _InputIterator __last, _Function __f) return __f; } +#if _LIBCPP_STD_VER > 14 +// for_each_n + +template +inline _LIBCPP_INLINE_VISIBILITY +_InputIterator +for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) +{ + typedef decltype(__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; + while (__n > 0) + { + __f(*__first); + ++__first; + --__n; + } + return __first; +} +#endif + // find template diff --git a/include/experimental/__config b/include/experimental/__config index 9a7bbe85d8d3..37f88c166dd2 100644 --- a/include/experimental/__config +++ b/include/experimental/__config @@ -44,6 +44,13 @@ #define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \ } } _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 diff --git a/include/experimental/coroutine b/include/experimental/coroutine new file mode 100644 index 000000000000..d2a03ae8a8c8 --- /dev/null +++ b/include/experimental/coroutine @@ -0,0 +1,270 @@ +// -*- 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 +class coroutine_traits; +// 18.11.2 coroutine handle +template +class coroutine_handle; +// 18.11.2.7 comparison operators: +bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +bool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +bool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +bool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +bool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; +// 18.11.3 trivial awaitables +struct suspend_never; +struct suspend_always; +// 18.11.2.8 hash support: +template struct hash; +template struct hash>; + +} // namespace coroutines_v1 +} // namespace experimental +} // namespace std + + */ + +#include +#include +#include +#include +#include // for hash +#include +#include +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#ifdef _LIBCPP_HAS_NO_COROUTINES +# if defined(_LIBCPP_WARNING) + _LIBCPP_WARNING(" cannot be used with this compiler") +# else +# warning cannot be used with this compiler +# endif +#endif + +#ifndef _LIBCPP_HAS_NO_COROUTINES + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES + +template +struct __coroutine_traits_sfinae {}; + +template +struct __coroutine_traits_sfinae< + _Tp, typename __void_t::type> +{ + using promise_type = typename _Tp::promise_type; +}; + +template +struct _LIBCPP_TEMPLATE_VIS coroutine_traits + : public __coroutine_traits_sfinae<_Ret> +{ +}; + +template +class _LIBCPP_TEMPLATE_VIS coroutine_handle; + +template <> +class _LIBCPP_TEMPLATE_VIS coroutine_handle { +public: + _LIBCPP_ALWAYS_INLINE + _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} + + _LIBCPP_ALWAYS_INLINE + _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} + + _LIBCPP_ALWAYS_INLINE + coroutine_handle& operator=(nullptr_t) _NOEXCEPT { + __handle_ = nullptr; + return *this; + } + + _LIBCPP_ALWAYS_INLINE + _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } + + _LIBCPP_ALWAYS_INLINE + _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } + + _LIBCPP_ALWAYS_INLINE + void operator()() { resume(); } + + _LIBCPP_ALWAYS_INLINE + void resume() { + _LIBCPP_ASSERT(__is_suspended(), + "resume() can only be called on suspended coroutines"); + _LIBCPP_ASSERT(!done(), + "resume() has undefined behavior when the coroutine is done"); + __builtin_coro_resume(__handle_); + } + + _LIBCPP_ALWAYS_INLINE + void destroy() { + _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 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()(__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 +class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { + using _Base = coroutine_handle<>; +public: +#ifndef _LIBCPP_CXX03_LANG + // 18.11.2.1 construct/reset + using coroutine_handle<>::coroutine_handle; +#else + _LIBCPP_ALWAYS_INLINE coroutine_handle() _NOEXCEPT : _Base() {} + _LIBCPP_ALWAYS_INLINE coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} +#endif + _LIBCPP_INLINE_VISIBILITY + coroutine_handle& operator=(nullptr_t) _NOEXCEPT { + _Base::operator=(nullptr); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + _Promise& promise() const { + return *reinterpret_cast<_Promise*>( + __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; + } + + // NOTE: this overload isn't required by the standard but is needed so + // the deleted _Promise* overload doesn't make from_address(nullptr) + // ambiguous. + // FIXME: should from_address work with nullptr? + _LIBCPP_ALWAYS_INLINE + static coroutine_handle from_address(nullptr_t) _NOEXCEPT { + return {}; + } + + // from_address cannot be used with the coroutines promise type. + static coroutine_handle from_address(_Promise*) = delete; + + _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; + } +}; + +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 +struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { + using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; + _LIBCPP_INLINE_VISIBILITY + size_t operator()(__arg_type const& __v) const _NOEXCEPT + {return hash()(__v.address());} +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) + +#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ diff --git a/include/iterator b/include/iterator index 4aa44746dc96..d163ab1b0910 100644 --- a/include/iterator +++ b/include/iterator @@ -990,7 +990,6 @@ public: _LIBCPP_INLINE_VISIBILITY char_type operator*() const {return static_cast(__sbuf_->sgetc());} - _LIBCPP_INLINE_VISIBILITY char_type* operator->() const {return nullptr;} _LIBCPP_INLINE_VISIBILITY istreambuf_iterator& operator++() { __sbuf_->sbumpc(); diff --git a/include/memory b/include/memory index 4201c92dd723..31dc73d8b142 100644 --- a/include/memory +++ b/include/memory @@ -2251,6 +2251,8 @@ void swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y) template struct _LIBCPP_TEMPLATE_VIS default_delete { + static_assert(!is_function<_Tp>::value, + "default_delete cannot be instantiated for function types"); #ifndef _LIBCPP_CXX03_LANG _LIBCPP_INLINE_VISIBILITY constexpr default_delete() noexcept = default; #else @@ -3653,6 +3655,18 @@ __shared_ptr_emplace<_Tp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT __a.deallocate(_PTraits::pointer_to(*this), 1); } +struct __shared_ptr_dummy_rebind_allocator_type; +template <> +class _LIBCPP_TEMPLATE_VIS allocator<__shared_ptr_dummy_rebind_allocator_type> +{ +public: + template + struct rebind + { + typedef allocator<_Other> other; + }; +}; + template class _LIBCPP_TEMPLATE_VIS enable_shared_from_this; template @@ -3921,6 +3935,17 @@ public: #endif // _LIBCPP_HAS_NO_VARIADICS private: + template ::value> + struct __shared_ptr_default_allocator + { + typedef allocator<_Yp> type; + }; + + template + struct __shared_ptr_default_allocator<_Yp, true> + { + typedef allocator<__shared_ptr_dummy_rebind_allocator_type> type; + }; template _LIBCPP_INLINE_VISIBILITY @@ -3939,8 +3964,7 @@ private: } } - _LIBCPP_INLINE_VISIBILITY - void __enable_weak_this(const volatile void*, const volatile void*) _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY void __enable_weak_this(...) _NOEXCEPT {} template friend class _LIBCPP_TEMPLATE_VIS shared_ptr; template friend class _LIBCPP_TEMPLATE_VIS weak_ptr; @@ -3972,8 +3996,9 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, : __ptr_(__p) { unique_ptr<_Yp> __hold(__p); - typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), allocator<_Yp>()); + typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; + typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, _AllocT > _CntrlBlk; + __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), _AllocT()); __hold.release(); __enable_weak_this(__p, __p); } @@ -3988,8 +4013,9 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, try { #endif // _LIBCPP_NO_EXCEPTIONS - typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Yp>()); + typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; + typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT > _CntrlBlk; + __cntrl_ = new _CntrlBlk(__p, __d, _AllocT()); __enable_weak_this(__p, __p); #ifndef _LIBCPP_NO_EXCEPTIONS } @@ -4010,8 +4036,9 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t __p, _Dp __d) try { #endif // _LIBCPP_NO_EXCEPTIONS - typedef __shared_ptr_pointer > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Tp>()); + typedef typename __shared_ptr_default_allocator<_Tp>::type _AllocT; + typedef __shared_ptr_pointer _CntrlBlk; + __cntrl_ = new _CntrlBlk(__p, __d, _AllocT()); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -4179,8 +4206,9 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_Yp, _Dp> __r, else #endif { - typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), allocator<_Yp>()); + typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; + typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT > _CntrlBlk; + __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), _AllocT()); __enable_weak_this(__r.get(), __r.get()); } __r.release(); @@ -4208,10 +4236,11 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_Yp, _Dp> __r, else #endif { + typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; typedef __shared_ptr_pointer<_Yp*, reference_wrapper::type>, - allocator<_Yp> > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), allocator<_Yp>()); + _AllocT > _CntrlBlk; + __cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), _AllocT()); __enable_weak_this(__r.get(), __r.get()); } __r.release(); diff --git a/include/module.modulemap b/include/module.modulemap index c354cae1e5f1..462d4234ae6c 100644 --- a/include/module.modulemap +++ b/include/module.modulemap @@ -500,6 +500,10 @@ module std [system] { module chrono { header "experimental/chrono" export * + } + module coroutine { + header "experimental/coroutine" + export * } module deque { header "experimental/deque" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6161838d0dfd..fe45f5ac0fe5 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -242,14 +242,11 @@ endif() if (LIBCXX_ENABLE_STATIC) add_library(cxx_static STATIC $) target_link_libraries(cxx_static ${LIBCXX_LIBRARIES}) - set(STATIC_OUTPUT_NAME "c++") - if (WIN32) - set(STATIC_OUTPUT_NAME "libc++") - endif() + set(CMAKE_STATIC_LIBRARY_PREFIX "lib") set_target_properties(cxx_static PROPERTIES LINK_FLAGS "${LIBCXX_LINK_FLAGS}" - OUTPUT_NAME "${STATIC_OUTPUT_NAME}" + OUTPUT_NAME "c++" ) list(APPEND LIBCXX_TARGETS "cxx_static") diff --git a/test/libcxx/double_include.sh.cpp b/test/libcxx/double_include.sh.cpp index 46dfc999be8b..0a9e9fcfaea8 100644 --- a/test/libcxx/double_include.sh.cpp +++ b/test/libcxx/double_include.sh.cpp @@ -137,6 +137,9 @@ #include #include #include +#if defined(__cpp_coroutines) +#include +#endif #include #include #include diff --git a/test/libcxx/experimental/language.support/support.coroutines/dialect_support.sh.cpp b/test/libcxx/experimental/language.support/support.coroutines/dialect_support.sh.cpp new file mode 100644 index 000000000000..56f47c8faf42 --- /dev/null +++ b/test/libcxx/experimental/language.support/support.coroutines/dialect_support.sh.cpp @@ -0,0 +1,59 @@ +// -*- 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. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: fcoroutines-ts + +// RUN: %build -fcoroutines-ts +// RUN: %run + +// A simple "breathing" test that checks that +// can be parsed and used in all dialects, including C++03 in order to match +// Clang's behavior. + +#include + +namespace coro = std::experimental::coroutines_v1; + +coro::suspend_always sa; +coro::suspend_never sn; + +struct MyFuture { + struct promise_type { + typedef coro::coroutine_handle HandleT; + coro::suspend_never initial_suspend() { return sn; } + coro::suspend_always final_suspend() { return sa; } + coro::suspend_never yield_value(int) { return sn; } + MyFuture get_return_object() { + MyFuture f(HandleT::from_promise(*this)); + return f; + } + void return_void() {} + void unhandled_exception() {} + }; + typedef promise_type::HandleT HandleT; + MyFuture() : p() {} + MyFuture(HandleT h) : p(h) {} + + coro::coroutine_handle p; +}; + +MyFuture test_coro() { + co_await sn; + co_yield 42; + co_return; +} + +int main() +{ + MyFuture f = test_coro(); + while (!f.p.done()) + f.p.resume(); + f.p.destroy(); +} diff --git a/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op_astrk/arrow.pass.cpp b/test/libcxx/experimental/language.support/support.coroutines/version.sh.cpp similarity index 52% rename from test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op_astrk/arrow.pass.cpp rename to test/libcxx/experimental/language.support/support.coroutines/version.sh.cpp index e3bf5e2bd84f..229ce10dd044 100644 --- a/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op_astrk/arrow.pass.cpp +++ b/test/libcxx/experimental/language.support/support.coroutines/version.sh.cpp @@ -1,3 +1,4 @@ +// -*- C++ -*- //===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure @@ -7,22 +8,18 @@ // //===----------------------------------------------------------------------===// -// +// UNSUPPORTED: c++98, c++03, c++11 +// REQUIRES: fcoroutines-ts -// istreambuf_iterator +// RUN: %build -fcoroutines-ts +// RUN: %run -// pointer operator->() const; +#include -#include -#include -#include +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION must be defined +#endif -typedef char C; -int main () +int main() { - std::istringstream s("filename"); - std::istreambuf_iterator i(s); - - (*i).~C(); // This is well-formed... - i->~C(); // ... so this should be supported! } diff --git a/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp b/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp new file mode 100644 index 000000000000..87cd29264b4e --- /dev/null +++ b/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp @@ -0,0 +1,44 @@ +// UNSUPPORTED: c++98, c++03 + +#include + +template struct Tag {}; + +template +using SPtr = std::shared_ptr)>; + +template +using FnType = void(Tag); + +template +void TestFn(Tag) {} + +template +FnType* getFn() { + return &TestFn; +} + +struct Deleter { + template + void operator()(Tp) const { + using RawT = typename std::remove_pointer::type; + static_assert(std::is_function::value || + std::is_same::type, + std::nullptr_t>::value, + ""); + } +}; + +int main() { + { + SPtr<0> s; // OK + SPtr<1> s1(nullptr); // OK + SPtr<2> s2(getFn<2>(), Deleter{}); // OK + SPtr<3> s3(nullptr, Deleter{}); // OK + } + // expected-error@memory:* 2 {{static_assert failed "default_delete cannot be instantiated for function types"}} + { + SPtr<4> s4(getFn<4>()); // expected-note {{requested here}} + SPtr<5> s5(getFn<5>(), std::default_delete>{}); // expected-note {{requested here}} + } +} diff --git a/test/std/algorithms/alg.nonmodifying/alg.foreach/for_each_n.pass.cpp b/test/std/algorithms/alg.nonmodifying/alg.foreach/for_each_n.pass.cpp new file mode 100644 index 000000000000..fd24edb43060 --- /dev/null +++ b/test/std/algorithms/alg.nonmodifying/alg.foreach/for_each_n.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// template +// InputIterator for_each_n(InputIterator first, Size n, Function f); + + +#include +#include + +#include "test_iterators.h" + +struct for_each_test +{ + for_each_test(int c) : count(c) {} + int count; + void operator()(int& i) {++i; ++count;} +}; + +int main() +{ + typedef input_iterator Iter; + int ia[] = {0, 1, 2, 3, 4, 5}; + const unsigned s = sizeof(ia)/sizeof(ia[0]); + + { + auto f = for_each_test(0); + Iter it = std::for_each_n(Iter(ia), 0, std::ref(f)); + assert(it == Iter(ia)); + assert(f.count == 0); + } + + { + auto f = for_each_test(0); + Iter it = std::for_each_n(Iter(ia), s, std::ref(f)); + + assert(it == Iter(ia+s)); + assert(f.count == s); + for (unsigned i = 0; i < s; ++i) + assert(ia[i] == static_cast(i+1)); + } + + { + auto f = for_each_test(0); + Iter it = std::for_each_n(Iter(ia), 1, std::ref(f)); + + assert(it == Iter(ia+1)); + assert(f.count == 1); + for (unsigned i = 0; i < 1; ++i) + assert(ia[i] == static_cast(i+2)); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.sh.cpp new file mode 100644 index 000000000000..a744f56eb811 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// constexpr explicit operator bool() const noexcept + +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test() { + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(!std::is_convertible::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 + char dummy = 42; + C c = C::from_address((void*)&dummy); + assert(c.address() == &dummy); + assert(bool(c) == true); + } +} + +int main() +{ + do_test>(); + do_test>(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.sh.cpp new file mode 100644 index 000000000000..05c3f230e5ca --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// bool operator==(coroutine_handle<>, coroutine_handle<>) noexcept +// bool operator!=(coroutine_handle<>, coroutine_handle<>) noexcept + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test(uintptr_t LHSVal, uintptr_t RHSVal) { + const C LHS = C::from_address(reinterpret_cast(LHSVal)); + const C RHS = C::from_address(reinterpret_cast(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 const TestCases[] = { + {0, 0}, + {16, 16}, + {0, 16}, + {16, 0} + }; + for (auto& TC : TestCases) { + do_test>(TC.first, TC.second); + do_test>(TC.first, TC.second); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.sh.cpp new file mode 100644 index 000000000000..7b3bcc394c8c --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// bool operator<(coroutine_handle<>, coroutine_handle<>) noexcept +// bool operator>(coroutine_handle<>, coroutine_handle<>) noexcept +// bool operator>=(coroutine_handle<>, coroutine_handle<>) noexcept +// bool operator<=(coroutine_handle<>, coroutine_handle<>) noexcept + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test(uintptr_t LHSVal, uintptr_t RHSVal) { + const C LHS = C::from_address(reinterpret_cast(LHSVal)); + const C RHS = C::from_address(reinterpret_cast(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 const TestCases[] = { + {0, 0}, + {16, 16}, + {0, 16}, + {16, 0} + }; + for (auto& TC : TestCases) { + do_test>(TC.first, TC.second); + do_test>(TC.first, TC.second); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.sh.cpp new file mode 100644 index 000000000000..48c3ca50cbf1 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// bool done() const + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test(coro::coroutine_handle 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{}); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.sh.cpp new file mode 100644 index 000000000000..9e7fb5b2f687 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// coroutine_handle& operator=(nullptr_t) noexcept + +#include +#include +#include + +namespace coro = std::experimental; + +template +void do_test() { + int dummy = 42; + void* dummy_h = &dummy; + { + C c; ((void)c); + static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::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>(); + do_test>(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.sh.cpp new file mode 100644 index 000000000000..961253fb7ca5 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// constexpr coroutine_handle() noexcept +// constexpr coroutine_handle(nullptr_t) noexcept + +#include +#include +#include + +namespace coro = std::experimental; + +template +void do_test() { + { + constexpr C c; + static_assert(std::is_nothrow_default_constructible::value, ""); + static_assert(c.address() == nullptr, ""); + } + { + constexpr C c(nullptr); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(c.address() == nullptr, ""); + } + { + C c; + assert(c.address() == nullptr); + } + { + C c(nullptr); + assert(c.address() == nullptr); + } +} + +int main() +{ + do_test>(); + do_test>(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/address.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/address.sh.cpp new file mode 100644 index 000000000000..7258f93905f3 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/address.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// constexpr void* address() const noexcept + +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +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); + } + { + char dummy = 42; + C c = C::from_address((void*)&dummy); + assert(c.address() == &dummy); + } +} + +int main() +{ + do_test>(); + do_test>(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.sh.cpp new file mode 100644 index 000000000000..26a45b033ff5 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.export/from_address.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// static coroutine_handle from_address(void*) noexcept + +#include +#include +#include + +namespace coro = std::experimental; + +template +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::value, ""); + assert(c.address() == nullptr); + } + { + char dummy = 42; + C c = C::from_address((void*)&dummy); + assert(c.address() == &dummy); + } +} + +int main() +{ + do_test>(); + do_test>(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.hash/hash.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.hash/hash.sh.cpp new file mode 100644 index 000000000000..5f66b3e11314 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.hash/hash.sh.cpp @@ -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 + +// + +// template +// struct coroutine_handle; + +// namespace std { +// template struct hash>; +// } + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test(uintptr_t LHSVal, uintptr_t RHSVal) { + const size_t ExpectLHS = std::hash{}(reinterpret_cast(LHSVal)); + const size_t ExpectRHS = std::hash{}(reinterpret_cast(RHSVal)); + const C LHS = C::from_address(reinterpret_cast(LHSVal)); + const C RHS = C::from_address(reinterpret_cast(RHSVal)); + const std::hash 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{}(LHS)); + } +} + +int main() +{ + std::pair const TestCases[] = { + {0, 0}, + {0, 8}, + {8, 8}, + {8, 16} + }; + for (auto& TC : TestCases) { + do_test>(TC.first, TC.second); + do_test>(TC.first, TC.second); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.prom/promise.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.prom/promise.sh.cpp new file mode 100644 index 000000000000..b38d7871be4b --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.prom/promise.sh.cpp @@ -0,0 +1,53 @@ +// -*- 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 + +// + +// template +// struct coroutine_handle; + +// Promise& promise() const + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +void do_test(coro::coroutine_handle&& 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() +{ + do_test(coro::coroutine_handle{}); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.sh.cpp new file mode 100644 index 000000000000..9cc0d1d72bf7 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/destroy.sh.cpp @@ -0,0 +1,65 @@ +// -*- 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 + +// + +// template +// struct coroutine_handle; + +// void destroy() + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + +template +auto has_destroy_imp(H&& h, int) -> decltype(h.destroy(), std::true_type{}); +template +auto has_destroy_imp(H&&, long) -> std::false_type; + +template +constexpr bool has_destroy() { + return decltype(has_destroy_imp(std::declval(), 0))::value; +} + +template +void do_test(coro::coroutine_handle&& H) { + using HType = coro::coroutine_handle; + // FIXME Add a runtime test + { + ASSERT_SAME_TYPE(decltype(H.destroy()), void); + LIBCPP_ASSERT_NOT_NOEXCEPT(H.destroy()); + static_assert(has_destroy(), ""); + static_assert(has_destroy(), ""); + } + { + static_assert(!has_destroy(), ""); + static_assert(!has_destroy(), ""); + } +} + +int main() +{ + do_test(coro::coroutine_handle<>{}); + do_test(coro::coroutine_handle{}); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.sh.cpp new file mode 100644 index 000000000000..b5ff187a49ce --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.resumption/resume.sh.cpp @@ -0,0 +1,84 @@ +// -*- 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 + +// + +// template +// struct coroutine_handle; + +// void operator()() +// void resume() + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace coro = std::experimental; + + +template +auto has_resume_imp(H&& h, int) -> decltype(h.resume(), std::true_type{}); +template +auto has_resume_imp(H&&, long) -> std::false_type; + +template +constexpr bool has_resume() { + return decltype(has_resume_imp(std::declval(), 0))::value; +} + + +template +auto has_call_operator_imp(H&& h, int) -> decltype(h(), std::true_type{}); +template +auto has_call_operator_imp(H&&, long) -> std::false_type; + +template +constexpr bool has_call_operator() { + return decltype(has_call_operator_imp(std::declval(), 0))::value; +} + +template +void do_test(coro::coroutine_handle&& H) { + using HType = coro::coroutine_handle; + // 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(), ""); + static_assert(has_resume(), ""); + static_assert(has_call_operator(), ""); + static_assert(has_call_operator(), ""); + } + { + static_assert(!has_resume(), ""); + static_assert(!has_resume(), ""); + static_assert(!has_call_operator(), ""); + static_assert(!has_call_operator(), ""); + } +} + +int main() +{ + do_test(coro::coroutine_handle<>{}); + do_test(coro::coroutine_handle{}); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/void_handle.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/void_handle.sh.cpp new file mode 100644 index 000000000000..945304a4673d --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/void_handle.sh.cpp @@ -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 + +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 + struct coroutine_traits<::B, Args...> { + using promise_type = B*; + }; + template <> + struct coroutine_traits<::C> { + using promise_type = void; + }; +}} + +template +void check_type() { + using P = typename coro::coroutine_traits::promise_type ; + static_assert(std::is_same::value, ""); +}; + +int main() +{ + check_type(); + check_type(); + check_type(); + check_type(); +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.traits/promise_type.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.traits/promise_type.sh.cpp new file mode 100644 index 000000000000..c1d3b818d403 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.traits/promise_type.sh.cpp @@ -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 + +namespace coro = std::experimental; + +template +constexpr bool has_promise_type(int) { return true; } +template +constexpr bool has_promise_type(long) { return false; } +template +constexpr bool has_promise_type() { return has_promise_type(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 + struct coroutine_traits<::B, Args...> { + using promise_type = B*; + }; + template <> + struct coroutine_traits<::C> { + using promise_type = void; + }; +}} + +template +void check_type() { + using Traits = coro::coroutine_traits; + static_assert(has_promise_type(), ""); + static_assert(std::is_same::value, ""); +} + +template +void check_no_type() { + using Traits = coro::coroutine_traits; + static_assert(!has_promise_type(), ""); +} + +int main() +{ + { + check_type(); + check_type(); + check_type(); + check_type(); + } + { + check_no_type(); + check_no_type(); + check_no_type(); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.sh.cpp new file mode 100644 index 000000000000..1987f68e70ab --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_always.sh.cpp @@ -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 +#include +#include + +#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::value, ""); + assert(s.await_ready() == false); + assert(cs.await_ready() == false); + } + { + LIBCPP_STATIC_ASSERT(noexcept(s.await_suspend(h)), ""); + static_assert(std::is_same::value, ""); + s.await_suspend(h); + cs.await_suspend(h); + } + { + LIBCPP_STATIC_ASSERT(noexcept(s.await_resume()), ""); + static_assert(std::is_same::value, ""); + s.await_resume(); + cs.await_resume(); + } + { + static_assert(std::is_nothrow_default_constructible::value, ""); + static_assert(std::is_nothrow_copy_constructible::value, ""); + static_assert(std::is_nothrow_move_constructible::value, ""); + static_assert(std::is_nothrow_copy_assignable::value, ""); + static_assert(std::is_nothrow_move_assignable::value, ""); + static_assert(std::is_trivially_copyable::value, ""); + static_assert(check_suspend_constexpr(), ""); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.sh.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.sh.cpp new file mode 100644 index 000000000000..72e0ac024558 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/coroutine.trivial.awaitables/suspend_never.sh.cpp @@ -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 +#include +#include + +#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::value, ""); + assert(s.await_ready() == true); + assert(cs.await_ready() == true); + } + { + LIBCPP_STATIC_ASSERT(noexcept(s.await_suspend(h)), ""); + static_assert(std::is_same::value, ""); + s.await_suspend(h); + cs.await_suspend(h); + } + { + LIBCPP_STATIC_ASSERT(noexcept(s.await_resume()), ""); + static_assert(std::is_same::value, ""); + s.await_resume(); + cs.await_resume(); + } + { + static_assert(std::is_nothrow_default_constructible::value, ""); + static_assert(std::is_nothrow_copy_constructible::value, ""); + static_assert(std::is_nothrow_move_constructible::value, ""); + static_assert(std::is_nothrow_copy_assignable::value, ""); + static_assert(std::is_nothrow_move_assignable::value, ""); + static_assert(std::is_trivially_copyable::value, ""); + static_assert(check_suspend_constexpr(), ""); + } +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp new file mode 100644 index 000000000000..cca875d1a6ba --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp @@ -0,0 +1,72 @@ +// -*- 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 +#include + +using namespace std::experimental; + +struct coro_t { + struct promise_type { + coro_t get_return_object() { + coroutine_handle{}; + return {}; + } + suspend_never initial_suspend() { return {}; } + suspend_never final_suspend() { return {}; } + void return_void(){} + static void unhandled_exception() {} + }; +}; + +struct B { + ~B() {} + bool await_ready() { return true; } + B await_resume() { return {}; } + template void await_suspend(F) {} +}; + + +struct A { + ~A(){} + bool await_ready() { return true; } + int await_resume() { return 42; } + template 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{}; + set_value(42); +} + +coro_t g() { B val = co_await B{}; } + +int main() { + last_value = -1; + f(0); + assert(last_value == 0); + f(1); + assert(last_value == 42); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp new file mode 100644 index 000000000000..e51ac67f0fef --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp @@ -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 + +// FIXME: When run under UBSAN this test hits an assertion inside Clang +// XFAIL: ubsan + +// RUN: %build -fcoroutines-ts +// RUN: %run + +#include +#include + +using namespace std::experimental; + +struct coro_t { + struct promise_type { + coro_t get_return_object() { + return coroutine_handle::from_promise(*this); + } + suspend_never initial_suspend() { return {}; } + suspend_never final_suspend() { return {}; } + void return_void(){} + void unhandled_exception() {} + }; + coro_t(coroutine_handle hh) : h(hh) {} + coroutine_handle h; +}; + +struct NoSuspend { + bool await_ready() { return false; } + void await_resume() {} + template bool await_suspend(F) { return false; } +}; + +struct DoSuspend { + bool await_ready() { return false; } + void await_resume() {} + template 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() { + 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); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp new file mode 100644 index 000000000000..b6832b0c1886 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp @@ -0,0 +1,93 @@ +// -*- 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 +#include +using namespace std::experimental; + +struct error {}; + +template +struct expected { + + struct Data { + T val; + Error error; + }; + Data data; + + struct DataPtr { + Data *p; + ~DataPtr() { delete p; } + }; + + expected() {} + expected(T val) : data{std::move(val),{}} {} + expected(struct error, Error error) : data{{}, std::move(error)} {} + expected(DataPtr & p) : data{std::move(p.p->val), std::move(p.p->error)} {} + + struct promise_type { + Data* data; + DataPtr get_return_object() { data = new Data{}; return {data}; } + suspend_never initial_suspend() { return {}; } + suspend_never final_suspend() { return {}; } + void return_value(T v) { data->val = std::move(v); data->error = {};} + void unhandled_exception() {} + }; + + bool await_ready() { return !data.error; } + T await_resume() { return std::move(data.val); } + void await_suspend(coroutine_handle h) { + h.promise().data->error =std::move(data.error); + h.destroy(); + } + + T const& value() { return data.val; } + Error const& error() { return data.error; } +}; + +expected g() { return {0}; } +expected h() { return {error{}, 42}; } + +extern "C" void print(int); + +bool f1_started, f1_resumed = false; +expected f1() { + f1_started = true; + (void)(co_await g()); + f1_resumed = true; + co_return 100; +} + +bool f2_started, f2_resumed = false; +expected f2() { + f2_started = true; + (void)(co_await h()); + f2_resumed = true; + co_return 200; +} + +int main() { + 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); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp new file mode 100644 index 000000000000..c7e34fe919e1 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp @@ -0,0 +1,120 @@ +// -*- 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 +#include + +#include "test_macros.h" + +using namespace std::experimental; + +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; } +#if TEST_STD_VER > 14 + Noisy(Noisy const&) = delete; +#else + // FIXME: This test depends on copy elision taking place in C++14 + // (pre-c++17 guaranteed copy elision) + Noisy(Noisy const&); +#endif +}; + +struct Bug { + bool await_ready() { return true; } + void await_suspend(std::experimental::coroutine_handle<>) {} + Noisy await_resume() { return {}; } +}; +struct coro2 { + struct promise_type { + suspend_never initial_suspend() { return{}; } + suspend_never final_suspend() { 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); + } + 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() { + a(); + b(); + c(); + d(); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp new file mode 100644 index 000000000000..4681793ed814 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp @@ -0,0 +1,107 @@ +// -*- 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 + +// FIXME: When run under UBSAN this test hits an assertion inside Clang +// XFAIL: ubsan + +// RUN: %build -fcoroutines-ts +// RUN: %run + +#include +#include +#include + +#include "coroutine_types.h" + +using namespace std::experimental; + +struct minig { + struct promise_type { + int current_value; + suspend_always yield_value(int value) { + this->current_value = value; + return {}; + } + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { 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 *p) + : p(coroutine_handle::from_promise(*p)) {} + + coroutine_handle p; +}; + + +minig mini_count(int n) { + for (int i = 0; i < n; i++) { + co_yield i; + } +} + +generator count(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +generator range(int from, int n) { + for (int i = from; i < n; ++i) + co_yield i; +} + +void test_count() { + const std::vector expect = {0, 1, 2, 3, 4}; + std::vector 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() { + test_count(); + test_range(); + test_mini_generator(); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp new file mode 100644 index 000000000000..e0d69104fdaf --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp @@ -0,0 +1,182 @@ +// -*- 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 +#include + +using namespace std::experimental; + +bool cancel = false; + +struct goroutine +{ + static int const N = 10; + static int count; + static coroutine_handle<> stack[N]; + + static void schedule(coroutine_handle<>& rh) + { + assert(count < N); + stack[count++] = rh; + rh = nullptr; + } + + ~goroutine() {} + + static void go(goroutine) {} + + static void run_one() + { + assert(count > 0); + stack[--count](); + } + + struct promise_type + { + suspend_never initial_suspend() { + return {}; + } + suspend_never final_suspend() { + return {}; + } + void return_void() {} + goroutine get_return_object() { + return{}; + } + void unhandled_exception() {} + }; +}; +int goroutine::count; +coroutine_handle<> goroutine::stack[N]; + +coroutine_handle workaround; + +class channel; + +struct push_awaiter { + channel* ch; + bool await_ready() {return false; } + void await_suspend(coroutine_handle<> rh); + void await_resume() {} +}; + +struct pull_awaiter { + channel * ch; + + bool await_ready(); + void await_suspend(coroutine_handle<> rh); + int await_resume(); +}; + +class channel +{ + using T = int; + + friend struct push_awaiter; + friend struct pull_awaiter; + + T const* pvalue = nullptr; + coroutine_handle<> reader = nullptr; + 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(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(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; //100'000'000; +const int repeat = 1; + +channel* c = new channel[N + 1]; + +int main() { + for (int i = 0; i < N; ++i) + goroutine::go(pusher(c[i], c[i + 1])); + + c[0].sync_push(0); + int result = c[N].sync_pull(); + + assert(result == 100); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp new file mode 100644 index 000000000000..e13196c253ea --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp @@ -0,0 +1,91 @@ +// -*- 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 +#include + +using namespace std::experimental; + +// This file tests, multishot, movable std::function like thing using coroutine +// for compile-time type erasure and unerasure. +template struct func { + struct Input {R a, b;}; + + struct promise_type { + Input* I; + R result; + func get_return_object() { return {this}; } + suspend_always initial_suspend() { return {}; } + suspend_never final_suspend() { return {}; } + void return_void() {} + template + 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 static func Create(F f) { + for (;;) { + co_yield f; + } + } + + template func(F f) : func(Create(f)) {} + + ~func() { + if (h) + h.destroy(); + } + +private: + func(promise_type *promise) + : h(coroutine_handle::from_promise(*promise)) {} + coroutine_handle h; +}; + +int Do(int acc, int n, func f) { + for (int i = 0; i < n; ++i) + acc = f({acc, i}); + return acc; +} + +int main() { + int result = Do(1, 10, [](int a, int b) {return a + b;}); + assert(result == 46); +} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp new file mode 100644 index 000000000000..9c94f73b2a70 --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp @@ -0,0 +1,87 @@ +// -*- 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 +#include +#include + +using namespace std::experimental; + +// This file tests, one shot, movable std::function like thing using coroutine +// for compile-time type erasure and unerasure. + +template struct func { + struct promise_type { + R result; + func get_return_object() { return {this}; } + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { 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 static func Create(F f) { co_return f(); } + + template func(F f) : func(Create(f)) {} + + ~func() { + if (h) + h.destroy(); + } + +private: + func(promise_type *promise) + : h(coroutine_handle::from_promise(*promise)) {} + coroutine_handle h; +}; + +std::vector yielded_values = {}; +int yield(int x) { yielded_values.push_back(x); return x + 1; } +float fyield(int x) { yielded_values.push_back(x); return x + 2; } + +void Do1(func f) { yield(f()); } +void Do2(func f) { yield(f()); } + +int main() { + Do1([] { return yield(43); }); + assert((yielded_values == std::vector{43, 44})); + + yielded_values = {}; + Do2([] { return fyield(44); }); + assert((yielded_values == std::vector{44, 46})); +} diff --git a/test/std/experimental/language.support/support.coroutines/includes.sh.cpp b/test/std/experimental/language.support/support.coroutines/includes.sh.cpp new file mode 100644 index 000000000000..f9d8a572256c --- /dev/null +++ b/test/std/experimental/language.support/support.coroutines/includes.sh.cpp @@ -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 + +// + +// Test that includes + +#include + + + +int main(){ + // std::nothrow is not implicitly defined by the compiler when the include is + // missing, unlike other parts of . Therefore we use std::nothrow to + // test for #include + (void)std::nothrow; + +} diff --git a/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp index 8de5fc7bab85..31add9df27a4 100644 --- a/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp @@ -24,6 +24,7 @@ test(S s, typename S::difference_type pos, S expected) typename S::const_iterator p = s.begin() + pos; typename S::iterator i = s.erase(p); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); assert(i - s.begin() == pos); } diff --git a/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp index e4fe2cdfd022..858d3754e9da 100644 --- a/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp @@ -25,6 +25,7 @@ test(S s, typename S::difference_type pos, typename S::difference_type n, S expe typename S::const_iterator last = s.cbegin() + pos + n; typename S::iterator i = s.erase(first, last); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); assert(i - s.begin() == pos); } diff --git a/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp index 64f8e506b13e..8424b5429cea 100644 --- a/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp @@ -23,6 +23,7 @@ test(S s, S expected) { s.pop_back(); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); } diff --git a/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp index eb6be202a350..2c900bb315bc 100644 --- a/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp @@ -29,6 +29,7 @@ test(S s, typename S::size_type pos, typename S::size_type n, S expected) { s.erase(pos, n); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); } #ifndef TEST_HAS_NO_EXCEPTIONS @@ -58,6 +59,7 @@ test(S s, typename S::size_type pos, S expected) { s.erase(pos); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); } #ifndef TEST_HAS_NO_EXCEPTIONS @@ -83,6 +85,7 @@ test(S s, S expected) { s.erase(); LIBCPP_ASSERT(s.__invariants()); + assert(s[s.size()] == typename S::value_type()); assert(s == expected); } diff --git a/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp b/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp index 4e73d8064317..82d63ecada48 100644 --- a/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp +++ b/test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp @@ -39,6 +39,7 @@ void test_no_inner_alloc() using SA = std::scoped_allocator_adaptor; static_assert(std::uses_allocator >::value, ""); Pair * ptr = (Pair*)std::malloc(sizeof(Pair)); + assert(ptr); Alloc CA(P); SA A(CA); A.construct(ptr); @@ -61,6 +62,7 @@ void test_no_inner_alloc() using SA = std::scoped_allocator_adaptor; static_assert(std::uses_allocator >::value, ""); Pair * ptr = (Pair*)std::malloc(sizeof(Pair)); + assert(ptr); Alloc CA(P); SA A(CA); A.construct(ptr); @@ -77,7 +79,6 @@ void test_no_inner_alloc() void test_with_inner_alloc() { - using VoidAlloc1 = CountingAllocator; using VoidAlloc2 = CountingAllocator; AllocController POuter; @@ -93,6 +94,7 @@ void test_with_inner_alloc() static_assert(!std::uses_allocator::value, ""); static_assert(std::uses_allocator::value, ""); Pair * ptr = (Pair*)std::malloc(sizeof(Pair)); + assert(ptr); Outer O(POuter); Inner I(PInner); SA A(O, I); @@ -119,6 +121,7 @@ void test_with_inner_alloc() static_assert(!std::uses_allocator::value, ""); static_assert(std::uses_allocator::value, ""); Pair * ptr = (Pair*)std::malloc(sizeof(Pair)); + assert(ptr); Outer O(POuter); Inner I(PInner); SA A(O, I); diff --git a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp index 2a7ac9979d02..f8f73f771356 100644 --- a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp +++ b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp @@ -45,6 +45,25 @@ struct Foo virtual ~Foo() = default; }; +#ifdef _LIBCPP_VERSION +struct Result {}; +static Result theFunction() { return Result(); } +static int resultDeletorCount; +static void resultDeletor(Result (*pf)()) { + assert(pf == theFunction); + ++resultDeletorCount; +} + +void test_pointer_to_function() { + { // https://bugs.llvm.org/show_bug.cgi?id=27566 + std::shared_ptr x(&theFunction, &resultDeletor); + std::shared_ptr y(theFunction, resultDeletor); + } + assert(resultDeletorCount == 2); +} +#else // _LIBCPP_VERSION +void test_pointer_to_function() {} +#endif // _LIBCPP_VERSION int main() { @@ -66,6 +85,8 @@ int main() assert(p2.get()); } + test_pointer_to_function(); + #if TEST_STD_VER >= 11 nc = globalMemCounter.outstanding_new; { diff --git a/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp index 76c1fb82b866..6b4283a2854b 100644 --- a/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp @@ -32,6 +32,16 @@ void test(InitArgs&&... args) assert(*lhs == *rhs); } +template +constexpr bool constexpr_test(InitArgs&&... args) +{ + static_assert( std::is_trivially_copy_constructible_v, ""); // requirement + const optional rhs(std::forward(args)...); + optional lhs = rhs; + return (lhs.has_value() == rhs.has_value()) && + (lhs.has_value() ? *lhs == *rhs : true); +} + void test_throwing_ctor() { #ifndef TEST_HAS_NO_EXCEPTIONS struct Z { @@ -108,6 +118,9 @@ int main() { test(); test(3); + static_assert(constexpr_test(), "" ); + static_assert(constexpr_test(3), "" ); + { const optional o(42); optional o2(o); diff --git a/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp index 09aaa0561b51..82acdd9d7758 100644 --- a/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp @@ -41,6 +41,17 @@ void test(InitArgs&&... args) assert(*lhs == *orig); } +template +constexpr bool constexpr_test(InitArgs&&... args) +{ + static_assert( std::is_trivially_copy_constructible_v, ""); // requirement + const optional orig(std::forward(args)...); + optional rhs(orig); + optional lhs = std::move(rhs); + return (lhs.has_value() == orig.has_value()) && + (lhs.has_value() ? *lhs == *orig : true); +} + void test_throwing_ctor() { #ifndef TEST_HAS_NO_EXCEPTIONS struct Z { @@ -144,6 +155,9 @@ int main() { test(); test(3); + static_assert(constexpr_test(), "" ); + static_assert(constexpr_test(3), "" ); + { optional o(42); optional o2(std::move(o)); diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp index a695df14ef62..3b20c369c638 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -149,7 +149,7 @@ constexpr bool test_constexpr_copy_ctor_extension_imp( } void test_constexpr_copy_ctor_extension() { -#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER) + // NOTE: This test is for not yet standardized behavior. using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -163,7 +163,6 @@ void test_constexpr_copy_ctor_extension() { static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); -#endif } int main() { diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp index b8ca6f9ef27a..a5de1f77334e 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -186,7 +186,7 @@ constexpr bool test_constexpr_ctor_extension_imp( } void test_constexpr_move_ctor_extension() { -#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER) + // NOTE: This test is for not yet standardized behavior. using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -201,7 +201,6 @@ void test_constexpr_move_ctor_extension() { static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), ""); -#endif } int main() { diff --git a/test/support/coroutine_types.h b/test/support/coroutine_types.h new file mode 100644 index 000000000000..f592bedca7f2 --- /dev/null +++ b/test/support/coroutine_types.h @@ -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. +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_COROUTINE_TYPES_H +#define SUPPORT_COROUTINE_TYPES_H + +#include + +template 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() { return {}; } + generator get_return_object() { return generator{this}; }; + void return_void() {} + void unhandled_exception() {} + }; + + struct iterator { + std::experimental::coroutine_handle _Coro; + bool _Done; + + iterator(std::experimental::coroutine_handle 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::from_promise(*p)) {} + + std::experimental::coroutine_handle p; +}; + +#endif // SUPPORT_COROUTINE_TYPES_H diff --git a/test/support/poisoned_hash_helper.hpp b/test/support/poisoned_hash_helper.hpp index 824c35837b2b..6f42ebf8b480 100644 --- a/test/support/poisoned_hash_helper.hpp +++ b/test/support/poisoned_hash_helper.hpp @@ -50,10 +50,8 @@ namespace PoisonedHashDetail { // specializations of hash for nullptr t and all cv-unqualified // arithmetic, enumeration, and pointer types. using LibraryHashTypes = TypeList< -#if !defined(TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR) #if TEST_STD_VER > 14 decltype(nullptr), -#endif #endif bool, char, diff --git a/test/support/test.workarounds/c1xx_broken_nullptr_conversion_operator.pass.cpp b/test/support/test.workarounds/c1xx_broken_nullptr_conversion_operator.pass.cpp deleted file mode 100644 index 250d06d2b902..000000000000 --- a/test/support/test.workarounds/c1xx_broken_nullptr_conversion_operator.pass.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 - -// Verify TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR. - -#include - -#include "test_workarounds.h" - -struct ConvertsToNullptr { - using DestType = decltype(nullptr); - operator DestType() const { return nullptr; } -}; - -int main() { -#if defined(TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR) - static_assert(!std::is_convertible::value, ""); -#else - static_assert(std::is_convertible::value, ""); -#endif -} diff --git a/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp b/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp new file mode 100644 index 000000000000..f25a9c9984cc --- /dev/null +++ b/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Verify TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION. + +#include + +#include "test_workarounds.h" + +template +struct identity { + using type = T; +}; + +template struct list {}; + +// C1XX believes this function template is not viable when LArgs is an empty +// parameter pack. +template +int f2(typename identity::type..., int i) { + return i; +} + +#ifdef TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION +// C1XX believes this function template *is* viable when LArgs is an empty +// parameter pack. Conforming compilers believe the two overloads are +// ambiguous when LArgs is an empty pack. +template +int f2(int i) { + return i; +} +#endif + +template +int f1(list, Args&&... args) { + return f2(args...); +} + +int main() { + f1(list<>{}, 42); +} diff --git a/test/support/test_macros.h b/test/support/test_macros.h index 6b573d40fe68..637686284ed2 100644 --- a/test/support/test_macros.h +++ b/test/support/test_macros.h @@ -154,6 +154,12 @@ #define TEST_NORETURN [[noreturn]] #endif +#if defined(_LIBCPP_SAFE_STATIC) +#define TEST_SAFE_STATIC _LIBCPP_SAFE_STATIC +#else +#define TEST_SAFE_STATIC +#endif + #if TEST_STD_VER < 11 #define ASSERT_NOEXCEPT(...) #define ASSERT_NOT_NOEXCEPT(...) diff --git a/test/support/test_workarounds.h b/test/support/test_workarounds.h index 614cec7aab86..ae123d7e41d0 100644 --- a/test/support/test_workarounds.h +++ b/test/support/test_workarounds.h @@ -14,14 +14,14 @@ #include "test_macros.h" #if defined(TEST_COMPILER_EDG) -# define TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR +# define TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR // VSO#424280 #endif #if defined(TEST_COMPILER_C1XX) -# define TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR -# define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +# define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE // VSO#117743 +# define TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION // VSO#109062 # ifndef _MSC_EXTENSIONS -# define TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK +# define TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK // VSO#119998 # endif #endif diff --git a/test/support/uses_alloc_types.hpp b/test/support/uses_alloc_types.hpp index 8422f809ba76..7f92f0fd19c7 100644 --- a/test/support/uses_alloc_types.hpp +++ b/test/support/uses_alloc_types.hpp @@ -15,6 +15,7 @@ #include #include "test_macros.h" +#include "test_workarounds.h" #include "type_id.h" // There are two forms of uses-allocator construction: @@ -256,6 +257,13 @@ struct UsesAllocatorTestBase { return alloc; } +#ifdef TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION + template + static CtorAlloc getAllocatorFromPackImp(CtorAlloc const& alloc) { + return alloc; + } +#endif + bool has_alloc() const { return alloc_store.get_allocator() != nullptr; } const CtorAlloc *get_alloc() const { return alloc_store.get_allocator(); } public: diff --git a/utils/libcxx/test/config.py b/utils/libcxx/test/config.py index 2118f9c7eb90..1bf2677a8509 100644 --- a/utils/libcxx/test/config.py +++ b/utils/libcxx/test/config.py @@ -142,6 +142,7 @@ def configure(self): self.configure_sanitizer() self.configure_coverage() self.configure_modules() + self.configure_coroutines() self.configure_substitutions() self.configure_features() @@ -954,6 +955,18 @@ def configure_coverage(self): self.cxx.flags += ['-g', '--coverage'] self.cxx.compile_flags += ['-O0'] + def configure_coroutines(self): + if self.cxx.hasCompileFlag('-fcoroutines-ts'): + macros = self.cxx.dumpMacros(flags=['-fcoroutines-ts']) + if '__cpp_coroutines' not in macros: + self.lit_config.warning('-fcoroutines-ts is supported but ' + '__cpp_coroutines is not defined') + # Consider coroutines supported only when the feature test macro + # reflects a recent value. + val = macros['__cpp_coroutines'].replace('L', '') + if int(val) >= 201703: + self.config.available_features.add('fcoroutines-ts') + def configure_modules(self): modules_flags = ['-fmodules'] if platform.system() != 'Darwin': diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index 101ad43212e5..80b53021c1f0 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -71,13 +71,13 @@ N4366LWGLWG 2228 missing SFINAE ruleLenexaComplete3.1 N4510LWGMinimal incomplete type support for standard containers, revision 4LenexaComplete3.6 - P0004R1LWGRemove Deprecated iostreams aliases.KonaComplete3.8 + P0004R1LWGRemove Deprecated iostreams aliases.KonaComplete3.8 P0006R0LWGAdopt Type Traits Variable Templates for C++17.KonaComplete3.8 - P0092R1LWGPolishing <chrono>KonaComplete3.8 - P0007R1LWGConstant View: A proposal for a std::as_const helper function template.KonaComplete3.8 + P0092R1LWGPolishing <chrono>KonaComplete3.8 + P0007R1LWGConstant View: A proposal for a std::as_const helper function template.KonaComplete3.8 P0156R0LWGVariadic lock_guard(rev 3).KonaReverted in Kona3.9 - P0074R0LWGMaking std::owner_less more flexibleKonaComplete3.8 - P0013R1LWGLogical type traits rev 2KonaComplete3.8 + P0074R0LWGMaking std::owner_less more flexibleKonaComplete3.8 + P0013R1LWGLogical type traits rev 2KonaComplete3.8 P0024R2LWGThe Parallelism TS Should be StandardizedJacksonville P0226R1LWGMathematical Special Functions for C++17Jacksonville @@ -444,7 +444,7 @@ 2787§[file_status.cons] doesn't match class definitionKonaComplete 2788basic_string range mutators unintentionally require a default constructible allocatorKonaComplete 2789Equivalence of contained objectsKonaComplete - 2790Missing specification of istreambuf_iterator::operator->Kona + 2790Missing specification of istreambuf_iterator::operator->KonaComplete 2794Missing requirements for allocator pointersKona 2795§[global.functions] provides incorrect example of ADL useKonaComplete 2796tuple should be a literal typeKonaComplete @@ -475,7 +475,7 @@ 2876shared_ptr::shared_ptr(const weak_ptr<Y>&) constructor should be constrainedKona 2878Missing DefaultConstructible requirement for istream_iterator default constructorKona 2890The definition of 'object state' applies only to class typesKonaComplete - 2900The copy and move constructors of optional are not constexprKona + 2900The copy and move constructors of optional are not constexprKonaComplete 2903The form of initialization for the emplace-constructors is not specifiedKona 2904Make variant move-assignment more exception safeKona 2905is_constructible_v<unique_ptr<P, D>, P, D const &> should be false when D is not copy constructibleKonaComplete @@ -489,7 +489,7 @@ -

Last Updated: 11-May-2017

+

Last Updated: 25-May-2017