diff options
Diffstat (limited to 'libcxx')
24 files changed, 931 insertions, 518 deletions
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 6180572..a36848e 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -432,7 +432,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_constexpr_queue`` ``202502L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_constrained_equality`` *unimplemented* + ``__cpp_lib_constrained_equality`` ``202411L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_copyable_function`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 74bfa97..91123ff 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -53,6 +53,8 @@ Implemented Papers - 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>`__) +- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://github.com/llvm/llvm-project/issues/105424>`__) +- P3379R0: Constrain ``std::expected equality`` operators (`Github <https://github.com/llvm/llvm-project/issues/118135>`__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index e4fa07d..f1d8e9a 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -60,7 +60,7 @@ "`P1642R11 <https://wg21.link/P1642R11>`__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","" "`P1899R3 <https://wg21.link/P1899R3>`__","``stride_view``","2022-07 (Virtual)","","","" "`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output","2022-07 (Virtual)","|Complete|","18","" -"`P2165R4 <https://wg21.link/P2165R4>`__","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","2022-07 (Virtual)","|Partial|","","Only the part for ``zip_view`` is implemented." +"`P2165R4 <https://wg21.link/P2165R4>`__","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","2022-07 (Virtual)","|Partial|","","Changes of ``tuple``, ``adjacent_view``, and ``cartesian_product_view`` are not yet implemented." "`P2278R4 <https://wg21.link/P2278R4>`__","``cbegin`` should always return a constant iterator","2022-07 (Virtual)","","","" "`P2286R8 <https://wg21.link/P2286R8>`__","Formatting Ranges","2022-07 (Virtual)","|Complete|","16","" "`P2291R3 <https://wg21.link/P2291R3>`__","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ``<charconv>`` Header","2022-07 (Virtual)","|Complete|","16","" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index 6fcb2f3..c622512 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -149,4 +149,5 @@ "`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Adopted Yet","|Complete|","16","" "`LWG4139 <https://wg21.link/LWG4139>`__","§[time.zone.leap] recursive constraint in ``<=>``","Not Adopted Yet","|Complete|","20","" "`LWG3456 <https://wg21.link/LWG3456>`__","Pattern used by ``std::from_chars`` is underspecified (option B)","Not Adopted Yet","|Complete|","20","" +"`LWG3882 <https://wg21.link/LWG3882>`__","``tuple`` relational operators have confused friendships","Not Adopted Yet","|Complete|","21","The comparsion operators are constrained harder than the proposed resolution. libstdc++ and MSVC STL do the same." "","","","","","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index febb0c1..e8b0c95 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -59,7 +59,7 @@ "`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","","" "`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","" "`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","","" -"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented." +"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Complete|","21","" "`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","" "`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19","" "","","","","","" diff --git a/libcxx/include/__assert b/libcxx/include/__assert index 90eaa60..a9451da 100644 --- a/libcxx/include/__assert +++ b/libcxx/include/__assert @@ -20,8 +20,8 @@ #define _LIBCPP_ASSERT(expression, message) \ (__builtin_expect(static_cast<bool>(expression), 1) \ ? (void)0 \ - : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \ - expression) " failed: " message "\n")) + : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING( \ + __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n")) // WARNING: __builtin_assume can currently inhibit optimizations. Only add assumptions with a clear // optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a diff --git a/libcxx/include/__config b/libcxx/include/__config index 549aa06..77a71b6 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -64,9 +64,21 @@ // HARDENING { -// TODO: Remove in LLVM 21. We're making this an error to catch folks who might not have migrated. -# ifdef _LIBCPP_ENABLE_ASSERTIONS -# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE instead" +// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated. +// Since hardening went through several changes (many of which impacted user-facing macros), +// we're keeping these checks around for a bit longer than usual. Failure to properly configure +// hardening results in checks being dropped silently, which is a pretty big deal. +# if defined(_LIBCPP_ENABLE_ASSERTIONS) +# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_HARDENED_MODE) +# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_SAFE_MODE) +# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_DEBUG_MODE) +# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" # endif // The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: diff --git a/libcxx/include/__cxx03/__math/logarithms.h b/libcxx/include/__cxx03/__math/logarithms.h index 2547350..9b9e59a 100644 --- a/libcxx/include/__cxx03/__math/logarithms.h +++ b/libcxx/include/__cxx03/__math/logarithms.h @@ -58,7 +58,7 @@ inline _LIBCPP_HIDE_FROM_ABI double log10(_A1 __x) _NOEXCEPT { inline _LIBCPP_HIDE_FROM_ABI int ilogb(float __x) _NOEXCEPT { return __builtin_ilogbf(__x); } template <class = int> -_LIBCPP_HIDE_FROM_ABI double ilogb(double __x) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int ilogb(double __x) _NOEXCEPT { return __builtin_ilogb(__x); } diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 03f50d9..dacc152 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -1709,41 +1709,45 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __n) _LIBCPP_D template <class _Tp, class _Hash, class _Equal, class _Alloc> template <bool _UniqueKeys> -void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) { - __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc(); - __bucket_list_.reset(__nbc > 0 ? __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr); - __bucket_list_.get_deleter().size() = __nbc; - if (__nbc > 0) { - for (size_type __i = 0; __i < __nbc; ++__i) - __bucket_list_[__i] = nullptr; - __next_pointer __pp = __first_node_.__ptr(); - __next_pointer __cp = __pp->__next_; - if (__cp != nullptr) { - size_type __chash = std::__constrain_hash(__cp->__hash(), __nbc); - __bucket_list_[__chash] = __pp; - size_type __phash = __chash; - for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) { - __chash = std::__constrain_hash(__cp->__hash(), __nbc); - if (__chash == __phash) - __pp = __cp; - else { - if (__bucket_list_[__chash] == nullptr) { - __bucket_list_[__chash] = __pp; - __pp = __cp; - __phash = __chash; - } else { - __next_pointer __np = __cp; - if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys) { - for (; __np->__next_ != nullptr && - key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value()); - __np = __np->__next_) - ; - } - __pp->__next_ = __np->__next_; - __np->__next_ = __bucket_list_[__chash]->__next_; - __bucket_list_[__chash]->__next_ = __cp; - } +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __bucket_count) { + __pointer_allocator& __ptr_alloc = __bucket_list_.get_deleter().__alloc(); + __bucket_list_.reset(__bucket_count > 0 ? __pointer_alloc_traits::allocate(__ptr_alloc, __bucket_count) : nullptr); + __bucket_list_.get_deleter().size() = __bucket_count; + + if (__bucket_count == 0) + return; + + for (size_type __i = 0; __i < __bucket_count; ++__i) + __bucket_list_[__i] = nullptr; + __next_pointer __pp = __first_node_.__ptr(); + __next_pointer __cp = __pp->__next_; + + if (!__cp) + return; + + size_type __chash = std::__constrain_hash(__cp->__hash(), __bucket_count); + __bucket_list_[__chash] = __pp; + size_type __phash = __chash; + for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) { + __chash = std::__constrain_hash(__cp->__hash(), __bucket_count); + if (__chash == __phash) + __pp = __cp; + else { + if (__bucket_list_[__chash] == nullptr) { + __bucket_list_[__chash] = __pp; + __pp = __cp; + __phash = __chash; + } else { + __next_pointer __np = __cp; + if _LIBCPP_CONSTEXPR (!_UniqueKeys) { + for (; __np->__next_ != nullptr && + key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value()); + __np = __np->__next_) + ; } + __pp->__next_ = __np->__next_; + __np->__next_ = __bucket_list_[__chash]->__next_; + __bucket_list_[__chash]->__next_ = __cp; } } } diff --git a/libcxx/include/__math/logarithms.h b/libcxx/include/__math/logarithms.h index 5f5f943..7343d6a 100644 --- a/libcxx/include/__math/logarithms.h +++ b/libcxx/include/__math/logarithms.h @@ -58,7 +58,7 @@ inline _LIBCPP_HIDE_FROM_ABI double log10(_A1 __x) _NOEXCEPT { inline _LIBCPP_HIDE_FROM_ABI int ilogb(float __x) _NOEXCEPT { return __builtin_ilogbf(__x); } template <class = int> -_LIBCPP_HIDE_FROM_ABI double ilogb(double __x) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int ilogb(double __x) _NOEXCEPT { return __builtin_ilogb(__x); } diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 1623702..23a391d 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -106,6 +106,11 @@ public: void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...)); // constexpr in C++20 constexpr void swap(const tuple&) const noexcept(see-below); // C++23 + + template<tuple-like UTuple> + friend constexpr bool operator==(const tuple& t, const UTuple& u); // C++23 + template<tuple-like UTuple> + friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // C++23 }; @@ -220,6 +225,7 @@ template <class... Types> # include <__config> # include <__cstddef/size_t.h> # include <__fwd/array.h> +# include <__fwd/get.h> # include <__fwd/pair.h> # include <__fwd/tuple.h> # include <__memory/allocator_arg_t.h> @@ -229,6 +235,7 @@ template <class... Types> # include <__tuple/make_tuple_types.h> # include <__tuple/sfinae_helpers.h> # include <__tuple/tuple_element.h> +# include <__tuple/tuple_like.h> # include <__tuple/tuple_like_ext.h> # include <__tuple/tuple_size.h> # include <__tuple/tuple_types.h> @@ -287,6 +294,68 @@ _LIBCPP_BEGIN_NAMESPACE_STD # ifndef _LIBCPP_CXX03_LANG +template <size_t _Ip, class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __tuple_compare_equal(const _Tp& __x, const _Up& __y) { + if constexpr (_Ip == 0) + return true; + else + return std::__tuple_compare_equal<_Ip - 1>(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); +} + +# if _LIBCPP_STD_VER >= 26 +template <class _Tp, class _Up, class _IndexSeq = make_index_sequence<tuple_size_v<_Tp>>> +inline constexpr bool __can_tuple_compare_equal = false; + +// TODO(LLVM 22): Remove `tuple_size_v<_Tp> == tuple_size_v<_Up>` here once once LLVM-20 support ends +// because the resolution of CWG2369 landed in LLVM-21. +template <class _Tp, class _Up, size_t... _Is> + requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) +inline constexpr bool __can_tuple_compare_equal<_Tp, _Up, index_sequence<_Is...>> = + __all<requires(const tuple_element_t<_Is, _Tp>& __t, const tuple_element_t<_Is, _Up>& __u) { + { __t == __u } -> __boolean_testable; + }...>::value; +# endif // _LIBCPP_STD_VER >= 26 + +# if _LIBCPP_STD_VER >= 20 +template <class _Ret, class _Tp, class _Up, size_t... _Is> +_LIBCPP_HIDE_FROM_ABI constexpr _Ret __tuple_compare_three_way(const _Tp& __x, const _Up& __y, index_sequence<_Is...>) { + _Ret __result = strong_ordering::equal; + static_cast<void>( + ((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); + return __result; +} +# endif // _LIBCPP_STD_VER >= 20 + +# if _LIBCPP_STD_VER >= 23 +template <class> +inline constexpr bool __is_tuple_v = false; + +template <class... _Tp> +inline constexpr bool __is_tuple_v<tuple<_Tp...>> = true; + +template <class _Tp> +concept __tuple_like_no_tuple = __tuple_like<_Tp> && !__is_tuple_v<_Tp>; + +template <class _Tp, class _Up, class _IndexSeq> +struct __tuple_common_comparison_category_impl {}; + +// TODO(LLVM 22): Remove `tuple_size_v<_Tp> == tuple_size_v<_Up>` here once once LLVM-20 support ends +// because the resolution of CWG2369 landed in LLVM-21. +template <class _Tp, class _Up, size_t... _Is> + requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) && requires { + typename common_comparison_category_t< + __synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; + } +struct __tuple_common_comparison_category_impl<_Tp, _Up, index_sequence<_Is...>> { + using type _LIBCPP_NODEBUG = + common_comparison_category_t<__synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; +}; + +template <__tuple_like _Tp, __tuple_like _Up> +using __tuple_common_comparison_category _LIBCPP_NODEBUG = + __tuple_common_comparison_category_impl<_Tp, _Up, make_index_sequence<tuple_size_v<_Tp>>>::type; +# endif // _LIBCPP_STD_VER >= 23 + // __tuple_leaf template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value > @@ -448,33 +517,28 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __swallow(_Tp&&...) _NO template <class _Indx, class... _Tp> struct __tuple_impl; +struct __forward_args {}; +struct __value_init {}; + template <size_t... _Indx, class... _Tp> struct _LIBCPP_DECLSPEC_EMPTY_BASES __tuple_impl<__index_sequence<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>... { _LIBCPP_HIDE_FROM_ABI constexpr __tuple_impl() noexcept( __all<is_nothrow_default_constructible<_Tp>::value...>::value) {} - template <size_t... _Uf, class... _Tf, size_t... _Ul, class... _Tl, class... _Up> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl( - __index_sequence<_Uf...>, - __tuple_types<_Tf...>, - __index_sequence<_Ul...>, - __tuple_types<_Tl...>, - _Up&&... __u) noexcept(__all<is_nothrow_constructible<_Tf, _Up>::value...>::value && - __all<is_nothrow_default_constructible<_Tl>::value...>::value) - : __tuple_leaf<_Uf, _Tf>(std::forward<_Up>(__u))..., __tuple_leaf<_Ul, _Tl>()... {} - - template <class _Alloc, size_t... _Uf, class... _Tf, size_t... _Ul, class... _Tl, class... _Up> + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(__forward_args, _Args&&... __args) + : __tuple_leaf<_Indx, _Tp>(std::forward<_Args>(__args))... {} + + template <class _Alloc> + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(allocator_arg_t, const _Alloc& __alloc, __value_init) + : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc>(), __alloc)... {} + + template <class _Alloc, class... _Args> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl( - allocator_arg_t, - const _Alloc& __a, - __index_sequence<_Uf...>, - __tuple_types<_Tf...>, - __index_sequence<_Ul...>, - __tuple_types<_Tl...>, - _Up&&... __u) - : __tuple_leaf<_Uf, _Tf>(__uses_alloc_ctor<_Tf, _Alloc, _Up>(), __a, std::forward<_Up>(__u))..., - __tuple_leaf<_Ul, _Tl>(__uses_alloc_ctor<_Tl, _Alloc>(), __a)... {} + allocator_arg_t, const _Alloc& __alloc, __forward_args, _Args&&... __args) + : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc, _Args>(), __alloc, std::forward<_Args>(__args))... {} template <class _Tuple, __enable_if_t<__tuple_constructible<_Tuple, tuple<_Tp...> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(_Tuple&& __t) noexcept( @@ -559,12 +623,7 @@ public: __enable_if_t< _And< _IsDefault<_Tp>... >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, _IsImpDefault<_Tp>...> >::value) tuple(allocator_arg_t, _Alloc const& __a) - : __base_(allocator_arg_t(), - __a, - __index_sequence<>(), - __tuple_types<>(), - __make_index_sequence<sizeof...(_Tp)>(), - __tuple_types<_Tp...>()) {} + : __base_(allocator_arg_t(), __a, __value_init{}) {} // tuple(const T&...) constructors (including allocator_arg_t variants) template <template <class...> class _And = _And, @@ -572,11 +631,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> >::value) tuple(const _Tp&... __t) noexcept(_And<is_nothrow_copy_constructible<_Tp>...>::value) - : __base_(__make_index_sequence<sizeof...(_Tp)>(), - __tuple_types<_Tp...>(), - __index_sequence<>(), - __tuple_types<>(), - __t...) {} + : __base_(__forward_args{}, __t...) {} template <class _Alloc, template <class...> class _And = _And, @@ -584,13 +639,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> >::value) tuple(allocator_arg_t, const _Alloc& __a, const _Tp&... __t) - : __base_(allocator_arg_t(), - __a, - __make_index_sequence<sizeof...(_Tp)>(), - __tuple_types<_Tp...>(), - __index_sequence<>(), - __tuple_types<>(), - __t...) {} + : __base_(allocator_arg_t(), __a, __forward_args{}, __t...) {} // tuple(U&& ...) constructors (including allocator_arg_t variants) template <class... _Up> @@ -609,11 +658,7 @@ public: int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(_Up&&... __u) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) - : __base_(__make_index_sequence<sizeof...(_Up)>(), - __tuple_types<_Tp...>(), - __index_sequence<>(), - __tuple_types<>(), - std::forward<_Up>(__u)...) {} + : __base_(__forward_args{}, std::forward<_Up>(__u)...) {} template <class _Alloc, class... _Up, @@ -621,13 +666,7 @@ public: int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u) - : __base_(allocator_arg_t(), - __a, - __make_index_sequence<sizeof...(_Up)>(), - __tuple_types<_Tp...>(), - __index_sequence<>(), - __tuple_types<>(), - std::forward<_Up>(__u)...) {} + : __base_(allocator_arg_t(), __a, __forward_args{}, std::forward<_Up>(__u)...) {} // Copy and move constructors (including the allocator_arg_t variants) tuple(const tuple&) = default; @@ -986,7 +1025,24 @@ public: noexcept(__all<is_nothrow_swappable_v<const _Tp&>...>::value) { __base_.swap(__t.__base_); } -# endif // _LIBCPP_STD_VER >= 23 + + template <__tuple_like_no_tuple _UTuple> +# if _LIBCPP_STD_VER >= 26 + requires __can_tuple_compare_equal<tuple, _UTuple> && (sizeof...(_Tp) == tuple_size_v<_UTuple>) +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple& __x, const _UTuple& __y) { + static_assert(sizeof...(_Tp) == tuple_size_v<_UTuple>, "Can't compare tuple-like values of different sizes"); + return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); + } + + template <__tuple_like_no_tuple _UTuple> + requires(sizeof...(_Tp) == tuple_size_v<_UTuple>) + _LIBCPP_HIDE_FROM_ABI friend constexpr __tuple_common_comparison_category<tuple, _UTuple> + operator<=>(const tuple& __x, const _UTuple& __y) { + return std::__tuple_compare_three_way<__tuple_common_comparison_category<tuple, _UTuple>>( + __x, __y, index_sequence_for<_Tp...>{}); + } +# endif // _LIBCPP_STD_VER >= 23 }; _LIBCPP_DIAGNOSTIC_PUSH @@ -1008,6 +1064,21 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(tuple&) _NOEXCEPT {} # if _LIBCPP_STD_VER >= 23 _LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} + + template <__tuple_like_no_tuple _UTuple> +# if _LIBCPP_STD_VER >= 26 + requires(tuple_size_v<_UTuple> == 0) +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple&, const _UTuple&) { + static_assert(tuple_size_v<_UTuple> == 0, "Can't compare tuple-like values of different sizes"); + return true; + } + + template <__tuple_like_no_tuple _UTuple> + requires(tuple_size_v<_UTuple> == 0) + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering operator<=>(const tuple&, const _UTuple&) { + return strong_ordering::equal; + } # endif }; _LIBCPP_DIAGNOSTIC_POP @@ -1126,22 +1197,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> forwa return tuple<_Tp&&...>(std::forward<_Tp>(__t)...); } -template <size_t _Ip> -struct __tuple_equal { - template <class _Tp, class _Up> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __x, const _Up& __y) { - return __tuple_equal<_Ip - 1>()(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); - } -}; - -template <> -struct __tuple_equal<0> { - template <class _Tp, class _Up> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp&, const _Up&) { - return true; - } -}; - template <class... _Tp, class... _Up> # if _LIBCPP_STD_VER >= 26 requires(__all<requires(const _Tp& __t, const _Up& __u) { @@ -1151,27 +1206,19 @@ template <class... _Tp, class... _Up> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes"); - return __tuple_equal<sizeof...(_Tp)>()(__x, __y); + return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); } # if _LIBCPP_STD_VER >= 20 // operator<=> -template <class... _Tp, class... _Up, size_t... _Is> -_LIBCPP_HIDE_FROM_ABI constexpr auto -__tuple_compare_three_way(const tuple<_Tp...>& __x, const tuple<_Up...>& __y, index_sequence<_Is...>) { - common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> __result = strong_ordering::equal; - static_cast<void>( - ((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); - return __result; -} - template <class... _Tp, class... _Up> requires(sizeof...(_Tp) == sizeof...(_Up)) _LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> operator<=>(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { - return std::__tuple_compare_three_way(__x, __y, index_sequence_for<_Tp...>{}); + return std::__tuple_compare_three_way<common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...>>( + __x, __y, index_sequence_for<_Tp...>{}); } # else // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/version b/libcxx/include/version index d98049b..aae9277 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -555,7 +555,7 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_constexpr_new 202406L # endif # define __cpp_lib_constexpr_queue 202502L -// # define __cpp_lib_constrained_equality 202411L +# define __cpp_lib_constrained_equality 202411L // # define __cpp_lib_copyable_function 202306L // # define __cpp_lib_debugging 202311L // # define __cpp_lib_default_template_type_for_algorithm_values 202403L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp index 74cf85e..4ec6c46 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp @@ -93,17 +93,11 @@ #elif TEST_STD_VER > 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # ifndef __cpp_lib_expected diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp index 148a6db..ccdb1a8 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp @@ -119,17 +119,11 @@ #elif TEST_STD_VER > 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp index b10441f..ceb338d 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp @@ -270,17 +270,11 @@ # error "__cpp_lib_constexpr_tuple should have the value 201811L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # ifndef __cpp_lib_make_from_tuple diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp index 02e7feb..b882a5d 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp @@ -401,17 +401,11 @@ # error "__cpp_lib_constexpr_utility should have the value 201811L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # ifndef __cpp_lib_exchange_function diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp index dea2f29..ed0bb22 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp @@ -99,17 +99,11 @@ #elif TEST_STD_VER > 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # if !defined(_LIBCPP_VERSION) 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 962688e..7bd8e89 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 @@ -6631,17 +6631,11 @@ # error "__cpp_lib_constexpr_vector should have the value 201907L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should be defined in c++26" -# endif -# if __cpp_lib_constrained_equality != 202411L -# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" -# endif -# else -# ifdef __cpp_lib_constrained_equality -# error "__cpp_lib_constrained_equality should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_constrained_equality +# error "__cpp_lib_constrained_equality should be defined in c++26" +# endif +# if __cpp_lib_constrained_equality != 202411L +# error "__cpp_lib_constrained_equality should have the value 202411L in c++26" # endif # ifndef __cpp_lib_containers_ranges diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp index 779a89b..b0301f3 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp @@ -13,6 +13,8 @@ // template<class... TTypes, class... UTypes> // bool // operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u); +// template<tuple-like UTuple> +// friend constexpr bool operator==(const tuple& t, const UTuple& u); // since C++23 // UNSUPPORTED: c++03 @@ -23,6 +25,13 @@ #include "test_comparisons.h" #include "test_macros.h" +#if TEST_STD_VER >= 23 +# include <ranges> +#endif +#if TEST_STD_VER >= 26 +# include <complex> +#endif + #if TEST_STD_VER >= 26 // Test SFINAE. @@ -41,140 +50,249 @@ static_assert( static_assert( !std::equality_comparable_with<std::tuple<EqualityComparable, EqualityComparable>, std::tuple<EqualityComparable>>); +// Heterogeneous comparisons. +// TODO: Use equality_comparable_with once other changes of tuple introduced in P2165R4 are implemented. +template <class T, class U> +concept can_eq_compare = requires(const T& t, const U& u) { t == u; }; + +static_assert(can_eq_compare<std::tuple<EqualityComparable>, std::array<EqualityComparable, 1>>); +static_assert(!can_eq_compare<std::tuple<EqualityComparable>, std::array<NonComparable, 1>>); + +static_assert(can_eq_compare<std::tuple<EqualityComparable, EqualityComparable>, + std::pair<EqualityComparable, EqualityComparable>>); +static_assert( + !can_eq_compare<std::tuple<EqualityComparable, EqualityComparable>, std::pair<EqualityComparable, NonComparable>>); + +static_assert(can_eq_compare<std::tuple<int*, int*>, std::ranges::subrange<const int*>>); +static_assert(!can_eq_compare<std::tuple<int (*)[1], int (*)[1]>, std::ranges::subrange<const int*>>); +static_assert(can_eq_compare<std::tuple<double, double>, std::complex<float>>); +static_assert(!can_eq_compare<std::tuple<int*, int*>, std::complex<float>>); + +// Size mismatch in heterogeneous comparisons. +static_assert(!can_eq_compare<std::tuple<>, std::array<EqualityComparable, 2>>); +static_assert(!can_eq_compare<std::tuple<EqualityComparable>, std::array<EqualityComparable, 2>>); +static_assert(!can_eq_compare<std::tuple<>, std::pair<EqualityComparable, EqualityComparable>>); +static_assert(!can_eq_compare<std::tuple<EqualityComparable>, std::pair<EqualityComparable, EqualityComparable>>); +static_assert(!can_eq_compare<std::tuple<int*>, std::ranges::subrange<int*>>); +static_assert(!can_eq_compare<std::tuple<double>, std::complex<double>>); + #endif -int main(int, char**) -{ - { - typedef std::tuple<> T1; - typedef std::tuple<> T2; - const T1 t1; - const T2 t2; - assert(t1 == t2); - assert(!(t1 != t2)); - } - { - typedef std::tuple<int> T1; - typedef std::tuple<double> T2; - const T1 t1(1); - const T2 t2(1.1); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<int> T1; - typedef std::tuple<double> T2; - const T1 t1(1); - const T2 t2(1); - assert(t1 == t2); - assert(!(t1 != t2)); - } - { - typedef std::tuple<int, double> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1, 2); - assert(t1 == t2); - assert(!(t1 != t2)); - } - { - typedef std::tuple<int, double> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1, 3); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<int, double> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1.1, 2); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<int, double> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1.1, 3); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 2, 3); - assert(t1 == t2); - assert(!(t1 != t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1.1, 2, 3); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 3, 3); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 2, 4); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 3, 2); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1.1, 2, 2); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1.1, 3, 3); - assert(!(t1 == t2)); - assert(t1 != t2); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1.1, 3, 2); - assert(!(t1 == t2)); - assert(t1 != t2); - } -#if TEST_STD_VER > 11 - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - constexpr T1 t1(1, 2, 3); - constexpr T2 t2(1.1, 3, 2); - static_assert(!(t1 == t2), ""); - static_assert(t1 != t2, ""); - } +TEST_CONSTEXPR_CXX14 bool test() { + { + typedef std::tuple<> T1; + typedef std::tuple<> T2; + const T1 t1; + const T2 t2; + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + typedef std::tuple<int> T1; + typedef std::tuple<double> T2; + const T1 t1(1); + const T2 t2(1.1); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<int> T1; + typedef std::tuple<double> T2; + const T1 t1(1); + const T2 t2(1); + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + typedef std::tuple<int, double> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1, 2); + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + typedef std::tuple<int, double> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1, 3); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<int, double> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1.1, 2); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<int, double> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1.1, 3); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 2, 3); + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1.1, 2, 3); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 3, 3); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 2, 4); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 3, 2); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1.1, 2, 2); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1.1, 3, 3); + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1.1, 3, 2); + assert(!(t1 == t2)); + assert(t1 != t2); + } +#if TEST_STD_VER >= 14 + { + using T1 = std::tuple<long, int, double>; + using T2 = std::tuple<double, long, int>; + constexpr T1 t1(1, 2, 3); + constexpr T2 t2(1.1, 3, 2); + assert(!(t1 == t2)); + assert(t1 != t2); + } #endif +#if TEST_STD_VER >= 23 + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2}; + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3}; + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + + int arr[1]{}; + T1 t1{arr, arr + 1}; + T2 t2{arr}; + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + int arr[1]{}; + T1 t1{arr, arr}; + T2 t2{arr}; + assert(!(t1 == t2)); + assert(t1 != t2); + } + { + assert((std::tuple<>{} == std::array<int*, 0>{})); + assert((std::tuple<>{} == std::array<double, 0>{})); + } +#endif +#if TEST_STD_VER >= 26 + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + assert(t1 == t2); + assert(!(t1 != t2)); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + assert(!(t1 == t2)); + assert(t1 != t2); + } +#endif + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp index 0ece614..ef50454 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp @@ -28,186 +28,305 @@ // UNSUPPORTED: c++03 -#include <tuple> -#include <string> #include <cassert> +#include <tuple> #include "test_macros.h" -int main(int, char**) -{ - { - typedef std::tuple<> T1; - typedef std::tuple<> T2; - const T1 t1; - const T2 t2; - assert(!(t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long> T1; - typedef std::tuple<double> T2; - const T1 t1(1); - const T2 t2(1); - assert(!(t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long> T1; - typedef std::tuple<double> T2; - const T1 t1(1); - const T2 t2(0.9); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long> T1; - typedef std::tuple<double> T2; - const T1 t1(1); - const T2 t2(1.1); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } - { - typedef std::tuple<long, int> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1, 2); - assert(!(t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(0.9, 2); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1.1, 2); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } - { - typedef std::tuple<long, int> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1, 1); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int> T1; - typedef std::tuple<double, long> T2; - const T1 t1(1, 2); - const T2 t2(1, 3); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 2, 3); - assert(!(t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(0.9, 2, 3); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1.1, 2, 3); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 1, 3); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 3, 3); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 2, 2); - assert(!(t1 < t2)); - assert(!(t1 <= t2)); - assert( (t1 > t2)); - assert( (t1 >= t2)); - } - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - const T1 t1(1, 2, 3); - const T2 t2(1, 2, 4); - assert( (t1 < t2)); - assert( (t1 <= t2)); - assert(!(t1 > t2)); - assert(!(t1 >= t2)); - } -#if TEST_STD_VER > 11 - { - typedef std::tuple<long, int, double> T1; - typedef std::tuple<double, long, int> T2; - constexpr T1 t1(1, 2, 3); - constexpr T2 t2(1, 2, 4); - static_assert( (t1 < t2), ""); - static_assert( (t1 <= t2), ""); - static_assert(!(t1 > t2), ""); - static_assert(!(t1 >= t2), ""); - } +#if TEST_STD_VER >= 23 +# include <array> +# include <ranges> +# include <utility> +#endif +#if TEST_STD_VER >= 26 +# include <complex> +#endif + +TEST_CONSTEXPR_CXX14 bool test() { + { + typedef std::tuple<> T1; + typedef std::tuple<> T2; + const T1 t1; + const T2 t2; + assert(!(t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long> T1; + typedef std::tuple<double> T2; + const T1 t1(1); + const T2 t2(1); + assert(!(t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long> T1; + typedef std::tuple<double> T2; + const T1 t1(1); + const T2 t2(0.9); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long> T1; + typedef std::tuple<double> T2; + const T1 t1(1); + const T2 t2(1.1); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + typedef std::tuple<long, int> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1, 2); + assert(!(t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(0.9, 2); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1.1, 2); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + typedef std::tuple<long, int> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1, 1); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int> T1; + typedef std::tuple<double, long> T2; + const T1 t1(1, 2); + const T2 t2(1, 3); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 2, 3); + assert(!(t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(0.9, 2, 3); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1.1, 2, 3); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 1, 3); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 3, 3); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 2, 2); + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert((t1 > t2)); + assert((t1 >= t2)); + } + { + typedef std::tuple<long, int, double> T1; + typedef std::tuple<double, long, int> T2; + const T1 t1(1, 2, 3); + const T2 t2(1, 2, 4); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } +#if TEST_STD_VER >= 14 + { + using T1 = std::tuple<long, int, double>; + using T2 = std::tuple<double, long, int>; + constexpr T1 t1(1, 2, 3); + constexpr T2 t2(1, 2, 4); + assert((t1 < t2)); + assert((t1 <= t2)); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } +#endif +#if TEST_STD_VER >= 23 + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 3}; + assert(t1 < t2); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + assert(t1 < t2); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + + int arr[1]{}; + T1 t1{arr, arr + 1}; + T2 t2{arr}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + + int arr[1]{}; + T1 t1{arr + 1, arr + 1}; + T2 t2{arr}; + assert(!(t1 < t2)); + assert(!(t1 <= t2)); + assert(t1 > t2); + assert(t1 >= t2); + } + { + constexpr std::tuple<> t1{}; + constexpr std::array<int*, 0> t2{}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } + { + constexpr std::tuple<> t1{}; + constexpr std::array<double, 0> t2{}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } +#endif +#if TEST_STD_VER >= 26 + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + assert(!(t1 < t2)); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(t1 >= t2); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + assert(t1 < t2); + assert(t1 <= t2); + assert(!(t1 > t2)); + assert(!(t1 >= t2)); + } #endif + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_three_way.compile.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_three_way.compile.pass.cpp index f9c72a1..8eae8d6 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_three_way.compile.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_three_way.compile.pass.cpp @@ -13,16 +13,31 @@ // template<class... TTypes, class... UTypes> // auto // operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u); +// template<tuple-like UTuple> +// friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // since C++23 // UNSUPPORTED: c++03, c++11, c++14, c++17 +#include <array> +#include <complex> +#include <ranges> #include <tuple> +#include <utility> template <class T, class U> concept can_compare = requires(T t, U u) { t <=> u; }; -typedef std::tuple<int> T1; -typedef std::tuple<int, long> T2; +using T1 = std::tuple<int>; +using T2 = std::tuple<int, long>; +using T1P = std::tuple<int*>; static_assert(!can_compare<T1, T2>); static_assert(!can_compare<T2, T1>); +static_assert(!can_compare<T1, std::array<int, 2>>); +static_assert(!can_compare<std::array<int, 2>, T1>); +static_assert(!can_compare<T1, std::pair<int, long>>); +static_assert(!can_compare<std::pair<int, long>, T1>); +static_assert(!can_compare<T1, std::complex<double>>); +static_assert(!can_compare<std::complex<double>, T1>); +static_assert(!can_compare<T1P, std::ranges::subrange<int*>>); +static_assert(!can_compare<std::ranges::subrange<int*>, T1P>); diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/three_way.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/three_way.pass.cpp index d9543148..697d0c0 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/three_way.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/three_way.pass.cpp @@ -13,6 +13,8 @@ // template<class... TTypes, class... UTypes> // auto // operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u); +// template<tuple-like UTuple> +// friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // since C++23 // UNSUPPORTED: c++03, c++11, c++14, c++17 @@ -22,11 +24,15 @@ TEST_CLANG_DIAGNOSTIC_IGNORED("-Wsign-compare") TEST_GCC_DIAGNOSTIC_IGNORED("-Wsign-compare") TEST_MSVC_DIAGNOSTIC_IGNORED(4242 4244) +#include <array> #include <cassert> #include <compare> +#include <complex> #include <limits> +#include <ranges> #include <tuple> #include <type_traits> // std::is_constant_evaluated +#include <utility> // A custom three-way result type struct CustomEquality { @@ -36,6 +42,11 @@ struct CustomEquality { }; constexpr bool test() { + struct WeakSpaceship { + constexpr bool operator==(const WeakSpaceship&) const { return true; } + constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; } + }; + // Empty tuple { typedef std::tuple<> T0; @@ -135,23 +146,17 @@ constexpr bool test() { ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); } { - struct WeakSpaceship { - constexpr bool operator==(const WeakSpaceship&) const { return true; } - constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; } - }; - { - typedef std::tuple<int, unsigned int, WeakSpaceship> T1; - typedef std::tuple<int, unsigned long, WeakSpaceship> T2; - // Strongly ordered members and a weakly ordered member yields weak ordering. - ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); - } - { - typedef std::tuple<unsigned int, int, WeakSpaceship> T1; - typedef std::tuple<double, long, WeakSpaceship> T2; - // Doubles are partially ordered, so one partial, one strong, and one weak ordering - // yields partial ordering. - ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); - } + typedef std::tuple<int, unsigned int, WeakSpaceship> T1; + typedef std::tuple<int, unsigned long, WeakSpaceship> T2; + // Strongly ordered members and a weakly ordered member yields weak ordering. + ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); + } + { + typedef std::tuple<unsigned int, int, WeakSpaceship> T1; + typedef std::tuple<double, long, WeakSpaceship> T2; + // Doubles are partially ordered, so one partial, one strong, and one weak ordering + // yields partial ordering. + ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); } { struct NoSpaceship { @@ -224,6 +229,134 @@ constexpr bool test() { } } +// Heterogeneous comparisons enabled by P2165R4. +#if TEST_STD_VER >= 23 + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<int, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1, 2}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::equal); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<int, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1, 0}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::greater); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::less); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::equivalent); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::pair<double, long>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::less); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::equivalent); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::array<double, 2>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::less); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + + int arr[1]{}; + T1 t1{arr, arr + 1}; + T2 t2{arr}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::equal); + } + { + using T1 = std::tuple<const int*, const int*>; + using T2 = std::ranges::subrange<const int*>; + + int arr[1]{}; + T1 t1{arr + 1, arr + 1}; + T2 t2{arr}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::greater); + } + { + constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{}; + constexpr std::pair<WeakSpaceship, WeakSpaceship> t2{}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering); + assert((t1 <=> t2) == std::weak_ordering::equivalent); + } + { + constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{}; + constexpr std::array<WeakSpaceship, 2> t2{}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering); + assert((t1 <=> t2) == std::weak_ordering::equivalent); + } + { + constexpr std::tuple<> t1{}; + constexpr std::array<int*, 0> t2{}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::equal); + } + { + constexpr std::tuple<> t1{}; + constexpr std::array<double, 0> t2{}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::equal); + } + { + constexpr std::tuple<> t1{}; + constexpr std::array<WeakSpaceship, 0> t2{}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering); + assert((t1 <=> t2) == std::strong_ordering::equal); + } +#endif +#if TEST_STD_VER >= 26 + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.0, 2.0}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::equivalent); + } + { + using T1 = std::tuple<long, int>; + using T2 = std::complex<double>; + constexpr T1 t1{1, 2}; + constexpr T2 t2{1.1, 3.0}; + ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering); + assert((t1 <=> t2) == std::partial_ordering::less); + } +#endif + return true; } diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h index a091043..8416de7 100644 --- a/libcxx/test/support/check_assertion.h +++ b/libcxx/test/support/check_assertion.h @@ -52,8 +52,8 @@ MatchResult MatchAssertionMessage(const std::string& text, std::string_view expe // library. std::string assertion_format_string = [&] { if (use_marker) - return (".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###"); - return ("(.*):(\\d+): assertion (.*) failed: (.*)\\n"); + return (".*###\\n(.*):(\\d+): libc\\+\\+ Hardening assertion (.*) failed: (.*)\\n###"); + return ("(.*):(\\d+): libc\\+\\+ Hardening assertion (.*) failed: (.*)\\n"); }(); std::regex assertion_format(assertion_format_string); diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index fe175fd7..d9317e0 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -442,11 +442,9 @@ feature_test_macros = [ { "name": "__cpp_lib_constrained_equality", "values": { - # "c++26": 202403, # P2944R3: Comparisons for reference_wrapper "c++26": 202411, # P3379R0: Constrain std::expected equality operators }, "headers": ["expected", "optional", "tuple", "utility", "variant"], - "unimplemented": True, }, { "name": "__cpp_lib_containers_ranges", |