[libcxx-commits] [libcxx] 0d1e5ab - [libc++] P2655R3 common_reference_t of reference_wrapper Should Be a Reference Type (#141408)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 6 09:33:02 PDT 2025


Author: Hui
Date: 2025-07-06T17:32:59+01:00
New Revision: 0d1e5ab2fd9cf9c48d60176391624544d2e2242c

URL: https://github.com/llvm/llvm-project/commit/0d1e5ab2fd9cf9c48d60176391624544d2e2242c
DIFF: https://github.com/llvm/llvm-project/commit/0d1e5ab2fd9cf9c48d60176391624544d2e2242c.diff

LOG: [libc++] P2655R3 common_reference_t of reference_wrapper Should Be a Reference Type (#141408)

Fixes #105260

This patch applies the change as a DR to C++20. The rationale is that
the paper is more like a bug fix. It does not introduce new features, it
simply changes an existing behaviour (as a bug fix). MSVC STL DRed this
paper to C++20 as well.

Added: 
    libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/21.rst
    libcxx/docs/Status/Cxx23Papers.csv
    libcxx/include/__functional/reference_wrapper.h
    libcxx/include/__type_traits/common_reference.h
    libcxx/include/functional
    libcxx/include/version
    libcxx/modules/std/functional.inc
    libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3c635e5e46bbd..61805726a4ff0 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -198,6 +198,10 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_char8_t``                                      ``201907L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_common_reference``                             ``202302L``
+    ---------------------------------------------------------- -----------------
+    ``__cpp_lib_common_reference_wrapper``                     ``202302L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_concepts``                                     ``202002L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_algorithms``                         ``201806L``

diff  --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index 924c2616335b2..2cb560b3852f3 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -51,6 +51,7 @@ Implemented Papers
 - P2441R2: ``views::join_with`` (`Github <https://github.com/llvm/llvm-project/issues/105185>`__)
 - P2711R1: Making multi-param constructors of ``views`` ``explicit`` (`Github <https://github.com/llvm/llvm-project/issues/105252>`__)
 - P2770R0: Stashing stashing ``iterators`` for proper flattening (`Github <https://github.com/llvm/llvm-project/issues/105250>`__)
+- P2655R3: ``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type (`Github <https://github.com/llvm/llvm-project/issues/105260>`__)
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 574675175a4cf..e4fa07d82289d 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -113,7 +113,7 @@
 "`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","2023-02 (Issaquah)","|Partial|","","The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet"
 "`P2679R2 <https://wg21.link/P2679R2>`__","Fixing ``std::start_lifetime_as`` for arrays","2023-02 (Issaquah)","","",""
 "`P2674R1 <https://wg21.link/P2674R1>`__","A trait for implicit lifetime types","2023-02 (Issaquah)","|Complete|","20",""
-"`P2655R3 <https://wg21.link/P2655R3>`__","``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","2023-02 (Issaquah)","","",""
+"`P2655R3 <https://wg21.link/P2655R3>`__","``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","2023-02 (Issaquah)","|Complete|","21","The paper is implemented as a DR to C++20"
 "`P2652R2 <https://wg21.link/P2652R2>`__","Disallow User Specialization of ``allocator_traits``","2023-02 (Issaquah)","|Complete|","19",""
 "`P2787R1 <https://wg21.link/P2787R1>`__","``pmr::generator`` - Promise Types are not Values","2023-02 (Issaquah)","","",""
 "`P2614R2 <https://wg21.link/P2614R2>`__","Deprecate ``numeric_limits::has_denorm``","2023-02 (Issaquah)","|Complete|","18",""

diff  --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 11ba364369428..148703b21d84a 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -11,15 +11,18 @@
 #define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
 
 #include <__compare/synth_three_way.h>
+#include <__concepts/convertible_to.h>
 #include <__config>
 #include <__functional/weak_result_type.h>
 #include <__memory/addressof.h>
+#include <__type_traits/common_reference.h>
 #include <__type_traits/desugars_to.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_const.h>
 #include <__type_traits/is_core_convertible.h>
 #include <__type_traits/is_same.h>
+#include <__type_traits/is_specialization.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
@@ -156,6 +159,32 @@ template <class _CanonicalTag, class _Operation, class... _Args>
 inline const bool __desugars_to_v<_CanonicalTag, reference_wrapper<_Operation>, _Args...> =
     __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
 
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp>
+inline constexpr bool __is_ref_wrapper = __is_specialization_v<_Tp, reference_wrapper>;
+
+template <class _Rp, class _Tp, class _RpQual, class _TpQual>
+concept __ref_wrap_common_reference_exists_with = __is_ref_wrapper<_Rp> && requires {
+  typename common_reference_t<typename _Rp::type&, _TpQual>;
+} && convertible_to<_RpQual, common_reference_t<typename _Rp::type&, _TpQual>>;
+
+template <class _Rp, class _Tp, template <class> class _RpQual, template <class> class _TpQual>
+  requires(__ref_wrap_common_reference_exists_with<_Rp, _Tp, _RpQual<_Rp>, _TpQual<_Tp>> &&
+           !__ref_wrap_common_reference_exists_with<_Tp, _Rp, _TpQual<_Tp>, _RpQual<_Rp>>)
+struct basic_common_reference<_Rp, _Tp, _RpQual, _TpQual> {
+  using type _LIBCPP_NODEBUG = common_reference_t<typename _Rp::type&, _TpQual<_Tp>>;
+};
+
+template <class _Tp, class _Rp, template <class> class _TpQual, template <class> class _RpQual>
+  requires(__ref_wrap_common_reference_exists_with<_Rp, _Tp, _RpQual<_Rp>, _TpQual<_Tp>> &&
+           !__ref_wrap_common_reference_exists_with<_Tp, _Rp, _TpQual<_Tp>, _RpQual<_Rp>>)
+struct basic_common_reference<_Tp, _Rp, _TpQual, _RpQual> {
+  using type _LIBCPP_NODEBUG = common_reference_t<typename _Rp::type&, _TpQual<_Tp>>;
+};
+
+#endif // _LIBCPP_STD_VER >= 20
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H

diff  --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h
index 7df55f7fecfd5..59badb64267de 100644
--- a/libcxx/include/__type_traits/common_reference.h
+++ b/libcxx/include/__type_traits/common_reference.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___TYPE_TRAITS_COMMON_REFERENCE_H
 
 #include <__config>
+#include <__type_traits/add_pointer.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/copy_cv.h>
 #include <__type_traits/copy_cvref.h>
@@ -139,13 +140,17 @@ struct __common_reference_sub_bullet2 : __common_reference_sub_bullet3<_Tp, _Up>
 template <class _Tp, class _Up>
 struct __common_reference_sub_bullet1 : __common_reference_sub_bullet2<_Tp, _Up> {};
 
-// sub-bullet 1 - If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, then
-// the member typedef `type` denotes that type.
+// sub-bullet 1 - Let R be COMMON-REF(T1, T2). If T1 and T2 are reference types, R is well-formed, and
+// is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> && is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>> is
+// true, then the member typedef type denotes R.
+
 template <class _Tp, class _Up>
 struct common_reference<_Tp, _Up> : __common_reference_sub_bullet1<_Tp, _Up> {};
 
 template <class _Tp, class _Up>
-  requires is_reference_v<_Tp> && is_reference_v<_Up> && requires { typename __common_ref_t<_Tp, _Up>; }
+  requires is_reference_v<_Tp> && is_reference_v<_Up> && requires { typename __common_ref_t<_Tp, _Up>; } &&
+           is_convertible_v<add_pointer_t<_Tp>, add_pointer_t<__common_ref_t<_Tp, _Up>>> &&
+           is_convertible_v<add_pointer_t<_Up>, add_pointer_t<__common_ref_t<_Tp, _Up>>>
 struct __common_reference_sub_bullet1<_Tp, _Up> {
   using type _LIBCPP_NODEBUG = __common_ref_t<_Tp, _Up>;
 };

diff  --git a/libcxx/include/functional b/libcxx/include/functional
index c72d0931e4b92..9ebcd818ec840 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -565,6 +565,7 @@ POLICY:  For non-variadic implementations, the number of arguments is limited
 #    include <__functional/bind_front.h>
 #    include <__functional/identity.h>
 #    include <__functional/ranges_operations.h>
+#    include <__type_traits/common_reference.h>
 #    include <__type_traits/unwrap_ref.h>
 #  endif
 

diff  --git a/libcxx/include/version b/libcxx/include/version
index 91fe48351e161..d98049bd57046 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -59,6 +59,8 @@ __cpp_lib_char8_t                                       201907L <atomic> <filesy
 __cpp_lib_chrono                                        201611L <chrono>
 __cpp_lib_chrono_udls                                   201304L <chrono>
 __cpp_lib_clamp                                         201603L <algorithm>
+__cpp_lib_common_reference                              202302L <type_traits>
+__cpp_lib_common_reference_wrapper                      202302L <functional>
 __cpp_lib_complex_udls                                  201309L <complex>
 __cpp_lib_concepts                                      202002L <concepts>
 __cpp_lib_constexpr_algorithms                          202306L <algorithm> <utility>
@@ -402,6 +404,8 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # if _LIBCPP_HAS_CHAR8_T
 #   define __cpp_lib_char8_t                            201907L
 # endif
+# define __cpp_lib_common_reference                     202302L
+# define __cpp_lib_common_reference_wrapper             202302L
 # define __cpp_lib_concepts                             202002L
 # define __cpp_lib_constexpr_algorithms                 201806L
 # define __cpp_lib_constexpr_complex                    201711L

diff  --git a/libcxx/modules/std/functional.inc b/libcxx/modules/std/functional.inc
index ddc7d023ee6dc..9ef8f584611fc 100644
--- a/libcxx/modules/std/functional.inc
+++ b/libcxx/modules/std/functional.inc
@@ -14,6 +14,10 @@ export namespace std {
   using std::invoke_r;
 #endif
 
+#if _LIBCPP_STD_VER >= 20
+  using std::basic_common_reference;
+#endif
+
   // [refwrap], reference_wrapper
   using std::reference_wrapper;
 

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index 8dbbbf432ddbf..8c0820681188d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -32,6 +32,10 @@
 #    error "__cpp_lib_boyer_moore_searcher should not be defined before c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should not be defined before c++20"
 #  endif
@@ -94,6 +98,10 @@
 #    error "__cpp_lib_boyer_moore_searcher should not be defined before c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should not be defined before c++20"
 #  endif
@@ -165,6 +173,10 @@
 #    error "__cpp_lib_boyer_moore_searcher should have the value 201603L in c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should not be defined before c++20"
 #  endif
@@ -245,6 +257,13 @@
 #    error "__cpp_lib_boyer_moore_searcher should have the value 201603L in c++20"
 #  endif
 
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++20"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++20"
+#  endif
+
 #  ifndef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should be defined in c++20"
 #  endif
@@ -337,6 +356,13 @@
 #    error "__cpp_lib_boyer_moore_searcher should have the value 201603L in c++23"
 #  endif
 
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++23"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++23"
+#  endif
+
 #  ifndef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should be defined in c++23"
 #  endif
@@ -441,6 +467,13 @@
 #    error "__cpp_lib_boyer_moore_searcher should have the value 201603L in c++26"
 #  endif
 
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++26"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++26"
+#  endif
+
 #  ifndef __cpp_lib_constexpr_functional
 #    error "__cpp_lib_constexpr_functional should be defined in c++26"
 #  endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
index 45c51b5807c69..e6c0940ab7fd5 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
@@ -28,6 +28,10 @@
 #    error "__cpp_lib_bounded_array_traits should not be defined before c++20"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should not be defined before c++17"
 #  endif
@@ -130,6 +134,10 @@
 #    error "__cpp_lib_bounded_array_traits should not be defined before c++20"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should not be defined before c++17"
 #  endif
@@ -250,6 +258,10 @@
 #    error "__cpp_lib_bounded_array_traits should not be defined before c++20"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
 #  ifndef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should be defined in c++17"
 #  endif
@@ -394,6 +406,13 @@
 #    error "__cpp_lib_bounded_array_traits should have the value 201902L in c++20"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++20"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++20"
+#  endif
+
 #  ifndef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should be defined in c++20"
 #  endif
@@ -568,6 +587,13 @@
 #    error "__cpp_lib_bounded_array_traits should have the value 201902L in c++23"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++23"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++23"
+#  endif
+
 #  ifndef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should be defined in c++23"
 #  endif
@@ -763,6 +789,13 @@
 #    error "__cpp_lib_bounded_array_traits should have the value 201902L in c++26"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++26"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++26"
+#  endif
+
 #  ifndef __cpp_lib_has_unique_object_representations
 #    error "__cpp_lib_has_unique_object_representations should be defined in c++26"
 #  endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index e546719142231..222d562a19d63 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -164,6 +164,14 @@
 #    error "__cpp_lib_clamp should not be defined before c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifdef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should not be defined before c++14"
 #  endif
@@ -1057,6 +1065,14 @@
 #    error "__cpp_lib_clamp should not be defined before c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifndef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should be defined in c++14"
 #  endif
@@ -2055,6 +2071,14 @@
 #    error "__cpp_lib_clamp should have the value 201603L in c++17"
 #  endif
 
+#  ifdef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should not be defined before c++20"
+#  endif
+
+#  ifdef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should not be defined before c++20"
+#  endif
+
 #  ifndef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should be defined in c++17"
 #  endif
@@ -3281,6 +3305,20 @@
 #    error "__cpp_lib_clamp should have the value 201603L in c++20"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++20"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++20"
+#  endif
+
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++20"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++20"
+#  endif
+
 #  ifndef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should be defined in c++20"
 #  endif
@@ -4726,6 +4764,20 @@
 #    error "__cpp_lib_clamp should have the value 201603L in c++23"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++23"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++23"
+#  endif
+
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++23"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++23"
+#  endif
+
 #  ifndef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should be defined in c++23"
 #  endif
@@ -6399,6 +6451,20 @@
 #    error "__cpp_lib_clamp should have the value 201603L in c++26"
 #  endif
 
+#  ifndef __cpp_lib_common_reference
+#    error "__cpp_lib_common_reference should be defined in c++26"
+#  endif
+#  if __cpp_lib_common_reference != 202302L
+#    error "__cpp_lib_common_reference should have the value 202302L in c++26"
+#  endif
+
+#  ifndef __cpp_lib_common_reference_wrapper
+#    error "__cpp_lib_common_reference_wrapper should be defined in c++26"
+#  endif
+#  if __cpp_lib_common_reference_wrapper != 202302L
+#    error "__cpp_lib_common_reference_wrapper should have the value 202302L in c++26"
+#  endif
+
 #  ifndef __cpp_lib_complex_udls
 #    error "__cpp_lib_complex_udls should be defined in c++26"
 #  endif

diff  --git a/libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp
new file mode 100644
index 0000000000000..a3630cb0017b6
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp
@@ -0,0 +1,152 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <functional>
+//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+//
+// common_reference specializations for reference_wrapper
+
+#include <concepts>
+#include <functional>
+#include <type_traits>
+
+template <class T>
+concept HasType = requires { typename T::type; };
+
+template <class Result, class T1, class T2>
+concept check_XY = std::same_as<Result, std::common_reference_t<T1, T2>>;
+
+template <class Result, class T1, class T2>
+concept check_YX = std::same_as<Result, std::common_reference_t<T2, T1>>;
+
+template <class Result, class T1, class T2>
+concept check = check_XY<Result, T1, T2> && check_YX<Result, T1, T2>;
+
+template <class T1, class T2>
+concept check_none_XY = !HasType<std::common_reference<T1, T2>>;
+template <class T1, class T2>
+concept check_none_YX = !HasType<std::common_reference<T2, T1>>;
+
+template <class T1, class T2>
+concept check_none = check_none_XY<T1, T2> && check_none_YX<T1, T2>;
+
+// https://eel.is/c++draft/meta.trans#other-2.4
+template <class X, class Y>
+using CondRes = decltype(false ? std::declval<X (&)()>()() : std::declval<Y (&)()>()());
+
+template <class X, class Y>
+struct Ternary {};
+
+template <class X, class Y>
+  requires requires() { typename CondRes<X, Y>; }
+struct Ternary<X, Y> {
+  using type = CondRes<X, Y>;
+};
+template <class X, class Y>
+using Ternary_t = typename Ternary<X, Y>::type;
+
+template <class T>
+using Ref = std::reference_wrapper<T>;
+
+using std::common_reference_t;
+using std::same_as;
+
+// clang-format off
+static_assert(check<int &     , Ref<int      >, int &      >);
+static_assert(check<int const&, Ref<int      >, int const& >);
+static_assert(check<int const&, Ref<int const>, int &      >);
+static_assert(check<int const&, Ref<int const>, int const& >);
+static_assert(check<int&,       Ref<int> const&, int& >);
+static_assert(check<const volatile int&, Ref<const volatile int>, const volatile int&>);
+
+// derived-base and implicit convertibles
+struct B {};
+struct D : B {};
+struct C {
+    operator B&() const;
+};
+
+static_assert(check<B&      , Ref<B>,       D &     >);
+static_assert(check<B const&, Ref<B>,       D const&>);
+static_assert(check<B const&, Ref<B const>, D const&>);
+
+static_assert(check<B&      , Ref<D>,       B &     >);
+static_assert(check<B const&, Ref<D>,       B const&>);
+static_assert(check<B const&, Ref<D const>, B const&>);
+
+static_assert(std::same_as<B&,       CondRes<Ref<D>,       B&>>);
+static_assert(std::same_as<B const&, CondRes<Ref<D>,       B const &>>);
+static_assert(std::same_as<B const&, CondRes<Ref<D const>, B const&>>);
+
+static_assert( check<B&        , Ref<B>      , C&      >);
+static_assert( check<B&        , Ref<B>      , C       >);
+static_assert( check<B const&  , Ref<B const>, C       >);
+static_assert(!check<B&        , Ref<C>      , B&      >); // Ref<C> cannot be converted to B&
+static_assert( check<B&        , Ref<B>      , C const&>); // was const B& before P2655R3
+
+
+using Ri   = Ref<int>;
+using RRi  = Ref<Ref<int>>;
+using RRRi = Ref<Ref<Ref<int>>>;
+static_assert(check<Ri&,  Ri&,  RRi>);
+static_assert(check<RRi&, RRi&, RRRi>);
+static_assert(check<Ri,   Ri,   RRi>);
+static_assert(check<RRi,  RRi,  RRRi>);
+
+static_assert(check_none<int&, RRi>);
+static_assert(check_none<int,  RRi>);
+static_assert(check_none<int&, RRRi>);
+static_assert(check_none<int,  RRRi>);
+
+static_assert(check_none<Ri&, RRRi>);
+static_assert(check_none<Ri,  RRRi>);
+
+
+template <typename T>
+struct Test {
+  // Check that reference_wrapper<T> behaves the same as T& in common_reference.
+
+  using R1 = common_reference_t<T&, T&>;
+  using R2 = common_reference_t<T&, T const&>;
+  using R3 = common_reference_t<T&, T&&>;
+  using R4 = common_reference_t<T&, T const&&>;
+  using R5 = common_reference_t<T&, T>;
+
+  static_assert(same_as<R1, common_reference_t<Ref<T>, T&>>);
+  static_assert(same_as<R2, common_reference_t<Ref<T>, T const&>>);
+  static_assert(same_as<R3, common_reference_t<Ref<T>, T&&>>);
+  static_assert(same_as<R4, common_reference_t<Ref<T>, T const&&>>);
+  static_assert(same_as<R5, common_reference_t<Ref<T>, T>>);
+
+  // commute:
+  static_assert(same_as<R1, common_reference_t<T&,        Ref<T>>>);
+  static_assert(same_as<R2, common_reference_t<T const&,  Ref<T>>>);
+  static_assert(same_as<R3, common_reference_t<T&&,       Ref<T>>>);
+  static_assert(same_as<R4, common_reference_t<T const&&, Ref<T>>>);
+  static_assert(same_as<R5, common_reference_t<T,         Ref<T>>>);
+
+  // reference qualification of reference_wrapper is irrelevant 
+  static_assert(same_as<R1, common_reference_t<Ref<T>&,        T&>>);
+  static_assert(same_as<R1, common_reference_t<Ref<T> ,        T&>>);
+  static_assert(same_as<R1, common_reference_t<Ref<T> const&,  T&>>);
+  static_assert(same_as<R1, common_reference_t<Ref<T>&&,       T&>>);
+  static_assert(same_as<R1, common_reference_t<Ref<T> const&&, T&>>);
+};
+
+// clang-format on
+// Instantiate above checks:
+template struct Test<int>;
+template struct Test<std::reference_wrapper<int>>;
+
+// reference_wrapper as both args is unaffected.
+// subject to simple first rule of
+static_assert(check<Ref<int>&, Ref<int>&, Ref<int>&>);
+
+// double wrap is unaffected.
+static_assert(check<Ref<int>&, Ref<Ref<int>>, Ref<int>&>);

diff  --git a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp
index e802776f52bfc..8e3cad797d5a7 100644
--- a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp
@@ -18,9 +18,7 @@
 #include "test_macros.h"
 
 template <class T>
-constexpr bool has_type = requires {
-  typename T::type;
-};
+constexpr bool has_type = requires { typename T::type; };
 
 // A slightly simplified variation of std::tuple
 template <class...>
@@ -74,8 +72,10 @@ static_assert(std::is_same_v<std::common_reference_t<void (&&)()>, void (&&)()>)
 //  -- Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
 //     the pack T. Then
 // (6.3.1)
-//    -- If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed,
-//       then the member typedef type denotes that type.
+//    -- Let R be COMMON-REF(T1, T2). If T1 and T2 are reference types, R is well-formed,
+//       and is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> && is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>>
+//       is true, then the member typedef type denotes R.
+
 struct B {};
 struct D : B {};
 static_assert(std::is_same_v<std::common_reference_t<B&, D&>, B&>);
@@ -99,7 +99,19 @@ static_assert(std::is_same_v<std::common_reference_t<int const&, int volatile&>,
 static_assert(std::is_same_v<std::common_reference_t<int const volatile&&, int volatile&&>, int const volatile&&>);
 
 static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&&)[10]>, int const (&)[10]>);
-static_assert(std::is_same_v<std::common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile (&)[10]>);
+static_assert(
+    std::is_same_v<std::common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile (&)[10]>);
+
+// when conversion from pointers are not true
+struct E {};
+struct F {
+  operator E&() const;
+};
+
+static_assert(!std::is_convertible_v<F*, E*>);
+
+// The following should not use 6.3.1, but fallback to 6.3.3
+static_assert(std::is_same_v<std::common_reference_t<E&, F>, E&>);
 
 // (6.3.2)
 //    -- Otherwise, if basic_common_reference<remove_cvref_t<T1>,
@@ -136,8 +148,8 @@ static_assert(std::is_same_v<std::common_reference_t<int&, MyIntRef>, MyIntRef>)
 //    -- Otherwise, if common_type_t<T1, T2> is well-formed, then the member
 //       typedef type denotes that type.
 struct moveonly {
-  moveonly() = default;
-  moveonly(moveonly&&) = default;
+  moveonly()                      = default;
+  moveonly(moveonly&&)            = default;
   moveonly& operator=(moveonly&&) = default;
 };
 struct moveonly2 : moveonly {};
@@ -169,14 +181,17 @@ static_assert(!has_type<std::common_reference<int, short, int, char*> >);
 
 #if TEST_STD_VER > 20
 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, int>>, std::tuple<int, int>>);
-static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, long>, std::tuple<long, int>>, std::tuple<long, long>>);
+static_assert(
+    std::is_same_v<std::common_reference_t<std::tuple<int, long>, std::tuple<long, int>>, std::tuple<long, long>>);
 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const int&>, std::tuple<const int&, int>>,
                              std::tuple<const int&, int>>);
 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, volatile int&>, std::tuple<volatile int&, int>>,
                              std::tuple<volatile int&, int>>);
