[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