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>> );
>
>
>

Reply via email to