-static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const volatile int&>, std::tuple<const volatile int&, int>>,
-                             std::tuple<const volatile int&, int>>);
-static_assert(!has_type<std::common_reference_t<std::tuple<const int&, volatile int&>, std::tuple<volatile int&, const int&>>>);
+static_assert(
+    std::is_same_v<std::common_reference_t<std::tuple<int&, const volatile int&>, std::tuple<const volatile int&, int>>,
+                   std::tuple<const volatile int&, int>>);
+static_assert(
+    !has_type<std::common_reference_t<std::tuple<const int&, volatile int&>, std::tuple<volatile int&, const int&>>>);
 
 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>);
 static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>);
@@ -185,26 +200,25 @@ static_assert(!has_type<std::common_reference<std::tuple<int, X2>, std::tuple<fl
 static_assert(!has_type<std::common_reference<std::tuple<int, X2>, int, X2>>);
 
 struct A {};
-template <template<class> class TQual, template<class> class UQual>
+template <template <class> class TQual, template <class> class UQual>
 struct std::basic_common_reference<A, std::tuple<B>, TQual, UQual> {
   using type = tuple<UQual<B>>;
 };
 
 static_assert(std::is_same_v<std::common_reference_t<A, std::tuple<B>, std::tuple<D>>, std::tuple<B>>);
 
-
-static_assert(std::is_same_v<std::common_reference_t<std::pair<int, int>>,
-                             std::pair<int, int>>);
-static_assert(std::is_same_v<std::common_reference_t<std::pair<int, long>, std::pair<long, int>>,
-                             std::pair<long, long>>);
+static_assert(std::is_same_v<std::common_reference_t<std::pair<int, int>>, std::pair<int, int>>);
+static_assert(
+    std::is_same_v<std::common_reference_t<std::pair<int, long>, std::pair<long, int>>, std::pair<long, long>>);
 static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const int&>, std::pair<const int&, int>>,
                              std::pair<const int&, int>>);
 static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, volatile int&>, std::pair<volatile int&, int>>,
                              std::pair<volatile int&, int>>);
