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

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jun 1 11:04:19 PDT 2025


https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/141408

>From 65719fb55353cf92b1cb390beb7b3c45faa62a07 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 May 2025 14:09:34 +0100
Subject: [PATCH 1/5] [libc++] P2655R3 common_reference_t of reference_wrapper
 Should Be a Reference Type

---
 .../include/__functional/reference_wrapper.h  |  29 ++++
 .../include/__type_traits/common_reference.h  |  11 +-
 .../refwrap/common_reference.compile.pass.cpp | 153 ++++++++++++++++++
 .../common_reference.compile.pass.cpp         |  58 ++++---
 4 files changed, 226 insertions(+), 25 deletions(-)
 create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp

diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index b409ad7511f6c..5740a943eee81 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -12,13 +12,16 @@
 
 #include <__compare/synth_three_way.h>
 #include <__concepts/boolean_testable.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_specialization.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
@@ -155,6 +158,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 = 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 = 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 c27da5251b9b7..5bc714055d901 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>
@@ -132,13 +133,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/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..142841a60eb90
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>&>);
\ No newline at end of file
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>>);

>From 700b91a40e7595e25d326f60d0b1c9ecdd3b0f0a Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 25 May 2025 14:16:47 +0100
Subject: [PATCH 2/5] release note

---
 libcxx/docs/ReleaseNotes/21.rst    | 1 +
 libcxx/docs/Status/Cxx23Papers.csv | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index d0383a705190d..88b259d90fa3a 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -47,6 +47,7 @@ Implemented Papers
 - P1222R4: A Standard ``flat_set`` (`Github <https://github.com/llvm/llvm-project/issues/105193>`__)
 - P2897R7: ``aligned_accessor``: An mdspan accessor expressing pointer over-alignment (`Github <https://github.com/llvm/llvm-project/issues/118372>`__)
 - P3247R2: Deprecate the notion of trivial types (`Github <https://github.com/llvm/llvm-project/issues/118387>`__)
+- 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 c26363bcda796..fb600558fc18a 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",""
 "`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",""

>From 7372952518db4e645e839a52ec2917de36a7bc20 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 1 Jun 2025 18:52:24 +0100
Subject: [PATCH 3/5] clang-format

---
 .../function.objects/refwrap/common_reference.compile.pass.cpp   | 1 -
 1 file changed, 1 deletion(-)

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
index 142841a60eb90..ea23f5a4a4832 100644
--- 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
@@ -144,7 +144,6 @@ struct Test {
 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>&>);

>From eebb63ec14cfed5069339a5a3475067f8978ab6e Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 1 Jun 2025 18:55:39 +0100
Subject: [PATCH 4/5] ci

---
 libcxx/include/__functional/reference_wrapper.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 5740a943eee81..a028d56522bf5 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -172,14 +172,14 @@ template <class _Rp, class _Tp, template <class> class _RpQual, template <class>
   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 = common_reference_t<typename _Rp::type&, _TpQual<_Tp>>;
+  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 = common_reference_t<typename _Rp::type&, _TpQual<_Tp>>;
+  using type _LIBCPP_NODEBUG = common_reference_t<typename _Rp::type&, _TpQual<_Tp>>;
 };
 
 #endif // _LIBCPP_STD_VER >= 20

>From 1422f69406031c47184c4b9360cb2eefd60a5875 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 1 Jun 2025 19:04:06 +0100
Subject: [PATCH 5/5] FTM

---
 libcxx/docs/FeatureTestMacroTable.rst         |  4 ++
 libcxx/include/version                        |  4 ++
 .../functional.version.compile.pass.cpp       | 33 ++++++++++
 .../type_traits.version.compile.pass.cpp      | 33 ++++++++++
 .../version.version.compile.pass.cpp          | 66 +++++++++++++++++++
 .../generate_feature_test_macro_components.py | 10 +++
 6 files changed, 150 insertions(+)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 9b57b7c8eeb52..57cbe4ad65397 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/include/version b/libcxx/include/version
index 77d97b93adc6c..2e0903b53aef7 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>
@@ -399,6 +401,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/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 aa33a2788f1eb..85130425a547c 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
@@ -1045,6 +1053,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
@@ -2031,6 +2047,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
@@ -3245,6 +3269,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
@@ -4678,6 +4716,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
@@ -6345,6 +6397,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/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 2b7f6fa8a48a9..d430a97301b6e 100755
--- 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