[PATCH 2/2] libstdc++: Implement P2655R3 common_reference of reference_wrapper

Patrick Palka ppalka@redhat.com
Tue Oct 7 03:09:08 GMT 2025


Tested on x86_64-pc-linux-gnu, does this look OK for trunk? I wonder
about backports, for either the whole paper or just the common_reference
change in <type_traits> for avoiding dangling references.

-- >8 --

This patch implements this paper as a DR against C++20 (as do MSVC and
libc++).

	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): New.
	(common_reference_wrapper): New.
	* include/bits/version.h: Regenerate.
	* include/std/functional (__glibcxx_want_common_reference_wrapper):
	Define.
	* include/std/type_traits (__glibcxx_want_common_reference):
	Define.
	(__common_reference_impl<T1, T2, 1>): Add pointer convertibility
	constraints as per P2655R3.
	* libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc: New
	test.
	* libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc: New
	test.
---
 libstdc++-v3/include/bits/refwrap.h           | 34 +++++++++++++++++++
 libstdc++-v3/include/bits/version.def         | 16 +++++++++
 libstdc++-v3/include/bits/version.h           | 20 +++++++++++
 libstdc++-v3/include/std/functional           |  1 +
 libstdc++-v3/include/std/type_traits          |  7 ++++
 .../20_util/common_reference/p2655r3.cc       | 15 ++++++++
 .../20_util/reference_wrapper/p2655r3.cc      | 33 ++++++++++++++++++
 7 files changed, 126 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc

diff --git a/libstdc++-v3/include/bits/refwrap.h b/libstdc++-v3/include/bits/refwrap.h
index 612715e9b7bd..5d9f8c8f49f9 100644
--- a/libstdc++-v3/include/bits/refwrap.h
+++ b/libstdc++-v3/include/bits/refwrap.h
@@ -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
 
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 3a26234f87ed..49d8d17e6677 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1774,6 +1774,22 @@ ftms = {
   };
 };
 
+ftms = {
+  name = common_reference;
+  values = {
+    v = 202302;
+    cxxmin = 20; // We treat P2655R3 as a DR against C++20.
+  };
+};
+
+ftms = {
+  name = common_reference_wrapper;
+  values = {
+    v = 202302;
+    cxxmin = 20; // We treat P2655R3 as a DR against C++20.
+  };
+};
+
 ftms = {
   name = formatters;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 46e4c1121e7a..3176a80f32e3 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1983,6 +1983,26 @@
 #endif /* !defined(__cpp_lib_flat_set) && defined(__glibcxx_want_flat_set) */
 #undef __glibcxx_want_flat_set
 
+#if !defined(__cpp_lib_common_reference)
+# if (__cplusplus >= 202002L)
+#  define __glibcxx_common_reference 202302L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_common_reference)
+#   define __cpp_lib_common_reference 202302L
+#  endif
+# endif
+#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
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 8ad73b343bda..6f7f2f627a2a 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -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/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 8b5110464e50..47cbf21b4c1d 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -41,6 +41,7 @@
 
 #define __glibcxx_want_bool_constant
 #define __glibcxx_want_bounded_array_traits
+#define __glibcxx_want_common_reference
 #define __glibcxx_want_constant_wrapper
 #define __glibcxx_want_has_unique_object_representations
 #define __glibcxx_want_integral_constant_callable
@@ -4223,6 +4224,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   template<typename _Tp1, typename _Tp2>
     requires is_reference_v<_Tp1> && is_reference_v<_Tp2>
       && requires { typename __common_ref<_Tp1, _Tp2>; }
+#if __cpp_lib_common_reference // C++ >= 20
+      && is_convertible_v<add_pointer_t<_Tp1>,
+			  add_pointer_t<__common_ref<_Tp1, _Tp2>>>
+      && is_convertible_v<add_pointer_t<_Tp2>,
+			  add_pointer_t<__common_ref<_Tp1, _Tp2>>>
+#endif
     struct __common_reference_impl<_Tp1, _Tp2, 1>
     { using type = __common_ref<_Tp1, _Tp2>; };
 
diff --git a/libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc b/libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc
new file mode 100644
index 000000000000..bc0372f79686
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc
@@ -0,0 +1,15 @@
+// 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 <type_traits>
+
+#if __cpp_lib_common_reference != 202302L
+# error "Feature-test macro __cpp_lib_common_reference has wrong value in <type_traits>"
+#endif
+
+struct A { };
+struct B { operator A&() const; };
+
+static_assert(std::is_same_v<std::common_reference_t<A&, const B&>, A&>);
+static_assert(std::is_same_v<std::common_reference_t<const B&, A&>, A&>);
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
index 000000000000..f66c2821554a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
@@ -0,0 +1,33 @@
+// 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>&>);
-- 
2.51.0.433.g45547b60ac



More information about the Libstdc++ mailing list