diff options
author | Hui <hui.xie1990@gmail.com> | 2025-07-06 17:32:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-06 17:32:59 +0100 |
commit | 0d1e5ab2fd9cf9c48d60176391624544d2e2242c (patch) | |
tree | db1ae0ee28ef940722a343cdc413ef605ca44d6a | |
parent | f1549befc1254c93ee0b6240f387fc74460c779b (diff) | |
download | llvm-0d1e5ab2fd9cf9c48d60176391624544d2e2242c.zip llvm-0d1e5ab2fd9cf9c48d60176391624544d2e2242c.tar.gz llvm-0d1e5ab2fd9cf9c48d60176391624544d2e2242c.tar.bz2 |
[libc++] P2655R3 common_reference_t of reference_wrapper Should Be a Reference Type (#141408)
Fixes #105260
This patch applies the change as a DR to C++20. The rationale is that
the paper is more like a bug fix. It does not introduce new features, it
simply changes an existing behaviour (as a bug fix). MSVC STL DRed this
paper to C++20 as well.
14 files changed, 382 insertions, 26 deletions
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 3c635e5..6180572 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/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 924c261..2cb560b 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -51,6 +51,7 @@ Implemented Papers - P2441R2: ``views::join_with`` (`Github <https://github.com/llvm/llvm-project/issues/105185>`__) - P2711R1: Making multi-param constructors of ``views`` ``explicit`` (`Github <https://github.com/llvm/llvm-project/issues/105252>`__) - P2770R0: Stashing stashing ``iterators`` for proper flattening (`Github <https://github.com/llvm/llvm-project/issues/105250>`__) +- 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 5746751..e4fa07d 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","The paper is implemented as a DR to C++20" "`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","" diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h index 11ba364..148703b 100644 --- a/libcxx/include/__functional/reference_wrapper.h +++ b/libcxx/include/__functional/reference_wrapper.h @@ -11,15 +11,18 @@ #define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H #include <__compare/synth_three_way.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_core_convertible.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_specialization.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> @@ -156,6 +159,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 _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 _LIBCPP_NODEBUG = 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 7df55f7..59badb6 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> @@ -139,13 +140,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/include/functional b/libcxx/include/functional index c72d093..9ebcd81 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -565,6 +565,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited # include <__functional/bind_front.h> # include <__functional/identity.h> # include <__functional/ranges_operations.h> +# include <__type_traits/common_reference.h> # include <__type_traits/unwrap_ref.h> # endif diff --git a/libcxx/include/version b/libcxx/include/version index 91fe483..d98049b 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> @@ -402,6 +404,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/modules/std/functional.inc b/libcxx/modules/std/functional.inc index ddc7d02..9ef8f58 100644 --- a/libcxx/modules/std/functional.inc +++ b/libcxx/modules/std/functional.inc @@ -14,6 +14,10 @@ export namespace std { using std::invoke_r; #endif +#if _LIBCPP_STD_VER >= 20 + using std::basic_common_reference; +#endif + // [refwrap], reference_wrapper using std::reference_wrapper; 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 8dbbbf4..8c08206 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 45c51b5..e6c0940 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 e546719..222d562 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 @@ -1057,6 +1065,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 @@ -2055,6 +2071,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 @@ -3281,6 +3305,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 @@ -4726,6 +4764,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 @@ -6399,6 +6451,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/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 0000000..a3630cb --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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>&>); 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 e802776..8e3cad7 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>>); diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index edd7b12..18eb8a8 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -314,6 +314,16 @@ feature_test_macros = [ "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}, "headers": ["complex"], |