diff options
author | Kamlesh Kumar <kamlesbhalui@gmail.com> | 2021-04-20 04:48:34 +0530 |
---|---|---|
committer | Kamlesh Kumar <kamleshbhalui@gmail.com> | 2021-04-20 04:52:59 +0530 |
commit | 36c3918ec55b49180933acceb36dbd9e8b5c97ed (patch) | |
tree | e8138ad32c88129be0b4574830e6d69651a36180 | |
parent | cf899a31aebf60e91a8732c6c5900398797230be (diff) | |
download | llvm-36c3918ec55b49180933acceb36dbd9e8b5c97ed.zip llvm-36c3918ec55b49180933acceb36dbd9e8b5c97ed.tar.gz llvm-36c3918ec55b49180933acceb36dbd9e8b5c97ed.tar.bz2 |
[libc++] [C++20] [P0586] Implement safe integral comparisons
* https://wg21.link/P0586
Reviewed By: #libc, curdeius, Quuxplusone
Differential Revision: https://reviews.llvm.org/D94511
15 files changed, 947 insertions, 16 deletions
diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv index 1c5a84c..ce4da44 100644 --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -164,7 +164,7 @@ "`P1961 <https://wg21.link/P1961>`__","LWG","Harmonizing the definitions of total order for pointers","Belfast","* *","" "`P1965 <https://wg21.link/P1965>`__","LWG","Blanket Wording for Specifying ""Hidden Friends""","Belfast","* *","" "","","","","","" -"`P0586 <https://wg21.link/P0586>`__","LWG","Safe integral comparisons","Prague","* *","" +"`P0586 <https://wg21.link/P0586>`__","LWG","Safe integral comparisons","Prague","|Complete|","13.0" "`P0593 <https://wg21.link/P0593>`__","CWG","Implicit creation of objects for low-level object manipulation","Prague","* *","" "`P1115 <https://wg21.link/P1115>`__","LWG","Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if","Prague","|Complete|","11.0" "`P1243 <https://wg21.link/P1243>`__","LWG","Rangify New Algorithms","Prague","* *","" diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 8c4f2a8..ff5197f 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -240,7 +240,7 @@ Status ------------------------------------------------- ----------------- ``__cpp_lib_int_pow2`` ``202002L`` ------------------------------------------------- ----------------- - ``__cpp_lib_integer_comparison_functions`` *unimplemented* + ``__cpp_lib_integer_comparison_functions`` ``202002L`` ------------------------------------------------- ----------------- ``__cpp_lib_interpolate`` ``201902L`` ------------------------------------------------- ----------------- diff --git a/libcxx/include/utility b/libcxx/include/utility index 925b952..a49826e 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -58,6 +58,14 @@ template <class T> void as_const(const T&&) = delete; // C+ template <class T> typename add_rvalue_reference<T>::type declval() noexcept; +template<class T, class U> constexpr bool cmp_equal(T t, U u) noexcept; // C++20 +template<class T, class U> constexpr bool cmp_not_equal(T t, U u) noexcept; // C++20 +template<class T, class U> constexpr bool cmp_less(T t, U u) noexcept; // C++20 +template<class T, class U> constexpr bool cmp_greater(T t, U u) noexcept; // C++20 +template<class T, class U> constexpr bool cmp_less_equal(T t, U u) noexcept; // C++20 +template<class T, class U> constexpr bool cmp_greater_equal(T t, U u) noexcept; // C++20 +template<class R, class T> constexpr bool in_range(T t) noexcept; // C++20 + template <class T1, class T2> struct pair { @@ -207,6 +215,7 @@ template <class T> #include <cstddef> #include <cstring> #include <cstdint> +#include <limits> #include <version> #include <__debug> @@ -214,6 +223,9 @@ template <class T> #pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD namespace rel_ops @@ -284,6 +296,82 @@ template <class _Tp> void as_const(const _Tp&&) = delete; #endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) +template<class _Tp, class... _Up> +struct _IsSameAsAny : _Or<_IsSame<_Tp, _Up>...> {}; + +template<class _Tp> +concept __is_safe_integral_cmp = is_integral_v<_Tp> && + !_IsSameAsAny<_Tp, bool, char, +#ifndef _LIBCPP_NO_HAS_CHAR8_T + char8_t, +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + char16_t, char32_t, +#endif + wchar_t>::value; + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_equal(_Tp __t, _Up __u) noexcept +{ + if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) + return __t == __u; + else if constexpr (is_signed_v<_Tp>) + return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u; + else + return __u < 0 ? false : __t == make_unsigned_t<_Up>(__u); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_not_equal(_Tp __t, _Up __u) noexcept +{ + return !_VSTD::cmp_equal(__t, __u); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_less(_Tp __t, _Up __u) noexcept +{ + if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) + return __t < __u; + else if constexpr (is_signed_v<_Tp>) + return __t < 0 ? true : make_unsigned_t<_Tp>(__t) < __u; + else + return __u < 0 ? false : __t < make_unsigned_t<_Up>(__u); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_greater(_Tp __t, _Up __u) noexcept +{ + return _VSTD::cmp_less(__u, __t); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_less_equal(_Tp __t, _Up __u) noexcept +{ + return !_VSTD::cmp_greater(__t, __u); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool cmp_greater_equal(_Tp __t, _Up __u) noexcept +{ + return !_VSTD::cmp_less(__t, __u); +} + +template<__is_safe_integral_cmp _Tp, __is_safe_integral_cmp _Up> +_LIBCPP_INLINE_VISIBILITY constexpr +bool in_range(_Up __u) noexcept +{ + return _VSTD::cmp_less_equal(__u, numeric_limits<_Tp>::max()) && + _VSTD::cmp_greater_equal(__u, numeric_limits<_Tp>::min()); +} +#endif + struct _LIBCPP_TEMPLATE_VIS piecewise_construct_t { explicit piecewise_construct_t() = default; }; #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY) extern _LIBCPP_EXPORTED_FROM_ABI const piecewise_construct_t piecewise_construct;// = piecewise_construct_t(); @@ -1647,4 +1735,6 @@ to_underlying(_Tp __val) noexcept { _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP_UTILITY diff --git a/libcxx/include/version b/libcxx/include/version index 9de078a..440fc59 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -322,7 +322,9 @@ __cpp_lib_void_t 201411L <type_traits> // # define __cpp_lib_format 201907L # define __cpp_lib_generic_unordered_lookup 201811L # define __cpp_lib_int_pow2 202002L -// # define __cpp_lib_integer_comparison_functions 202002L +# if !defined(_LIBCPP_HAS_NO_CONCEPTS) +# define __cpp_lib_integer_comparison_functions 202002L +# endif # define __cpp_lib_interpolate 201902L # if !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) # define __cpp_lib_is_constant_evaluated 201811L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp index 1ec2f43..b5662f7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp @@ -184,16 +184,16 @@ # error "__cpp_lib_exchange_function should have the value 201304L in c++20" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(__cpp_concepts) && __cpp_concepts >= 201907L # ifndef __cpp_lib_integer_comparison_functions # error "__cpp_lib_integer_comparison_functions should be defined in c++20" # endif # if __cpp_lib_integer_comparison_functions != 202002L # error "__cpp_lib_integer_comparison_functions should have the value 202002L in c++20" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_integer_comparison_functions -# error "__cpp_lib_integer_comparison_functions should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_integer_comparison_functions should not be defined when defined(__cpp_concepts) && __cpp_concepts >= 201907L is not defined!" # endif # endif @@ -251,16 +251,16 @@ # error "__cpp_lib_exchange_function should have the value 201304L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(__cpp_concepts) && __cpp_concepts >= 201907L # ifndef __cpp_lib_integer_comparison_functions # error "__cpp_lib_integer_comparison_functions should be defined in c++2b" # endif # if __cpp_lib_integer_comparison_functions != 202002L # error "__cpp_lib_integer_comparison_functions should have the value 202002L in c++2b" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_integer_comparison_functions -# error "__cpp_lib_integer_comparison_functions should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_integer_comparison_functions should not be defined when defined(__cpp_concepts) && __cpp_concepts >= 201907L is not defined!" # endif # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp index f83917f..64db73f 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -2653,16 +2653,16 @@ # error "__cpp_lib_int_pow2 should have the value 202002L in c++20" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(__cpp_concepts) && __cpp_concepts >= 201907L # ifndef __cpp_lib_integer_comparison_functions # error "__cpp_lib_integer_comparison_functions should be defined in c++20" # endif # if __cpp_lib_integer_comparison_functions != 202002L # error "__cpp_lib_integer_comparison_functions should have the value 202002L in c++20" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_integer_comparison_functions -# error "__cpp_lib_integer_comparison_functions should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_integer_comparison_functions should not be defined when defined(__cpp_concepts) && __cpp_concepts >= 201907L is not defined!" # endif # endif @@ -3834,16 +3834,16 @@ # error "__cpp_lib_int_pow2 should have the value 202002L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(__cpp_concepts) && __cpp_concepts >= 201907L # ifndef __cpp_lib_integer_comparison_functions # error "__cpp_lib_integer_comparison_functions should be defined in c++2b" # endif # if __cpp_lib_integer_comparison_functions != 202002L # error "__cpp_lib_integer_comparison_functions should have the value 202002L in c++2b" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_integer_comparison_functions -# error "__cpp_lib_integer_comparison_functions should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_integer_comparison_functions should not be defined when defined(__cpp_concepts) && __cpp_concepts >= 201907L is not defined!" # endif # endif diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_equal/cmp_equal.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_equal/cmp_equal.pass.cpp new file mode 100644 index 0000000..7e88e4b --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_equal/cmp_equal.pass.cpp @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// template<class T, class U> +// constexpr bool cmp_equal(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_equal1() { + constexpr Tuple<T> tup; + assert(std::cmp_equal(T(0), T(0))); + assert(std::cmp_equal(T(10), T(10))); + assert(std::cmp_equal(tup.min, tup.min)); + assert(std::cmp_equal(tup.max, tup.max)); + assert(!std::cmp_equal(T(0), T(1))); + assert(!std::cmp_equal(T(1), T(0))); + assert(!std::cmp_equal(T(5), T(10))); + assert(!std::cmp_equal(T(10), T(5))); + assert(!std::cmp_equal(tup.min, tup.max)); + assert(!std::cmp_equal(tup.max, tup.min)); + assert(!std::cmp_equal(1, tup.max)); + assert(!std::cmp_equal(tup.max, 1)); + assert(!std::cmp_equal(1, tup.min)); + assert(!std::cmp_equal(tup.min, 1)); + assert(std::cmp_equal(T(-5), T(-5))); + assert(!std::cmp_equal(-2, tup.min)); + assert(!std::cmp_equal(tup.min, -2)); + assert(!std::cmp_equal(-2, tup.max)); + assert(!std::cmp_equal(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_equal2() { + constexpr Tuple<T> ttup; + constexpr Tuple<U> utup; + assert(std::cmp_equal(T(0), U(0))); + assert(std::cmp_equal(T(10), U(10))); + assert(!std::cmp_equal(T(0), U(1))); + assert(!std::cmp_equal(T(1), U(0))); + assert(!std::cmp_equal(T(5), U(10))); + assert(!std::cmp_equal(T(10), U(5))); + assert(!std::cmp_equal(ttup.min, utup.max)); + assert(!std::cmp_equal(utup.min, ttup.max)); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_equal1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_equal2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_equal(0, 0)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater/cmp_greater.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater/cmp_greater.pass.cpp new file mode 100644 index 0000000..0182c45 --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater/cmp_greater.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// constexpr bool cmp_greater(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_greater1() { + constexpr Tuple<T> tup; + assert(!std::cmp_greater(T(0), T(1))); + assert(!std::cmp_greater(T(1), T(2))); + assert(!std::cmp_greater(tup.min, tup.max)); + assert(!std::cmp_greater(tup.min, tup.mid)); + assert(!std::cmp_greater(tup.mid, tup.max)); + assert(std::cmp_greater(T(1), T(0))); + assert(std::cmp_greater(T(10), T(5))); + assert(std::cmp_greater(tup.max, tup.min)); + assert(std::cmp_greater(tup.mid, tup.min)); + assert(!std::cmp_greater(tup.mid, tup.mid)); + assert(!std::cmp_greater(tup.min, tup.min)); + assert(!std::cmp_greater(tup.max, tup.max)); + assert(std::cmp_greater(tup.max, 1)); + assert(std::cmp_greater(1, tup.min)); + assert(!std::cmp_greater(T(-1), T(-1))); + assert(std::cmp_greater(-2, tup.min) == std::is_signed_v<T>); + assert(!std::cmp_greater(tup.min, -2) == std::is_signed_v<T>); + assert(!std::cmp_greater(-2, tup.max)); + assert(std::cmp_greater(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_greater2() { + assert(!std::cmp_greater(T(0), U(1))); + assert(std::cmp_greater(T(1), U(0))); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_greater1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_greater2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_greater(1, 0)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater_equal/cmp_greater_equal.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater_equal/cmp_greater_equal.pass.cpp new file mode 100644 index 0000000..4b25615 --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_greater_equal/cmp_greater_equal.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// constexpr bool cmp_greater_equal(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_greater_equal1() { + constexpr Tuple<T> tup; + assert(!std::cmp_greater_equal(T(0), T(1))); + assert(!std::cmp_greater_equal(T(1), T(2))); + assert(!std::cmp_greater_equal(tup.min, tup.max)); + assert(!std::cmp_greater_equal(tup.min, tup.mid)); + assert(!std::cmp_greater_equal(tup.mid, tup.max)); + assert(std::cmp_greater_equal(T(1), T(0))); + assert(std::cmp_greater_equal(T(10), T(5))); + assert(std::cmp_greater_equal(tup.max, tup.min)); + assert(std::cmp_greater_equal(tup.mid, tup.min)); + assert(std::cmp_greater_equal(tup.mid, tup.mid)); + assert(std::cmp_greater_equal(tup.min, tup.min)); + assert(std::cmp_greater_equal(tup.max, tup.max)); + assert(std::cmp_greater_equal(tup.max, 1)); + assert(std::cmp_greater_equal(1, tup.min)); + assert(std::cmp_greater_equal(T(-1), T(-1))); + assert(std::cmp_greater_equal(-2, tup.min) == std::is_signed_v<T>); + assert(std::cmp_greater_equal(tup.min, -2) == std::is_unsigned_v<T>); + assert(!std::cmp_greater_equal(-2, tup.max)); + assert(std::cmp_greater_equal(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_greater_equal2() { + assert(!std::cmp_greater_equal(T(0), U(1))); + assert(std::cmp_greater_equal(T(1), U(0))); + assert(std::cmp_greater_equal(T(0), U(0))); + assert(std::cmp_greater_equal(T(1), U(1))); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_greater_equal1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_greater_equal2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_greater_equal(1, 0)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less/cmp_less.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less/cmp_less.pass.cpp new file mode 100644 index 0000000..70edebf --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less/cmp_less.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// template<class T, class U> +// constexpr bool cmp_less(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_less1() { + constexpr Tuple<T> tup; + assert(std::cmp_less(T(0), T(1))); + assert(std::cmp_less(T(1), T(2))); + assert(std::cmp_less(tup.min, tup.max)); + assert(std::cmp_less(tup.min, tup.mid)); + assert(std::cmp_less(tup.mid, tup.max)); + assert(!std::cmp_less(T(1), T(0))); + assert(!std::cmp_less(T(10), T(5))); + assert(!std::cmp_less(tup.max, tup.min)); + assert(!std::cmp_less(tup.mid, tup.min)); + assert(!std::cmp_less(tup.mid, tup.mid)); + assert(!std::cmp_less(tup.min, tup.min)); + assert(!std::cmp_less(tup.max, tup.max)); + assert(!std::cmp_less(tup.max, 1)); + assert(!std::cmp_less(1, tup.min)); + assert(!std::cmp_less(T(-1), T(-1))); + assert(!std::cmp_less(-2, tup.min) == std::is_signed_v<T>); + assert(std::cmp_less(tup.min, -2) == std::is_signed_v<T>); + assert(std::cmp_less(-2, tup.max)); + assert(!std::cmp_less(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_less2() { + assert(std::cmp_less(T(0), U(1))); + assert(!std::cmp_less(T(1), U(0))); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_less1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_less2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_less(0, 1)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less_equal/cmp_less_equal.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less_equal/cmp_less_equal.pass.cpp new file mode 100644 index 0000000..78c3c2a --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_less_equal/cmp_less_equal.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// constexpr bool cmp_less_equal(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_less_equal1() { + constexpr Tuple<T> tup; + assert(std::cmp_less_equal(T(0), T(0))); + assert(std::cmp_less_equal(T(0), T(1))); + assert(std::cmp_less_equal(tup.min, tup.max)); + assert(std::cmp_less_equal(tup.min, tup.mid)); + assert(std::cmp_less_equal(tup.mid, tup.max)); + assert(std::cmp_less_equal(tup.max, tup.max)); + assert(std::cmp_less_equal(tup.mid, tup.mid)); + assert(std::cmp_less_equal(tup.min, tup.min)); + assert(!std::cmp_less_equal(T(1), T(0))); + assert(!std::cmp_less_equal(T(10), T(5))); + assert(!std::cmp_less_equal(tup.max, tup.min)); + assert(!std::cmp_less_equal(tup.mid, tup.min)); + assert(!std::cmp_less_equal(tup.max, 1)); + assert(!std::cmp_less_equal(1, tup.min)); + assert(std::cmp_less_equal(T(-1), T(-1))); + assert(!std::cmp_less_equal(-2, tup.min) == std::is_signed_v<T>); + assert(std::cmp_less_equal(tup.min, -2) == std::is_signed_v<T>); + assert(std::cmp_less_equal(-2, tup.max)); + assert(!std::cmp_less_equal(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_less_equal2() { + assert(std::cmp_less_equal(T(0), U(1))); + assert(std::cmp_less_equal(T(0), U(0))); + assert(!std::cmp_less_equal(T(1), U(0))); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_less_equal1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_less_equal2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_less_equal(0, 1)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_not_equal/cmp_not_equal.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_not_equal/cmp_not_equal.pass.cpp new file mode 100644 index 0000000..70c2901 --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.cmp_not_equal/cmp_not_equal.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// template<class T, class U> +// constexpr bool cmp_not_equal(T t, U u) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_cmp_not_equal1() { + constexpr Tuple<T> tup; + assert(!std::cmp_not_equal(T(0), T(0))); + assert(!std::cmp_not_equal(T(10), T(10))); + assert(!std::cmp_not_equal(tup.min, tup.min)); + assert(!std::cmp_not_equal(tup.max, tup.max)); + assert(std::cmp_not_equal(T(0), T(1))); + assert(std::cmp_not_equal(T(1), T(0))); + assert(std::cmp_not_equal(T(5), T(10))); + assert(std::cmp_not_equal(T(10), T(5))); + assert(std::cmp_not_equal(tup.min, tup.max)); + assert(std::cmp_not_equal(tup.max, tup.min)); + assert(std::cmp_not_equal(1, tup.max)); + assert(std::cmp_not_equal(tup.max, 1)); + assert(std::cmp_not_equal(1, tup.min)); + assert(std::cmp_not_equal(tup.min, 1)); + assert(std::cmp_not_equal(-2, tup.min)); + assert(std::cmp_not_equal(tup.min, -2)); + assert(std::cmp_not_equal(-2, tup.max)); + assert(std::cmp_not_equal(tup.max, -2)); +} + +template <typename T, typename U> +constexpr void test_cmp_not_equal2() { + constexpr Tuple<T> ttup; + constexpr Tuple<U> utup; + assert(!std::cmp_not_equal(T(0), U(0))); + assert(!std::cmp_not_equal(T(10), U(10))); + assert(std::cmp_not_equal(T(0), U(1))); + assert(std::cmp_not_equal(T(1), U(0))); + assert(std::cmp_not_equal(T(5), U(10))); + assert(std::cmp_not_equal(T(10), U(5))); + assert(std::cmp_not_equal(ttup.min, utup.max)); + assert(std::cmp_not_equal(utup.min, ttup.max)); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_cmp_not_equal1<Ts>() , ...); +} + +template <class T, class... Us> +constexpr void test2_impl(const std::tuple<Us...>&) { + (test_cmp_not_equal2<T, Us>() , ...); +} + +template <class... Ts, class UTuple> +constexpr void test2(const std::tuple<Ts...>&, const UTuple& utuple) { + (test2_impl<Ts>(utuple) , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test2(types, types); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::cmp_not_equal(0, 0)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.fail.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.fail.cpp new file mode 100644 index 0000000..bd436dd --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.fail.cpp @@ -0,0 +1,147 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// template<class T, class U> +// constexpr bool cmp_equal(T t, U u) noexcept; // C++20 + +// template<class T, class U> +// constexpr bool cmp_not_equal(T t, U u) noexcept; // C++20 + +// template<class T, class U> +// constexpr bool cmp_less(T t, U u) noexcept; // C++20 + +// template<class T, class U> +// constexpr bool cmp_less_equal(T t, U u) noexcept; // C++20 + +// template<class T, class U> +// constexpr bool cmp_greater(T t, U u) noexcept; // C++20 + +// template<class T, class U> +// constexpr bool cmp_greater_equal(T t, U u) noexcept; // C++20 + +// template<class R, class T> +// constexpr bool in_range(T t) noexcept; // C++20 + +#include <utility> + +#include "test_macros.h" + +struct NonEmptyT { + int val; + NonEmptyT() : val(0) {} + NonEmptyT(int val) : val(val) {} + operator int&() { return val; } + operator int() const { return val; } +}; + +enum ColorT { red, green, blue }; + +struct EmptyT {}; + +template <class T> +constexpr void test() { + std::cmp_equal(T(), T()); // expected-error11{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(T(), int()); // expected-error11{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(int(), T()); // expected-error11{{no matching function for call to 'cmp_equal'}} + std::cmp_not_equal(T(), T()); // expected-error11{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(T(), int()); // expected-error11{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(int(), T()); // expected-error11{{no matching function for call to 'cmp_not_equal'}} + std::cmp_less(T(), T()); // expected-error11{{no matching function for call to 'cmp_less'}} + std::cmp_less(T(), int()); // expected-error11{{no matching function for call to 'cmp_less'}} + std::cmp_less(int(), T()); // expected-error11{{no matching function for call to 'cmp_less'}} + std::cmp_less_equal(T(), T()); // expected-error11{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(T(), int()); // expected-error11{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(int(), T()); // expected-error11{{no matching function for call to 'cmp_less_equal'}} + std::cmp_greater(T(), T()); // expected-error11{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(T(), int()); // expected-error11{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(int(), T()); // expected-error11{{no matching function for call to 'cmp_greater'}} + std::cmp_greater_equal(T(), T()); // expected-error11{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(T(), int()); // expected-error11{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(int(), T()); // expected-error11{{no matching function for call to 'cmp_greater_equal'}} + std::in_range<T>(int()); // expected-error11{{no matching function for call to 'in_range'}} + std::in_range<int>(T()); // expected-error11{{no matching function for call to 'in_range'}} +} +#ifndef _LIBCPP_NO_HAS_CHAR8_T +template <class T> +constexpr void test_char8t() { + std::cmp_equal(T(), T()); // expected-error1{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(T(), int()); // expected-error1{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(int(), T()); // expected-error1{{no matching function for call to 'cmp_equal'}} + std::cmp_not_equal(T(), T()); // expected-error1{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(T(), int()); // expected-error1{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(int(), T()); // expected-error1{{no matching function for call to 'cmp_not_equal'}} + std::cmp_less(T(), T()); // expected-error1{{no matching function for call to 'cmp_less'}} + std::cmp_less(T(), int()); // expected-error1{{no matching function for call to 'cmp_less'}} + std::cmp_less(int(), T()); // expected-error1{{no matching function for call to 'cmp_less'}} + std::cmp_less_equal(T(), T()); // expected-error1{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(T(), int()); // expected-error1{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(int(), T()); // expected-error1{{no matching function for call to 'cmp_less_equal'}} + std::cmp_greater(T(), T()); // expected-error1{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(T(), int()); // expected-error1{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(int(), T()); // expected-error1{{no matching function for call to 'cmp_greater'}} + std::cmp_greater_equal(T(), T()); // expected-error1{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(T(), int()); // expected-error1{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(int(), T()); // expected-error1{{no matching function for call to 'cmp_greater_equal'}} + std::in_range<T>(int()); // expected-error1{{no matching function for call to 'in_range'}} + std::in_range<int>(T()); // expected-error1{{no matching function for call to 'in_range'}} +} +#endif // _LIBCPP_NO_HAS_CHAR8_T + +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS +template <class T> +constexpr void test_uchars() { + std::cmp_equal(T(), T()); // expected-error2{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(T(), int()); // expected-error2{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(int(), T()); // expected-error2{{no matching function for call to 'cmp_equal'}} + std::cmp_not_equal(T(), T()); // expected-error2{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(T(), int()); // expected-error2{{no matching function for call to 'cmp_not_equal'}} + std::cmp_not_equal(int(), T()); // expected-error2{{no matching function for call to 'cmp_not_equal'}} + std::cmp_less(T(), T()); // expected-error2{{no matching function for call to 'cmp_less'}} + std::cmp_less(T(), int()); // expected-error2{{no matching function for call to 'cmp_less'}} + std::cmp_less(int(), T()); // expected-error2{{no matching function for call to 'cmp_less'}} + std::cmp_less_equal(T(), T()); // expected-error2{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(T(), int()); // expected-error2{{no matching function for call to 'cmp_less_equal'}} + std::cmp_less_equal(int(), T()); // expected-error2{{no matching function for call to 'cmp_less_equal'}} + std::cmp_greater(T(), T()); // expected-error2{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(T(), int()); // expected-error2{{no matching function for call to 'cmp_greater'}} + std::cmp_greater(int(), T()); // expected-error2{{no matching function for call to 'cmp_greater'}} + std::cmp_greater_equal(T(), T()); // expected-error2{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(T(), int()); // expected-error2{{no matching function for call to 'cmp_greater_equal'}} + std::cmp_greater_equal(int(), T()); // expected-error2{{no matching function for call to 'cmp_greater_equal'}} + std::in_range<T>(int()); // expected-error2{{no matching function for call to 'in_range'}} + std::in_range<int>(T()); // expected-error2{{no matching function for call to 'in_range'}} +} +#endif // _LIBCPP_HAS_NO_UNICODE_CHARS + +int main() { + test<bool>(); + test<char>(); + test<wchar_t>(); + test<float>(); + test<double>(); + test<long double>(); + test<std::byte>(); + test<NonEmptyT>(); + test<ColorT>(); + test<nullptr_t>(); + test<EmptyT>(); +#ifndef _LIBCPP_NO_HAS_CHAR8_T + test_char8t<char8_t>(); +#endif // !_LIBCPP_NO_HAS_CHAR8_T + +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test_uchars<char16_t>(); + test_uchars<char32_t>(); +#endif // !_LIBCPP_HAS_NO_UNICODE_CHARS + return 0; +} diff --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.in_range/in_range.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.in_range/in_range.pass.cpp new file mode 100644 index 0000000..3946904 --- /dev/null +++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.in_range/in_range.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// <utility> + +// template<class R, class T> +// constexpr bool in_range(T t) noexcept; // C++20 + +#include <utility> +#include <limits> +#include <numeric> +#include <tuple> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +struct Tuple { + T min; + T max; + T mid; + constexpr Tuple() { + min = std::numeric_limits<T>::min(); + max = std::numeric_limits<T>::max(); + mid = std::midpoint(min, max); + } +}; + +template <typename T> +constexpr void test_in_range1() { + constexpr Tuple<T> tup; + assert(std::in_range<T>(tup.min)); + assert(std::in_range<T>(tup.min + 1)); + assert(std::in_range<T>(tup.max)); + assert(std::in_range<T>(tup.max - 1)); + assert(std::in_range<T>(tup.mid)); + assert(std::in_range<T>(tup.mid - 1)); + assert(std::in_range<T>(tup.mid + 1)); +} + +constexpr void test_in_range() { + constexpr Tuple<uint8_t> utup8; + constexpr Tuple<int8_t> stup8; + assert(!std::in_range<int8_t>(utup8.max)); + assert(std::in_range<short>(utup8.max)); + assert(!std::in_range<uint8_t>(stup8.min)); + assert(std::in_range<int8_t>(utup8.mid)); + assert(!std::in_range<uint8_t>(stup8.mid)); + assert(!std::in_range<uint8_t>(-1)); +} + +template <class... Ts> +constexpr void test1(const std::tuple<Ts...>&) { + (test_in_range1<Ts>() , ...); +} + +constexpr bool test() { + std::tuple< +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + unsigned long long, long long, unsigned long, long, unsigned int, int, + unsigned short, short, unsigned char, signed char> types; + test1(types); + test_in_range(); + return true; +} + +int main() { + ASSERT_NOEXCEPT(std::in_range<int>(-1)); + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 02f9e00..978430c 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -340,7 +340,8 @@ feature_test_macros = [ add_version_header(x) for x in [ "name": "__cpp_lib_integer_comparison_functions", "values": { "c++20": 202002 }, "headers": ["utility"], - "unimplemented": True, + "test_suite_guard": "defined(__cpp_concepts) && __cpp_concepts >= 201907L", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CONCEPTS)", }, { "name": "__cpp_lib_integer_sequence", "values": { "c++14": 201304 }, |