Tested x86_64-linux and by minimally tested on mips-none-elf. Pushed to trunk.
The standard says that <coroutine> should be present for freestanding. That was intentionally left out of the initial implementation, but can be done without much trouble. The header should be moved to libsupc++ at some point in stage 1. The standard also says that <coroutine> defines a std::hash specialization, which was missing from our implementation. That's a problem for freestanding (see LWG 3653) so only do that for hosted. We can use concepts to constrain the __coroutine_traits_impl base class when compiled with concepts enabled. In a pure C++20 implementation we would not need that base class at all and could just use a constrained partial specialization of coroutine_traits. But the absence of the __coroutine_traits_impl<R, void> base would create an ABI difference between the non-standard C++14/C++17 support for coroutines and the same code compiled as C++20. If we drop support for <coroutine> pre-C++20 we should revisit this. libstdc++-v3/ChangeLog: PR libstdc++/103726 * include/Makefile.am: Install <coroutine> for freestanding. * include/Makefile.in: Regenerate. * include/std/coroutine: Adjust headers and preprocessor conditions. (__coroutine_traits_impl): Use concepts when available. [_GLIBCXX_HOSTED] (hash<coroutine_handle>): Define. --- libstdc++-v3/include/Makefile.am | 4 +-- libstdc++-v3/include/Makefile.in | 4 +-- libstdc++-v3/include/std/coroutine | 55 ++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 7afebb5c5f0..8f93bf2d7b7 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -1425,7 +1425,7 @@ endif # This is a subset of the full install-headers rule. We only need <ciso646>, # <cstddef>, <cfloat>, <limits>, <climits>, <version>, <cstdint>, <cstdlib>, # <new>, <typeinfo>, <exception>, <initializer_list>, <cstdalign>, <cstdarg>, -# <concepts>, <cstdbool>, <type_traits>, <bit>, <atomic>, +# <concepts>, <coroutine>, <cstdbool>, <type_traits>, <bit>, <atomic>, # and any files which they include (and which we provide). # <new>, <typeinfo>, <exception>, <initializer_list> and <compare> # are installed by libsupc++, so only the others and the sub-includes @@ -1440,7 +1440,7 @@ install-freestanding-headers: ${glibcxx_srcdir}/$(CPU_DEFINES_SRCDIR)/cpu_defines.h; do \ $(INSTALL_DATA) $${file} $(DESTDIR)${host_installdir}; done $(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${std_builddir} - for file in limits type_traits atomic bit concepts version; do \ + for file in limits type_traits atomic bit concepts coroutine version; do \ $(INSTALL_DATA) ${std_builddir}/$${file} $(DESTDIR)${gxx_include_dir}/${std_builddir}; done $(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${c_base_builddir} for file in ciso646 cstddef cfloat climits cstdint cstdlib \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 0031f54f3fa..4ab942ae666 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -1906,7 +1906,7 @@ ${pch3_output}: ${pch3_source} ${pch2_output} # This is a subset of the full install-headers rule. We only need <ciso646>, # <cstddef>, <cfloat>, <limits>, <climits>, <version>, <cstdint>, <cstdlib>, # <new>, <typeinfo>, <exception>, <initializer_list>, <cstdalign>, <cstdarg>, -# <concepts>, <cstdbool>, <type_traits>, <bit>, <atomic>, +# <concepts>, <coroutine>, <cstdbool>, <type_traits>, <bit>, <atomic>, # and any files which they include (and which we provide). # <new>, <typeinfo>, <exception>, <initializer_list> and <compare> # are installed by libsupc++, so only the others and the sub-includes @@ -1921,7 +1921,7 @@ install-freestanding-headers: ${glibcxx_srcdir}/$(CPU_DEFINES_SRCDIR)/cpu_defines.h; do \ $(INSTALL_DATA) $${file} $(DESTDIR)${host_installdir}; done $(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${std_builddir} - for file in limits type_traits atomic bit concepts version; do \ + for file in limits type_traits atomic bit concepts coroutine version; do \ $(INSTALL_DATA) ${std_builddir}/$${file} $(DESTDIR)${gxx_include_dir}/${std_builddir}; done $(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${c_base_builddir} for file in ciso646 cstddef cfloat climits cstdint cstdlib \ diff --git a/libstdc++-v3/include/std/coroutine b/libstdc++-v3/include/std/coroutine index ead5dad9bf0..f4189c7e3fc 100644 --- a/libstdc++-v3/include/std/coroutine +++ b/libstdc++-v3/include/std/coroutine @@ -34,22 +34,23 @@ // It is very likely that earlier versions would work, but they are untested. #if __cplusplus >= 201402L -#include <bits/c++config.h> +#include <type_traits> +#if __cplusplus > 201703L +# include <compare> +#endif + +#if !defined __cpp_lib_three_way_comparison && _GLIBCXX_HOSTED +# include <bits/stl_function.h> // for std::less +#endif /** * @defgroup coroutines Coroutines * * Components for supporting coroutine implementations. + * + * @since C++20 (and since C++14 as a libstdc++ extension) */ -#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L -# include <compare> -# define _COROUTINES_USE_SPACESHIP 1 -#else -# include <bits/stl_function.h> // for std::less -# define _COROUTINES_USE_SPACESHIP 0 -#endif - namespace std _GLIBCXX_VISIBILITY (default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -60,25 +61,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline namespace __n4861 { - // 17.12.2 coroutine traits + // C++20 17.12.2 coroutine traits /// [coroutine.traits] /// [coroutine.traits.primary] /// If _Result::promise_type is valid and denotes a type then the traits /// have a single publicly accessible member, otherwise they are empty. + template <typename _Result, typename... _ArgTypes> + struct coroutine_traits; + template <typename _Result, typename = void> struct __coroutine_traits_impl {}; template <typename _Result> +#if __cpp_concepts + requires requires { typename _Result::promise_type; } + struct __coroutine_traits_impl<_Result, void> +#else struct __coroutine_traits_impl<_Result, - __void_t<typename _Result::promise_type>> + __void_t<typename _Result::promise_type>> +#endif { using promise_type = typename _Result::promise_type; }; - template <typename _Result, typename...> + template <typename _Result, typename... _ArgTypes> struct coroutine_traits : __coroutine_traits_impl<_Result> {}; - // 17.12.3 Class template coroutine_handle + // C++20 17.12.3 Class template coroutine_handle /// [coroutine.handle] template <typename _Promise = void> struct coroutine_handle; @@ -139,7 +148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __a.address() == __b.address(); } -#if _COROUTINES_USE_SPACESHIP +#ifdef __cpp_lib_three_way_comparison constexpr strong_ordering operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept { @@ -156,7 +165,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr bool operator<(coroutine_handle<> __a, coroutine_handle<> __b) noexcept { +#if _GLIBCXX_HOSTED return less<void*>()(__a.address(), __b.address()); +#else + return (__UINTPTR_TYPE__)__a.address() < (__UINTPTR_TYPE__)__b.address(); +#endif } constexpr bool @@ -330,6 +343,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // namespace __n4861 +#if _GLIBCXX_HOSTED + template<typename _Tp> struct hash; + + template<typename _Promise> + struct hash<coroutine_handle<_Promise>> + { + size_t + operator()(const coroutine_handle<_Promise>& __h) noexcept + { + return reinterpret_cast<size_t>(__h.address()); + } + }; +#endif + #else #error "the coroutine header requires -fcoroutines" #endif -- 2.31.1