]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement rest of P2655R3 common_reference of reference_wrapper
authorPatrick Palka <ppalka@redhat.com>
Fri, 5 Dec 2025 18:43:40 +0000 (13:43 -0500)
committerPatrick Palka <ppalka@redhat.com>
Fri, 5 Dec 2025 18:43:40 +0000 (13:43 -0500)
PR libstdc++/120446

libstdc++-v3/ChangeLog:

* include/bits/refwrap.h (__detail::__is_ref_wrapper):
Define as per P2655R3 for C++20.
(__detail::__ref_wrap_common_reference_exists_with): Likewise.
(basic_common_reference): Define partial specializations using
the above as per P2655R3 for C++20.
* include/bits/version.def (common_reference_wrapper): New.
* include/bits/version.h: Regenerate.
* include/std/functional (__glibcxx_want_common_reference_wrapper):
Define.
* testsuite/20_util/reference_wrapper/p2655r3.cc: New test.

Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
libstdc++-v3/include/bits/refwrap.h
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/include/std/functional
libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc [new file with mode: 0644]

index 612715e9b7bdd65f9f46c2b0bc8b6e40edd67d73..5d9f8c8f49f939ce3ee9a391f5f54f5dc5c82e47 100644 (file)
@@ -457,6 +457,40 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type)
 
   /// @}
 
+#if __glibcxx_common_reference_wrapper // C++ >= 20
+  namespace __detail
+  {
+    template<typename _Tp>
+      constexpr bool __is_ref_wrapper = false;
+
+    template<typename _Tp>
+      constexpr bool __is_ref_wrapper<reference_wrapper<_Tp>> = true;
+
+    template<typename _Rp, typename _Tp, typename _RQual, typename _TQual>
+      concept __ref_wrap_common_reference_exists_with = __is_ref_wrapper<_Rp>
+       && requires { typename common_reference_t<typename _Rp::type&, _TQual>; }
+       && convertible_to<_RQual, common_reference_t<typename _Rp::type&, _TQual>>;
+  } // namespace __detail
+
+  template<typename _Rp, typename _Tp,
+          template<typename> class _RQual, template<typename> class _TQual>
+    requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp,
+                                                              _RQual<_Rp>, _TQual<_Tp>>
+      && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp,
+                                                            _TQual<_Tp>, _RQual<_Rp>>)
+  struct basic_common_reference<_Rp, _Tp, _RQual, _TQual>
+  { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; };
+
+  template<typename _Tp, typename _Rp,
+          template<typename> class _TQual, template<typename> class _RQual>
+    requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp,
+                                                              _RQual<_Rp>, _TQual<_Tp>>
+      && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp,
+                                                            _TQual<_Tp>, _RQual<_Rp>>)
+  struct basic_common_reference<_Tp, _Rp, _TQual, _RQual>
+  { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; };
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
index 91c1edec4d6086df5d5d335d5fea85a158332991..412b9ce96f8af020e77ec9824c4198f1be3dc8c5 100644 (file)
@@ -1829,6 +1829,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = common_reference_wrapper;
+  values = {
+    v = 202302;
+    cxxmin = 20; // We treat P2655R3 as a DR against C++20.
+  };
+};
+
 ftms = {
   name = formatters;
   values = {
index f5ddc86f21a3b7916f4ae3d7cc6944ccef930579..2b96934ca099f05ded5c3ef083ec1444251c72f8 100644 (file)
 #endif /* !defined(__cpp_lib_common_reference) && defined(__glibcxx_want_common_reference) */
 #undef __glibcxx_want_common_reference
 
+#if !defined(__cpp_lib_common_reference_wrapper)
+# if (__cplusplus >= 202002L)
+#  define __glibcxx_common_reference_wrapper 202302L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_common_reference_wrapper)
+#   define __cpp_lib_common_reference_wrapper 202302L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_common_reference_wrapper) && defined(__glibcxx_want_common_reference_wrapper) */
+#undef __glibcxx_want_common_reference_wrapper
+
 #if !defined(__cpp_lib_formatters)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_formatters 202302L
index 69a3910b0bd9b432b5d2765774935b0edd2b997d..74aa5fa3e9a18aed722f6df7a1cf76bfadd4e64e 100644 (file)
@@ -64,6 +64,7 @@
 #define __glibcxx_want_not_fn
 #define __glibcxx_want_ranges
 #define __glibcxx_want_reference_wrapper
+#define __glibcxx_want_common_reference_wrapper
 #define __glibcxx_want_transparent_operators
 #include <bits/version.h>
 
diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
new file mode 100644 (file)
index 0000000..f2fafec
--- /dev/null
@@ -0,0 +1,75 @@
+// P2655R3 - common_reference_t of reference_wrapper Should Be a Reference Type
+// Implemented as a DR against C++20
+// { dg-do compile { target c++20 } }
+
+#include <functional>
+
+#if __cpp_lib_common_reference_wrapper != 202302L
+# error "Feature-test macro __cpp_lib_common_reference_wrapper has wrong value in <functional>"
+#endif
+
+using std::is_same_v;
+using std::common_reference_t;
+using std::reference_wrapper;
+
+static_assert( is_same_v<common_reference_t<const reference_wrapper<int>&, int&>, int&> );
+static_assert( is_same_v<common_reference_t<int&, const reference_wrapper<int>&>, int&> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>, int&>,
+                        common_reference_t<int&, int&>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>, const int&>,
+                        common_reference_t<int&, const int&>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<const int>, int&>,
+                        common_reference_t<const int&, int&>> );
+
+static_assert( is_same_v<common_reference_t<int&, reference_wrapper<int>>,
+                        common_reference_t<int&, int&>> );
+static_assert( is_same_v<common_reference_t<const int&, reference_wrapper<int>>,
+                        common_reference_t<int&, const int&>> );
+static_assert( is_same_v<common_reference_t<int&, reference_wrapper<const int>>,
+                        common_reference_t<const int&, int&>> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>&, reference_wrapper<int>&>,
+                        reference_wrapper<int>&> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<char>,
+                                           reference_wrapper<int>>,
+                        int> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<reference_wrapper<int>>,
+                                           reference_wrapper<int>>,
+                        reference_wrapper<int>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>,
+                                           reference_wrapper<reference_wrapper<int>>>,
+                        reference_wrapper<int>> );
+
+struct A { };
+struct B { operator A&() const; };
+
+template<typename T, typename U>
+concept has_common_reference = requires {
+  typename std::common_reference_t<T, U>;
+};
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<A>, const B&>, A&> );
+// reference_wrapper<const B> is not convertible to A&, as it would require two user
+// defined conversions.
+static_assert( !has_common_reference<A, reference_wrapper<const B>> );
+static_assert( !has_common_reference<reference_wrapper<A>, reference_wrapper<const B>> );
+
+struct D1 : A {};
+struct D2 : A {};
+
+template<template<class> typename Qual1, template<class> typename Qual2>
+struct std::basic_common_reference<D1, D2, Qual1, Qual2>
+ : std::common_reference<Qual1<A>, Qual2<A>>
+{ };
+
+template<template<class> typename Qual1, template<class> typename Qual2>
+struct std::basic_common_reference<D2, D1, Qual1, Qual2>
+ : std::common_reference<Qual1<A>, Qual2<A>>
+{ };
+
+static_assert( is_same_v<common_reference_t<D1&, D2&>, A&> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<D1>, D2&>, A&> );
+static_assert( is_same_v<common_reference_t<D1&, reference_wrapper<D2>>, A&> );
+static_assert( !has_common_reference<reference_wrapper<D1>, reference_wrapper<D2>> );