libstdc++: Install <coroutine> header for freestanding [PR103726]

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.
This commit is contained in:
Jonathan Wakely 2022-01-10 20:48:53 +00:00
parent e4fe6dba90
commit 265d3e1a4e
3 changed files with 45 additions and 18 deletions

View File

@ -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 \

View File

@ -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 \

View File

@ -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