diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index dfb026bd2..4d03fa0e1 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/complex ${CMAKE_CURRENT_LIST_DIR}/inc/concepts ${CMAKE_CURRENT_LIST_DIR}/inc/condition_variable + ${CMAKE_CURRENT_LIST_DIR}/inc/coroutine ${CMAKE_CURRENT_LIST_DIR}/inc/csetjmp ${CMAKE_CURRENT_LIST_DIR}/inc/csignal ${CMAKE_CURRENT_LIST_DIR}/inc/cstdalign diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index 680c38d4a..c7aaea945 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/stl/inc/coroutine b/stl/inc/coroutine new file mode 100644 index 000000000..af9428c28 --- /dev/null +++ b/stl/inc/coroutine @@ -0,0 +1,169 @@ +// coroutine standard header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#ifndef _COROUTINE_ +#define _COROUTINE_ +#include +#if _STL_COMPILER_PREPROCESSOR + +#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED +#pragma message("The contents of are not available with /await.") +#pragma message("Remove /await for standard coroutines or use for legacy /await support.") +#else // ^^^ /await ^^^ / vvv no /await vvv +#ifndef __cpp_lib_coroutine +#pragma message("The contents of are available only with C++20 or later.") +#else // ^^^ __cpp_lib_coroutine not defined / __cpp_lib_coroutine defined vvv +#ifndef _ALLOW_COROUTINE_ABI_MISMATCH +#pragma detect_mismatch("_COROUTINE_ABI", "2") +#endif // _ALLOW_COROUTINE_ABI_MISMATCH + +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN + +// STRUCT TEMPLATE coroutine_traits +template +struct _Coroutine_traits {}; + +template +struct _Coroutine_traits<_Ret, void_t> { + using promise_type = typename _Ret::promise_type; +}; + +template +struct coroutine_traits : _Coroutine_traits<_Ret> {}; + +// STRUCT TEMPLATE coroutine_handle +template +struct coroutine_handle; + +template <> +struct coroutine_handle { + constexpr coroutine_handle() noexcept = default; + constexpr coroutine_handle(nullptr_t) noexcept {} + + coroutine_handle& operator=(nullptr_t) noexcept { + _Ptr = nullptr; + return *this; + } + + _NODISCARD constexpr void* address() const noexcept { + return _Ptr; + } + + _NODISCARD static constexpr coroutine_handle from_address(void* const _Addr) noexcept { // strengthened + coroutine_handle _Result; + _Result._Ptr = _Addr; + return _Result; + } + + constexpr explicit operator bool() const noexcept { + return _Ptr != nullptr; + } + + _NODISCARD bool done() const noexcept { // strengthened + return __builtin_coro_done(_Ptr); + } + + void operator()() const noexcept { // strengthened + __builtin_coro_resume(_Ptr); + } + + void resume() const noexcept { // strengthened + __builtin_coro_resume(_Ptr); + } + + void destroy() const noexcept { // strengthened + __builtin_coro_destroy(_Ptr); + } + +protected: + void* _Ptr = nullptr; +}; + +template +struct coroutine_handle : coroutine_handle<> { + using coroutine_handle<>::coroutine_handle; + + _NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened + const auto _Prom_ptr = const_cast(static_cast(_STD addressof(_Prom))); + const auto _Frame_ptr = __builtin_coro_promise(_Prom_ptr, 0, true); + coroutine_handle _Result; + _Result._Ptr = _Frame_ptr; + return _Result; + } + + coroutine_handle& operator=(nullptr_t) noexcept { + _Ptr = nullptr; + return *this; + } + + _NODISCARD static constexpr coroutine_handle from_address(void* const _Addr) noexcept { // strengthened + coroutine_handle _Result; + _Result._Ptr = _Addr; + return _Result; + } + + _NODISCARD _Promise& promise() const noexcept { // strengthened + return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false)); + } +}; + +_NODISCARD constexpr bool operator==(const coroutine_handle<> _Left, const coroutine_handle<> _Right) noexcept { + return _Left.address() == _Right.address(); +} + +_NODISCARD constexpr strong_ordering operator<=>( + const coroutine_handle<> _Left, const coroutine_handle<> _Right) noexcept { + return compare_three_way()(_Left.address(), _Right.address()); +} + +template +struct hash> { + _NODISCARD size_t operator()(const coroutine_handle<_Promise>& _Coro) noexcept { + return _Hash_representation(_Coro.address()); + } +}; + +// STRUCT suspend_never +struct suspend_never { + _NODISCARD constexpr bool await_ready() const noexcept { + return true; + } + + constexpr void await_suspend(coroutine_handle<>) const noexcept {} + constexpr void await_resume() const noexcept {} +}; + +// STRUCT suspend_always +struct suspend_always { + _NODISCARD constexpr bool await_ready() const noexcept { + return false; + } + + constexpr void await_suspend(coroutine_handle<>) const noexcept {} + constexpr void await_resume() const noexcept {} +}; + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // __cpp_lib_coroutine +#endif // _RESUMABLE_FUNCTIONS_SUPPORTED +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _COROUTINE_ diff --git a/stl/inc/experimental/generator b/stl/inc/experimental/generator index d6884848e..af54662c1 100644 --- a/stl/inc/experimental/generator +++ b/stl/inc/experimental/generator @@ -9,14 +9,19 @@ #include #if _STL_COMPILER_PREPROCESSOR -#ifndef __cpp_coroutines -#error requires /std:c++latest or /await compiler option -#endif // __cpp_coroutines +#if !defined(__cpp_coroutines) && !defined(__cpp_impl_coroutine) +#error requires /std:c++latest or /await compiler options +#endif // !defined(__cpp_coroutines) && !defined(__cpp_impl_coroutine) #ifdef _CPPUNWIND #include #endif +#include +#ifdef __cpp_coroutines #include +#else // __cpp_coroutines +#include +#endif // __cpp_coroutines #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) diff --git a/stl/inc/experimental/resumable b/stl/inc/experimental/resumable index b05684342..78c3b317c 100644 --- a/stl/inc/experimental/resumable +++ b/stl/inc/experimental/resumable @@ -31,6 +31,11 @@ support Clang. You can define _SILENCE_CLANG_COROUTINE_MESSAGE to silence this m unsupported. #endif // defined(__clang__) && !defined(_SILENCE_CLANG_COROUTINE_MESSAGE) +#if defined(_MSC_VER) && defined(__cpp_impl_coroutine) +#error The and headers are only supported \ +with /await and implement pre-C++20 coroutine support. Use for standard C++20 coroutines. +#endif // defined(_MSC_VER) && defined(__cpp_impl_coroutine) + // intrinsics used in implementation of coroutine_handle extern "C" size_t _coro_resume(void*); extern "C" void _coro_destroy(void*); @@ -39,6 +44,10 @@ extern "C" size_t _coro_done(void*); #pragma intrinsic(_coro_destroy) #pragma intrinsic(_coro_done) +#ifndef _ALLOW_COROUTINE_ABI_MISMATCH +#pragma detect_mismatch("_COROUTINE_ABI", "1") +#endif // _ALLOW_COROUTINE_ABI_MISMATCH + _STD_BEGIN namespace experimental { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 3b581162c..621299458 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -170,6 +170,8 @@ // P0896R4 Ranges // (partially implemented) // P0898R3 Standard Library Concepts +// P0912R5 Library Support For Coroutines +// (partially implemented, missing noop coroutines) // P0919R3 Heterogeneous Lookup For Unordered Containers // P0966R1 string::reserve() Should Not Shrink // P1006R1 constexpr For pointer_traits::pointer_to() @@ -1164,6 +1166,10 @@ #define __cpp_lib_constexpr_tuple 201811L #define __cpp_lib_constexpr_utility 201811L +#ifdef __cpp_impl_coroutine // TRANSITION, VS 2019 16.8 Preview 1 +#define __cpp_lib_coroutine 197000L +#endif // __cpp_impl_coroutine + #ifdef __cpp_impl_destroying_delete #define __cpp_lib_destroying_delete 201806L #endif // __cpp_impl_destroying_delete diff --git a/tests/std/tests/VSO_0971246_legacy_await_headers/env.lst b/tests/std/tests/VSO_0971246_legacy_await_headers/env.lst index 2bde643ff..ce95e6d28 100644 --- a/tests/std/tests/VSO_0971246_legacy_await_headers/env.lst +++ b/tests/std/tests/VSO_0971246_legacy_await_headers/env.lst @@ -3,7 +3,8 @@ RUNALL_INCLUDE ..\prefix.lst RUNALL_CROSSLIST -PM_CL="/EHsc /MT /d1await:strict /std:c++latest" +# PM_CL="/EHsc /MT /std:c++latest" # TRANSITION, VS 2019 16.8 Preview 1 PM_CL="/EHsc /MT /await /std:c++latest" PM_CL="/BE /c /EHsc /MD /await /std:c++latest /permissive-" PM_CL="/BE /c /EHsc /MD /await /std:c++latest" +PM_CL="/BE /c /EHsc /MD /std:c++latest" diff --git a/tests/std/tests/include_each_header_alone_matrix.lst b/tests/std/tests/include_each_header_alone_matrix.lst index 57333f82e..c1ee9bf14 100644 --- a/tests/std/tests/include_each_header_alone_matrix.lst +++ b/tests/std/tests/include_each_header_alone_matrix.lst @@ -18,6 +18,7 @@ PM_CL="/DMEOW_HEADER=compare" PM_CL="/DMEOW_HEADER=complex" PM_CL="/DMEOW_HEADER=concepts" PM_CL="/DMEOW_HEADER=condition_variable" +PM_CL="/DMEOW_HEADER=coroutine" PM_CL="/DMEOW_HEADER=deque" PM_CL="/DMEOW_HEADER=exception" PM_CL="/DMEOW_HEADER=execution"