On Mon, Oct 13, 2025 at 9:30 AM Tomasz Kaminski <[email protected]> wrote:
> > > On Mon, Oct 13, 2025 at 6:43 AM Patrick Palka <[email protected]> wrote: > >> PR libstdc++/120446 >> >> libstdc++-v3/ChangeLog: >> >> * include/bits/refwrap.h (__detail::__is_ref_wrapper): >> Define as per P2655R3 for C++20. >> (__detail::__ref_wrap_common_reference_exists_with): Likewise. >> (basic_common_reference): Define partial specializations using >> the above as per P2655R3 for C++20. >> * include/bits/version.def (common_reference_wrapper): New. >> * include/bits/version.h: Regenerate. >> * include/std/functional >> (__glibcxx_want_common_reference_wrapper): >> Define. >> * testsuite/20_util/reference_wrapper/p2655r3.cc: New test. >> --- >> > LGTM. > >> libstdc++-v3/include/bits/refwrap.h | 34 +++++++++++++++ >> libstdc++-v3/include/bits/version.def | 8 ++++ >> libstdc++-v3/include/bits/version.h | 10 +++++ >> libstdc++-v3/include/std/functional | 1 + >> .../20_util/reference_wrapper/p2655r3.cc | 43 +++++++++++++++++++ >> 5 files changed, 96 insertions(+) >> create mode 100644 >> libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc >> >> diff --git a/libstdc++-v3/include/bits/refwrap.h >> b/libstdc++-v3/include/bits/refwrap.h >> index 612715e9b7bd..5d9f8c8f49f9 100644 >> --- a/libstdc++-v3/include/bits/refwrap.h >> +++ b/libstdc++-v3/include/bits/refwrap.h >> @@ -457,6 +457,40 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, >> true_type) >> >> /// @} >> >> +#if __glibcxx_common_reference_wrapper // C++ >= 20 >> + namespace __detail >> + { >> + template<typename _Tp> >> + constexpr bool __is_ref_wrapper = false; >> + >> + template<typename _Tp> >> + constexpr bool __is_ref_wrapper<reference_wrapper<_Tp>> = true; >> + >> + template<typename _Rp, typename _Tp, typename _RQual, typename >> _TQual> >> + concept __ref_wrap_common_reference_exists_with = >> __is_ref_wrapper<_Rp> >> + && requires { typename common_reference_t<typename _Rp::type&, >> _TQual>; } >> + && convertible_to<_RQual, common_reference_t<typename _Rp::type&, >> _TQual>>; >> + } // namespace __detail >> + >> + template<typename _Rp, typename _Tp, >> + template<typename> class _RQual, template<typename> class >> _TQual> >> + requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp, >> + >> _RQual<_Rp>, _TQual<_Tp>> >> + && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp, >> + _TQual<_Tp>, >> _RQual<_Rp>>) >> + struct basic_common_reference<_Rp, _Tp, _RQual, _TQual> >> + { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; }; >> + >> + template<typename _Tp, typename _Rp, >> + template<typename> class _TQual, template<typename> class >> _RQual> >> + requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp, >> + >> _RQual<_Rp>, _TQual<_Tp>> >> + && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp, >> + _TQual<_Tp>, >> _RQual<_Rp>>) >> + struct basic_common_reference<_Tp, _Rp, _TQual, _RQual> >> + { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; }; >> +#endif >> + >> _GLIBCXX_END_NAMESPACE_VERSION >> } // namespace std >> >> diff --git a/libstdc++-v3/include/bits/version.def >> b/libstdc++-v3/include/bits/version.def >> index e2b064e09b1e..9f4e46e37260 100644 >> --- a/libstdc++-v3/include/bits/version.def >> +++ b/libstdc++-v3/include/bits/version.def >> @@ -1801,6 +1801,14 @@ ftms = { >> }; >> }; >> >> +ftms = { >> + name = common_reference_wrapper; >> + values = { >> + v = 202302; >> + cxxmin = 20; // We treat P2655R3 as a DR against C++20. >> + }; >> +}; >> + >> ftms = { >> name = formatters; >> values = { >> diff --git a/libstdc++-v3/include/bits/version.h >> b/libstdc++-v3/include/bits/version.h >> index 4581519d3a7d..e7af12bf629c 100644 >> --- a/libstdc++-v3/include/bits/version.h >> +++ b/libstdc++-v3/include/bits/version.h >> @@ -2011,6 +2011,16 @@ >> #endif /* !defined(__cpp_lib_common_reference) && >> defined(__glibcxx_want_common_reference) */ >> #undef __glibcxx_want_common_reference >> >> +#if !defined(__cpp_lib_common_reference_wrapper) >> +# if (__cplusplus >= 202002L) >> +# define __glibcxx_common_reference_wrapper 202302L >> +# if defined(__glibcxx_want_all) || >> defined(__glibcxx_want_common_reference_wrapper) >> +# define __cpp_lib_common_reference_wrapper 202302L >> +# endif >> +# endif >> +#endif /* !defined(__cpp_lib_common_reference_wrapper) && >> defined(__glibcxx_want_common_reference_wrapper) */ >> +#undef __glibcxx_want_common_reference_wrapper >> + >> #if !defined(__cpp_lib_formatters) >> # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED >> # define __glibcxx_formatters 202302L >> diff --git a/libstdc++-v3/include/std/functional >> b/libstdc++-v3/include/std/functional >> index 8ad73b343bda..6f7f2f627a2a 100644 >> --- a/libstdc++-v3/include/std/functional >> +++ b/libstdc++-v3/include/std/functional >> @@ -64,6 +64,7 @@ >> #define __glibcxx_want_not_fn >> #define __glibcxx_want_ranges >> #define __glibcxx_want_reference_wrapper >> +#define __glibcxx_want_common_reference_wrapper >> #define __glibcxx_want_transparent_operators >> #include <bits/version.h> >> >> diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc >> b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc >> new file mode 100644 >> index 000000000000..a240971f2e24 >> --- /dev/null >> +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc >> @@ -0,0 +1,43 @@ >> +// P2655R3 - common_reference_t of reference_wrapper Should Be a >> Reference Type >> +// Implemented as a DR against C++20 >> +// { dg-do compile { target c++20 } } >> + >> +#include <functional> >> + >> +#if __cpp_lib_common_reference_wrapper != 202302L >> +# error "Feature-test macro __cpp_lib_common_reference_wrapper has wrong >> value in <functional>" >> +#endif >> + >> +using std::is_same_v; >> +using std::common_reference_t; >> +using std::reference_wrapper; >> + >> +static_assert( is_same_v<common_reference_t<const >> reference_wrapper<int>&, int&>, int&> ); >> +static_assert( is_same_v<common_reference_t<int&, const >> reference_wrapper<int>&>, int&> ); >> + >> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>, >> int&>, >> + common_reference_t<int&, int&>> ); >> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>, >> const int&>, >> + common_reference_t<int&, const int&>> ); >> +static_assert( is_same_v<common_reference_t<reference_wrapper<const >> int>, int&>, >> + common_reference_t<const int&, int&>> ); >> + >> +static_assert( is_same_v<common_reference_t<int&, >> reference_wrapper<int>>, >> + common_reference_t<int&, int&>> ); >> +static_assert( is_same_v<common_reference_t<const int&, >> reference_wrapper<int>>, >> + common_reference_t<int&, const int&>> ); >> +static_assert( is_same_v<common_reference_t<int&, >> reference_wrapper<const int>>, >> + common_reference_t<const int&, int&>> ); >> + >> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>&, >> reference_wrapper<int>&>, >> + reference_wrapper<int>&> ); >> + >> +static_assert( is_same_v<common_reference_t<reference_wrapper<char>, >> + reference_wrapper<int>>, >> + int> ); >> +static_assert( >> is_same_v<common_reference_t<reference_wrapper<reference_wrapper<int>>, >> + reference_wrapper<int>>, >> + reference_wrapper<int>> ); >> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>, >> + >> reference_wrapper<reference_wrapper<int>>>, >> + reference_wrapper<int>> ); >> -- >> 2.51.0.491.g4b71b29477 >> > These are the test I would add in this commit, we can add pair/tuple later: struct A { }; struct B { operator A&() const; }; template<typename T, typename U> concept has_common_reference = requires { typename std::common_reference_t<T, U>; }; static_assert( is_same_v<common_reference_t<reference_wrapper<A>, const B&>, A&> ); // reference_wrapper<const B> is not convertible to A&, as it would require two user // defined conversions. static_assert( !has_common_reference<A, reference_wrapper<const B>> ); static_assert( !has_common_reference<reference_wrapper<A>, reference_wrapper<const B>> ); struct D1 : A {}; struct D2 : A {}; template<template<class> typename Qual1, template<class> typename Qual2> struct std::basic_common_reference<D1, D2, Qual1, Qual2> : std::common_reference<Qual1<A>, Qual2<A>> { }; template<template<class> typename Qual1, template<class> typename Qual2> struct std::basic_common_reference<D2, D1, Qual1, Qual2> : std::common_reference<Qual1<A>, Qual2<A>> { }; static_assert( is_same_v<common_reference_t<D1&, D2&>, A&> ); static_assert( is_same_v<common_reference_t<reference_wrapper<D1>, D2&>, A&> ); static_assert( is_same_v<common_reference_t<D1&, reference_wrapper<D2>>, A&> ); static_assert( !has_common_reference<reference_wrapper<D1>, reference_wrapper<D2>> ); > I would add test testing combination of this two changes: > struct A { }; > struct B { operator A&() const; }; > // This should be OK > static_assert( std::is_same_v<std::common_reference_t<refence_wrapper<A>, > const B&>, A&> ); > // common_reference_t would exists, but the concept > common_reference_with<A&, reference_wrapper<const B>> would not be modeled, > // because it would require two user defined conversions > static_assert( std::is_same_v<std::common_reference_t<A&, > reference_wrapper<const B>>, A&> ); > // Not sure what happens here. > static_assert( std::is_same_v<std::common_reference_t<refence_wrapper<A>, > reference_wrapper<const B>>, reference_wrapper<A>> ); > > >
