[libcxx-commits] [libcxx] 4884d6c - [libc++] Extend __default_three_way_comparator to any types that only implements operator<=> (#157602)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 12 01:57:38 PDT 2025
Author: Nikolas Klauser
Date: 2025-09-12T10:57:34+02:00
New Revision: 4884d6cbce99286e349e239c1c1103b9f3820b56
URL: https://github.com/llvm/llvm-project/commit/4884d6cbce99286e349e239c1c1103b9f3820b56
DIFF: https://github.com/llvm/llvm-project/commit/4884d6cbce99286e349e239c1c1103b9f3820b56.diff
LOG: [libc++] Extend __default_three_way_comparator to any types that only implements operator<=> (#157602)
This uses the new `__builtin_lt_synthesises_from_spaceship` builtin from
clang to use three way comparison for arbitrary user-defined types that
only provide a spaceship operator.
Added:
libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
Modified:
libcxx/include/__type_traits/desugars_to.h
libcxx/include/__utility/default_three_way_comparator.h
libcxx/include/__utility/lazy_synth_three_way_comparator.h
libcxx/include/string
Removed:
################################################################################
diff --git a/libcxx/include/__type_traits/desugars_to.h b/libcxx/include/__type_traits/desugars_to.h
index b67baae31b181..029b3c6336837 100644
--- a/libcxx/include/__type_traits/desugars_to.h
+++ b/libcxx/include/__type_traits/desugars_to.h
@@ -10,6 +10,7 @@
#define _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H
#include <__config>
+#include <__type_traits/integral_constant.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -64,6 +65,9 @@ template <class _CanonicalTag, class _Operation, class... _Args>
inline const bool __desugars_to_v<_CanonicalTag, _Operation&&, _Args...> =
__desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+template <class _CanonicalTag, class _Operation, class... _Args>
+struct __desugars_to : integral_constant<bool, __desugars_to_v<_CanonicalTag, _Operation, _Args...> > {};
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H
diff --git a/libcxx/include/__utility/default_three_way_comparator.h b/libcxx/include/__utility/default_three_way_comparator.h
index ce423c6ce98e4..438ab55b43230 100644
--- a/libcxx/include/__utility/default_three_way_comparator.h
+++ b/libcxx/include/__utility/default_three_way_comparator.h
@@ -27,9 +27,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _LHS, class _RHS, class = void>
struct __default_three_way_comparator;
-template <class _Tp>
-struct __default_three_way_comparator<_Tp, _Tp, __enable_if_t<is_arithmetic<_Tp>::value> > {
- _LIBCPP_HIDE_FROM_ABI static int operator()(_Tp __lhs, _Tp __rhs) {
+template <class _LHS, class _RHS>
+struct __default_three_way_comparator<_LHS,
+ _RHS,
+ __enable_if_t<is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value> > {
+ _LIBCPP_HIDE_FROM_ABI static int operator()(_LHS __lhs, _RHS __rhs) {
if (__lhs < __rhs)
return -1;
if (__lhs > __rhs)
@@ -38,12 +40,30 @@ struct __default_three_way_comparator<_Tp, _Tp, __enable_if_t<is_arithmetic<_Tp>
}
};
+#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_lt_synthesises_from_spaceship)
+template <class _LHS, class _RHS>
+struct __default_three_way_comparator<
+ _LHS,
+ _RHS,
+ __enable_if_t<!(is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value) &&
+ __builtin_lt_synthesises_from_spaceship(const _LHS&, const _RHS&)>> {
+ _LIBCPP_HIDE_FROM_ABI static int operator()(const _LHS& __lhs, const _RHS& __rhs) {
+ auto __res = __lhs <=> __rhs;
+ if (__res < 0)
+ return -1;
+ if (__res > 0)
+ return 1;
+ return 0;
+ }
+};
+#endif
+
template <class _LHS, class _RHS, bool = true>
-inline const bool __has_default_three_way_comparator_v = false;
+struct __has_default_three_way_comparator : false_type {};
template <class _LHS, class _RHS>
-inline const bool
- __has_default_three_way_comparator_v< _LHS, _RHS, sizeof(__default_three_way_comparator<_LHS, _RHS>) >= 0> = true;
+struct __has_default_three_way_comparator<_LHS, _RHS, sizeof(__default_three_way_comparator<_LHS, _RHS>) >= 0>
+ : true_type {};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__utility/lazy_synth_three_way_comparator.h b/libcxx/include/__utility/lazy_synth_three_way_comparator.h
index ca98845f04191..9105d05e1ed6a 100644
--- a/libcxx/include/__utility/lazy_synth_three_way_comparator.h
+++ b/libcxx/include/__utility/lazy_synth_three_way_comparator.h
@@ -10,6 +10,7 @@
#define _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H
#include <__config>
+#include <__type_traits/conjunction.h>
#include <__type_traits/desugars_to.h>
#include <__type_traits/enable_if.h>
#include <__utility/default_three_way_comparator.h>
@@ -69,11 +70,12 @@ struct __eager_compare_result {
};
template <class _Comparator, class _LHS, class _RHS>
-struct __lazy_synth_three_way_comparator<_Comparator,
- _LHS,
- _RHS,
- __enable_if_t<__desugars_to_v<__less_tag, _Comparator, _LHS, _RHS> &&
- __has_default_three_way_comparator_v<_LHS, _RHS> > > {
+struct __lazy_synth_three_way_comparator<
+ _Comparator,
+ _LHS,
+ _RHS,
+ __enable_if_t<_And<__desugars_to<__less_tag, _Comparator, _LHS, _RHS>,
+ __has_default_three_way_comparator<_LHS, _RHS> >::value> > {
// This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of
// the comparator.
_LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {}
diff --git a/libcxx/include/string b/libcxx/include/string
index 0abdfebcb863f..f13a7640760f7 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -2521,6 +2521,7 @@ _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_DECLARE, wchar_t)
# endif
# undef _LIBCPP_DECLARE
+# if _LIBCPP_STD_VER <= 17 || !__has_builtin(__builtin_lt_synthesises_from_spaceship)
template <class _CharT, class _Traits, class _Alloc>
struct __default_three_way_comparator<basic_string<_CharT, _Traits, _Alloc>, basic_string<_CharT, _Traits, _Alloc> > {
using __string_t _LIBCPP_NODEBUG = basic_string<_CharT, _Traits, _Alloc>;
@@ -2533,6 +2534,7 @@ struct __default_three_way_comparator<basic_string<_CharT, _Traits, _Alloc>, bas
return __ret;
}
};
+# endif
# if _LIBCPP_STD_VER >= 17
template <class _InputIterator,
diff --git a/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp b/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
new file mode 100644
index 0000000000000..42b4855a9fddd
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <__utility/default_three_way_comparator.h>
+#include <string>
+#include <vector>
+
+static_assert(std::__has_default_three_way_comparator<int, int>::value);
+static_assert(std::__has_default_three_way_comparator<int, long>::value);
+static_assert(std::__has_default_three_way_comparator<long, int>::value);
+static_assert(std::__has_default_three_way_comparator<long, long>::value);
+static_assert(std::__has_default_three_way_comparator<std::string, std::string>::value);
+
+#if __has_builtin(__builtin_lt_synthesises_from_spaceship)
+static_assert(std::__has_default_three_way_comparator<const std::string&, const std::string&>::value);
+static_assert(std::__has_default_three_way_comparator<const std::string&, const std::string_view&>::value);
+static_assert(std::__has_default_three_way_comparator<std::string, std::string_view>::value);
+static_assert(std::__has_default_three_way_comparator<const std::string&, const char*>::value);
+static_assert(std::__has_default_three_way_comparator<std::string, const char*>::value);
+static_assert(!std::__has_default_three_way_comparator<const std::string&, const wchar_t*>::value);
+
+static_assert(std::__has_default_three_way_comparator<const std::vector<int>&, const std::vector<int>&>::value);
+
+struct MyStruct {
+ int i;
+
+ friend auto operator<=>(MyStruct, MyStruct) = default;
+};
+
+static_assert(std::__has_default_three_way_comparator<const MyStruct&, const MyStruct&>::value);
+#endif
More information about the libcxx-commits
mailing list