diff mbox series

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

Message ID 20220111133015.2560682-1-jwakely@redhat.com
State New
Headers show
Series [committed] libstdc++: Install <coroutine> header for freestanding [PR103726] | expand

Commit Message

Jonathan Wakely Jan. 11, 2022, 1:30 p.m. UTC
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 mbox series

Patch

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