aboutsummaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/docs/FeatureTestMacroTable.rst2
-rw-r--r--libcxx/docs/ReleaseNotes/21.rst2
-rw-r--r--libcxx/docs/Status/Cxx23Papers.csv2
-rw-r--r--libcxx/docs/Status/Cxx2cIssues.csv1
-rw-r--r--libcxx/docs/Status/Cxx2cPapers.csv2
-rw-r--r--libcxx/include/__assert4
-rw-r--r--libcxx/include/__config18
-rw-r--r--libcxx/include/__cxx03/__math/logarithms.h2
-rw-r--r--libcxx/include/__hash_table72
-rw-r--r--libcxx/include/__math/logarithms.h2
-rw-r--r--libcxx/include/tuple203
-rw-r--r--libcxx/include/version2
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp16
-rw-r--r--libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp380
-rw-r--r--libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp469
-rw-r--r--libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_three_way.compile.pass.cpp19
-rw-r--r--libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/three_way.pass.cpp167
-rw-r--r--libcxx/test/support/check_assertion.h4
-rw-r--r--libcxx/utils/generate_feature_test_macro_components.py2
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",