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