Index: libcxx/docs/Cxx2aStatusPaperStatus.csv =================================================================== --- libcxx/docs/Cxx2aStatusPaperStatus.csv +++ libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -164,7 +164,7 @@ "`P1961 `__","LWG","Harmonizing the definitions of total order for pointers","Belfast","* *","" "`P1965 `__","LWG","Blanket Wording for Specifying ""Hidden Friends""","Belfast","* *","" "","","","","","" -"`P0586 `__","LWG","Safe integral comparisons","Prague","* *","" +"`P0586 `__","LWG","Safe integral comparisons","Prague","|Complete|","13.0" "`P0593 `__","CWG","Implicit creation of objects for low-level object manipulation","Prague","* *","" "`P1115 `__","LWG","Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if","Prague","|Complete|","11.0" "`P1243 `__","LWG","Rangify New Algorithms","Prague","* *","" Index: libcxx/docs/FeatureTestMacroTable.rst =================================================================== --- libcxx/docs/FeatureTestMacroTable.rst +++ libcxx/docs/FeatureTestMacroTable.rst @@ -240,7 +240,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_int_pow2`` ``202002L`` ------------------------------------------------- ----------------- - ``__cpp_lib_integer_comparison_functions`` *unimplemented* + ``__cpp_lib_integer_comparison_functions`` ``202002L`` ------------------------------------------------- ----------------- ``__cpp_lib_interpolate`` ``201902L`` ------------------------------------------------- ----------------- Index: libcxx/include/utility =================================================================== --- libcxx/include/utility +++ libcxx/include/utility @@ -58,6 +58,14 @@ template typename add_rvalue_reference::type declval() noexcept; +template constexpr bool cmp_equal(T t, U u) noexcept; // C++20 +template constexpr bool cmp_not_equal(T t, U u) noexcept; // C++20 +template constexpr bool cmp_less(T t, U u) noexcept; // C++20 +template constexpr bool cmp_greater(T t, U u) noexcept; // C++20 +template constexpr bool cmp_less_equal(T t, U u) noexcept; // C++20 +template constexpr bool cmp_greater_equal(T t, U u) noexcept; // C++20 +template constexpr bool in_range(T t) noexcept; // C++20 + template struct pair { @@ -202,6 +210,7 @@ #include #include #include +#include #include #include <__debug> @@ -209,6 +218,9 @@ #pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD namespace rel_ops @@ -276,6 +288,92 @@ template void as_const(const _Tp&&) = delete; #endif +#if _LIBCPP_STD_VER > 17 +#if defined(__cpp_concepts) && __cpp_concepts >= 201811L +template +struct __is_any_of; + +template +struct __is_any_of<_Ty1, _Ty2> { +constexpr bool static value = is_same_v<_Ty1, _Ty2>; +}; + +template +struct __is_any_of<_Ty, _Ty1, _Tyn...> { +constexpr bool static value = is_same_v<_Ty, _Ty1> || __is_any_of<_Ty, _Tyn...>::value; +}; + +template +concept __is_safe_integral_cmp = is_integral_v<_Ty> && + !__is_any_of, bool, char, +#ifndef _LIBCPP_NO_HAS_CHAR8_T + char8_t, +#endif // !_LIBCPP_NO_HAS_CHAR8_T +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + char16_t, char32_t, +#endif // !_LIBCPP_HAS_NO_UNICODE_CHARS + wchar_t, byte>::value; + +template +requires(__is_safe_integral_cmp<_T1> && __is_safe_integral_cmp<_T2>) +constexpr bool cmp_equal(const _T1 t1, const _T2 t2) noexcept +{ + using T1U = make_unsigned_t<_T1>; + using T2U = make_unsigned_t<_T2>; + if constexpr (is_signed_v<_T1> == is_signed_v<_T2>) + return t1 == t2; + else if constexpr (is_signed_v<_T1>) + return t1 < 0 ? false : T1U(t1) == t2; + else + return t2 < 0 ? false : t1 == T2U(t2); +} + +template +constexpr bool cmp_not_equal(const _T1 t1, const _T2 t2) noexcept +{ + return !cmp_equal(t1, t2); +} + +template +requires(__is_safe_integral_cmp<_T1> && __is_safe_integral_cmp<_T2>) +constexpr bool cmp_less(const _T1 t1, const _T2 t2) noexcept +{ + using T1U = make_unsigned_t<_T1>; + using T2U = make_unsigned_t<_T2>; + if constexpr (is_signed_v<_T1> == is_signed_v<_T2>) + return t1 < t2; + else if constexpr (is_signed_v<_T1>) + return t1 < 0 ? true : T1U(t1) < t2; + else + return t2 < 0 ? false : t1 < T2U(t2); +} + +template +constexpr bool cmp_greater(const _T1 t1, const _T2 t2) noexcept +{ + return cmp_less(t2, t1); +} + +template +constexpr bool cmp_less_equal(const _T1 t1, const _T2 t2) noexcept +{ + return !cmp_greater(t1, t2); +} + +template +constexpr bool cmp_greater_equal(const _T1 t1, const _T2 t2) noexcept +{ + return !cmp_less(t1, t2); +} + +template +constexpr bool in_range(const _Ty t) noexcept +{ + return cmp_less_equal(t, numeric_limits<_Rt>::max()) && cmp_greater_equal(t, numeric_limits<_Rt>::min()); +} +#endif +#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(); @@ -1626,4 +1724,6 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP_UTILITY Index: libcxx/include/version =================================================================== --- libcxx/include/version +++ libcxx/include/version @@ -319,7 +319,9 @@ // # 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(__cpp_concepts) && __cpp_concepts >= 201811LL +# 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 Index: libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp @@ -171,16 +171,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 >= 201811L # 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 >= 201811L is not defined!" # endif # endif @@ -234,16 +234,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 >= 201811L # 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 >= 201811L is not defined!" # endif # endif Index: libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -2682,16 +2682,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 >= 201811L # 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 >= 201811L is not defined!" # endif # endif @@ -3901,16 +3901,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 >= 201811L # 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 >= 201811L is not defined!" # endif # endif Index: libcxx/test/std/utilities/utility/intcmp/intcmp.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/utility/intcmp/intcmp.fail.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// constexpr bool cmp_equal(T t, U u) noexcept; // C++20 + +// template +// constexpr bool cmp_less(T t, U u) noexcept; // C++20 + +#include + +#include "test_macros.h" + +template +constexpr void test() { + std::cmp_equal(T(), T()); // expected-error10{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(T(), int()); // expected-error10{{no matching function for call to 'cmp_equal'}} + std::cmp_equal(int(), T()); // expected-error10{{no matching function for call to 'cmp_equal'}} + std::cmp_less(T(), T()); // expected-error10{{no matching function for call to 'cmp_less'}} + std::cmp_less(T(), int()); // expected-error10{{no matching function for call to 'cmp_less'}} + std::cmp_less(int(), T()); // expected-error10{{no matching function for call to 'cmp_less'}} +} + +int main() { + test(); + test(); + test(); + test(); + test(); + test(); + test(); +#ifndef _LIBCPP_NO_HAS_CHAR8_T + test(); +#endif // !_LIBCPP_NO_HAS_CHAR8_T + +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(); + test(); +#endif // !_LIBCPP_HAS_NO_UNICODE_CHARS +return 0; +} Index: libcxx/test/std/utilities/utility/intcmp/intcmp.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/utility/intcmp/intcmp.pass.cpp @@ -0,0 +1,352 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +template +struct Tuple { + _Ty min; + _Ty max; + _Ty mid; +constexpr Tuple() { + min = std::numeric_limits<_Ty>::min(); + max = std::numeric_limits<_Ty>::max(); + mid = std::midpoint(min, max); + } +}; + +template + constexpr static bool test_in_range() { + constexpr Tuple tup; + assert(std::in_range(tup.min)); + assert(std::in_range(tup.min + 1)); + assert(std::in_range(tup.max)); + assert(std::in_range(tup.max - 1)); + assert(std::in_range(tup.mid)); + assert(std::in_range(tup.mid - 1)); + assert(std::in_range(tup.mid + 1)); + return true; + } + +template + constexpr static bool test_cmp_equal1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + 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)); + } + return true; + } + +template + constexpr static bool test_cmp_equal2() { + constexpr Tuple ttup; + constexpr Tuple 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)); + return true; +} + +template +constexpr bool test_cmp_not_equal1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + 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)); + } + + return true; +} + +template +constexpr bool test_cmp_not_equal2() { + constexpr Tuple ttup; + constexpr Tuple 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)); + return true; +} + +template +constexpr bool test_cmp_less1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + assert(!std::cmp_less(T(-1), T(-1))); + + assert(!std::cmp_less(-2, tup.min)); + assert(std::cmp_less(tup.min, -2)); + assert(std::cmp_less(-2, tup.max)); + assert(!std::cmp_less(tup.max, -2)); + } + + return true; +} + +template +constexpr bool test_cmp_less2() { + assert(std::cmp_less(T(0), U(1))); + assert(!std::cmp_less(T(1), U(0))); + return true; +} + +template +constexpr bool test_cmp_less_equal1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + assert(std::cmp_less_equal(T(-1), T(-1))); + assert(!std::cmp_less_equal(-2, tup.min)); + assert(std::cmp_less_equal(tup.min, -2)); + assert(std::cmp_less_equal(-2, tup.max)); + assert(!std::cmp_less_equal(tup.max, -2)); + } + return true; +} + +template +constexpr bool test_cmp_less_equal2() { + assert(std::cmp_less_equal(T(0), U(1))); + assert(!std::cmp_less_equal(T(1), U(0))); + return true; +} + +template +constexpr bool test_cmp_greater1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + assert(!std::cmp_greater(T(-1), T(-1))); + + assert(std::cmp_greater(-2, tup.min)); + assert(!std::cmp_greater(tup.min, -2)); + assert(!std::cmp_greater(-2, tup.max)); + assert(std::cmp_greater(tup.max, -2)); + } + + return true; +} + +template +constexpr bool test_cmp_greater2() { + assert(!std::cmp_greater(T(0), U(1))); + assert(std::cmp_greater(T(1), U(0))); + return true; +} + +template +constexpr bool test_cmp_greater_equal1() { + constexpr Tuple 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)); + + if constexpr (std::is_signed_v) { + assert(std::cmp_greater_equal(T(-1), T(-1))); + + assert(std::cmp_greater_equal(-2, tup.min)); + assert(!std::cmp_greater_equal(tup.min, -2)); + assert(!std::cmp_greater_equal(-2, tup.max)); + assert(std::cmp_greater_equal(tup.max, -2)); + } + return true; +} + +template +constexpr bool 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))); + return true; +} + +template +constexpr bool test1() +{ + return (... && test_in_range()) && + (... && test_cmp_equal1()) && + (... && test_cmp_not_equal1()) && + (... && test_cmp_less1()) && + (... && test_cmp_less_equal1()) && + (... && test_cmp_greater1()) && + (... && test_cmp_greater_equal1()); +} + +template +constexpr bool test2(const std::tuple&, const std::tuple&) +{ + static_assert(sizeof...(T) == sizeof...(U)); + return (... && test_cmp_equal2()) && + (... && test_cmp_equal2()) && + (... && test_cmp_not_equal2()) && + (... && test_cmp_not_equal2()) && + (... && test_cmp_less2()) && + (... && test_cmp_less2()) && + (... && test_cmp_less_equal2()) && + (... && test_cmp_less_equal2()) && + (... && test_cmp_greater2()) && + (... && test_cmp_greater2()) && + (... && test_cmp_greater_equal2()); + (... && test_cmp_greater_equal2()); +} + +int main() { + + static_assert(test1()); + static_assert(test2(std::tuple{}, + std::tuple{})); + return 0; +} Index: libcxx/utils/generate_feature_test_macro_components.py =================================================================== --- libcxx/utils/generate_feature_test_macro_components.py +++ libcxx/utils/generate_feature_test_macro_components.py @@ -315,7 +315,8 @@ "name": "__cpp_lib_integer_comparison_functions", "values": { "c++20": 202002 }, "headers": ["utility"], - "unimplemented": True, + "depends": "defined(__cpp_concepts) && __cpp_concepts >= 201811L", + "internal_depends": "defined(__cpp_concepts) && __cpp_concepts >= 201811LL", }, { "name": "__cpp_lib_integer_sequence", "values": { "c++14": 201304 },