-static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const volatile int&>, std::pair<const volatile int&, int>>,
-                             std::pair<const volatile int&, int>>);
-static_assert(!has_type<std::common_reference_t<std::pair<const int&, volatile int&>,
-                        std::pair<volatile int&, const int&>>>);
+static_assert(
+    std::is_same_v<std::common_reference_t<std::pair<int&, const volatile int&>, std::pair<const volatile int&, int>>,
+                   std::pair<const volatile int&, int>>);
+static_assert(
+    !has_type<std::common_reference_t<std::pair<const int&, volatile int&>, std::pair<volatile int&, const int&>>>);
 
 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>);
 static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>);

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index edd7b124a1fb3..18eb8a8623748 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -313,6 +313,16 @@ def add_version_header(tc):
             "values": {"c++17": 201603},
             "headers": ["algorithm"],
         },
+        {
+            "name": "__cpp_lib_common_reference",
+            "values": {"c++20": 202302},
+            "headers": ["type_traits"],
+        },
+        {
+            "name": "__cpp_lib_common_reference_wrapper",
+            "values": {"c++20": 202302},
+            "headers": ["functional"],
+        },
         {
             "name": "__cpp_lib_complex_udls",
             "values": {"c++14": 201309},


        


More information about the libcxx-commits mailing list