libstdc++: Install <coroutine> header for freestanding [PR103726]
authorJonathan Wakely <jwakely@redhat.com>
Mon, 10 Jan 2022 20:48:53 +0000 (20:48 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 11 Jan 2022 13:28:46 +0000 (13:28 +0000)
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
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/std/coroutine

index 7afebb5..8f93bf2 100644 (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 \
index 0031f54..4ab942a 100644 (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 \
index ead5dad..f4189c7 100644 (file)
 // 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