[libcxx-commits] [libcxx] a69addf - [libc++][math] Add `constexpr` to comparison functions (#210075)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 28 08:14:51 PDT 2026


Author: Lucas Mellone
Date: 2026-07-28T18:14:47+03:00
New Revision: a69addf4fb640c34fa8249543003c375247c4933

URL: https://github.com/llvm/llvm-project/commit/a69addf4fb640c34fa8249543003c375247c4933
DIFF: https://github.com/llvm/llvm-project/commit/a69addf4fb640c34fa8249543003c375247c4933.diff

LOG: [libc++][math] Add `constexpr` to comparison functions (#210075)

Implement `constexpr` to all comparison functions (`std::isgreater`,
`std::isgreaterequal`, `std::isless`, `std::islessequal`,
`std::islessgreater`, `std::isunordered`) as defined by
[P0533R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0533r9.pdf).

Towards https://github.com/llvm/llvm-project/issues/105174. Follows-up
https://github.com/llvm/llvm-project/pull/94118.

Added: 
    libcxx/test/std/numerics/c.math/isgreater.pass.cpp
    libcxx/test/std/numerics/c.math/isgreaterequal.pass.cpp
    libcxx/test/std/numerics/c.math/isless.pass.cpp
    libcxx/test/std/numerics/c.math/islessequal.pass.cpp
    libcxx/test/std/numerics/c.math/islessgreater.pass.cpp
    libcxx/test/std/numerics/c.math/isunordered.pass.cpp

Modified: 
    libcxx/include/__math/traits.h
    libcxx/include/cmath
    libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
    libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index ff22cee7305d7..f32dc47ab1b1b 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -137,7 +137,8 @@ template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
 // isgreater
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isgreater(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+isgreater(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isgreater((type)__x, (type)__y);
 }
@@ -145,7 +146,8 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
 // isgreaterequal
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isgreaterequal(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+isgreaterequal(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isgreaterequal((type)__x, (type)__y);
 }
@@ -153,7 +155,7 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
 // isless
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isless((type)__x, (type)__y);
 }
@@ -161,7 +163,8 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
 // islessequal
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool islessequal(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+islessequal(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_islessequal((type)__x, (type)__y);
 }
@@ -169,7 +172,8 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
 // islessgreater
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool islessgreater(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+islessgreater(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_islessgreater((type)__x, (type)__y);
 }
@@ -177,7 +181,8 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
 // isunordered
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isunordered(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+isunordered(_A1 __x, _A2 __y) _NOEXCEPT {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isunordered((type)__x, (type)__y);
 }
@@ -216,42 +221,43 @@ template <class _A1>
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isgreater(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isgreater(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isgreater((type)__x, (type)__y);
 }
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isgreaterequal(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
+isgreaterequal(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isgreaterequal((type)__x, (type)__y);
 }
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isless((type)__x, (type)__y);
 }
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool islessequal(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool islessequal(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_islessequal((type)__x, (type)__y);
 }
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool islessgreater(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool islessgreater(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_islessgreater((type)__x, (type)__y);
 }
 
 template <class _A1, class _A2>
   requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2>
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isunordered(_A1 __x, _A2 __y) noexcept {
+[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isunordered(_A1 __x, _A2 __y) noexcept {
   using type = __promote_t<_A1, _A2>;
   return __builtin_isunordered((type)__x, (type)__y);
 }

diff  --git a/libcxx/include/cmath b/libcxx/include/cmath
index 992854b0490a3..e731f58e05f95 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -140,17 +140,17 @@ bool signbit(arithmetic x);
 
 int fpclassify(arithmetic x); // constexpr since C++23
 
-bool isfinite(arithmetic x);
-bool isinf(arithmetic x);
-bool isnan(arithmetic x);
-bool isnormal(arithmetic x);
-
-bool isgreater(arithmetic x, arithmetic y);
-bool isgreaterequal(arithmetic x, arithmetic y);
-bool isless(arithmetic x, arithmetic y);
-bool islessequal(arithmetic x, arithmetic y);
-bool islessgreater(arithmetic x, arithmetic y);
-bool isunordered(arithmetic x, arithmetic y);
+bool isfinite(arithmetic x); // constexpr since C++23
+bool isinf(arithmetic x);    // constexpr since C++23
+bool isnan(arithmetic x);    // constexpr since C++23
+bool isnormal(arithmetic x); // constexpr since C++23
+
+bool isgreater(arithmetic x, arithmetic y);      // constexpr since C++23
+bool isgreaterequal(arithmetic x, arithmetic y); // constexpr since C++23
+bool isless(arithmetic x, arithmetic y);         // constexpr since C++23
+bool islessequal(arithmetic x, arithmetic y);    // constexpr since C++23
+bool islessgreater(arithmetic x, arithmetic y);  // constexpr since C++23
+bool isunordered(arithmetic x, arithmetic y);    // constexpr since C++23
 
 floating_point acosh (arithmetic x);
 float          acoshf(float x);

diff  --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
index 926ff37cddbfc..beca4907284ad 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
@@ -227,29 +227,29 @@ int main(int, char**) {
   ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
   ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0L, 0.0L) == 0);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0L, 0.0L) == 0);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0L, 0.0L) == 0);
 
   assert(!ImplementedP0533R9 && R"(
 Congratulations! You just have implemented P0533R9 (https://wg21.link/p0533r9).

diff  --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
index 455c03ef58d18..0ae3f5802e21f 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
@@ -221,29 +221,29 @@ int main(int, char**) {
   ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
   ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreater(-1.0L, 0.0L) == 0);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isgreaterequal(-1.0L, 0.0L) == 0);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isless(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::isless(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessequal(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessequal(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0f, 0.0f) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0, 0.0) == 1);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::islessgreater(-1.0L, 0.0L) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0f, 0.0f) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0, 0.0) == 1);
+  ASSERT_CONSTEXPR_CXX23(std::islessgreater(-1.0L, 0.0L) == 1);
 
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0f, 0.0f) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0, 0.0) == 0);
-  ASSERT_NOT_CONSTEXPR_CXX23(std::isunordered(-1.0L, 0.0L) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0f, 0.0f) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0, 0.0) == 0);
+  ASSERT_CONSTEXPR_CXX23(std::isunordered(-1.0L, 0.0L) == 0);
 
   assert(!ImplementedP0533R9 && R"(
 Congratulations! You just have implemented P0533R9 (https://wg21.link/p0533r9).

diff  --git a/libcxx/test/std/numerics/c.math/isgreater.pass.cpp b/libcxx/test/std/numerics/c.math/isgreater.pass.cpp
new file mode 100644
index 0000000000000..e09680edf50e1
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/isgreater.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool isgreater(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(std::isgreater(lim::max(), T(0)));
+    assert(!std::isgreater(T(0), lim::max()));
+    assert(!std::isgreater(lim::max(), lim::max()));
+
+    assert(std::isgreater(lim::infinity(), lim::max()));
+    assert(!std::isgreater(-lim::infinity(), lim::lowest()));
+    assert(!std::isgreater(lim::infinity(), lim::infinity()));
+
+    assert(!std::isgreater(lim::quiet_NaN(), T(0)));
+    assert(!std::isgreater(T(0), lim::quiet_NaN()));
+    assert(!std::isgreater(lim::quiet_NaN(), lim::quiet_NaN()));
+    assert(!std::isgreater(lim::signaling_NaN(), T(0)));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(std::isgreater(lim::max(), T(0)));
+    assert(!std::isgreater(T(0), lim::max()));
+    assert(!std::isgreater(lim::max(), lim::max()));
+
+    assert(!std::isgreater(T(1), T(1)));
+    assert(!std::isgreater(lim::lowest(), T(0)));
+
+    if (lim::is_signed) {
+      assert(std::isgreater(T(-1), lim::lowest()));
+      assert(!std::isgreater(lim::lowest(), T(-1)));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::isgreater` with mixed-type promotions.
+  {
+    assert(std::isgreater(2.0, 1));               // double vs int
+    assert(!std::isgreater(1, 2.0f));             // int vs float
+    assert(std::isgreater(2.0L, 1.0f));           // long double vs float
+    assert(!std::isgreater(lim::quiet_NaN(), 0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/numerics/c.math/isgreaterequal.pass.cpp b/libcxx/test/std/numerics/c.math/isgreaterequal.pass.cpp
new file mode 100644
index 0000000000000..a1f03253247ca
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/isgreaterequal.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool isgreaterequal(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(std::isgreaterequal(lim::max(), T(0)));
+    assert(!std::isgreaterequal(T(0), lim::max()));
+    assert(std::isgreaterequal(lim::max(), lim::max()));
+
+    assert(std::isgreaterequal(lim::infinity(), lim::max()));
+    assert(!std::isgreaterequal(-lim::infinity(), lim::lowest()));
+    assert(std::isgreaterequal(lim::infinity(), lim::infinity()));
+
+    assert(!std::isgreaterequal(lim::quiet_NaN(), T(0)));
+    assert(!std::isgreaterequal(T(0), lim::quiet_NaN()));
+    assert(!std::isgreaterequal(lim::signaling_NaN(), T(0)));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(std::isgreaterequal(lim::max(), T(0)));
+    assert(!std::isgreaterequal(T(0), lim::max()));
+    assert(std::isgreaterequal(lim::max(), lim::max()));
+
+    assert(std::isgreaterequal(T(1), T(1)));
+
+    if (std::is_signed<T>::value) {
+      assert(std::isgreaterequal(T(-1), lim::lowest()));
+      assert(!std::isgreaterequal(lim::lowest(), T(-1)));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::isgreaterequal` with mixed-type promotions.
+  {
+    assert(std::isgreaterequal(2.0, 1));               // double vs int
+    assert(!std::isgreaterequal(1, 2.0f));             // int vs float
+    assert(std::isgreaterequal(2.0L, 1.0f));           // long double vs float
+    assert(!std::isgreaterequal(lim::quiet_NaN(), 0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/numerics/c.math/isless.pass.cpp b/libcxx/test/std/numerics/c.math/isless.pass.cpp
new file mode 100644
index 0000000000000..70f71500f4696
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/isless.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool isless(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::isless(lim::max(), T(0)));
+    assert(std::isless(T(0), lim::max()));
+
+    assert(!std::isless(lim::infinity(), lim::max()));
+    assert(std::isless(-lim::infinity(), lim::lowest()));
+
+    assert(!std::isless(T(0), lim::quiet_NaN()));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::isless(lim::max(), T(0)));
+    assert(std::isless(T(0), lim::max()));
+    assert(!std::isless(lim::max(), lim::max()));
+
+    assert(!std::isless(T(1), T(1)));
+
+    if (lim::is_signed) {
+      assert(!std::isless(T(-1), lim::lowest()));
+      assert(std::isless(lim::lowest(), T(-1)));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::isless` with mixed-type promotions.
+  {
+    assert(!std::isless(2.0, 1));                // double vs int
+    assert(std::isless(1, 2.0f));                // int vs float
+    assert(!std::isless(2.0L, 1.0f));            // long double vs float
+    assert(!std::isless(lim::quiet_NaN(), 1.0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/numerics/c.math/islessequal.pass.cpp b/libcxx/test/std/numerics/c.math/islessequal.pass.cpp
new file mode 100644
index 0000000000000..34b5cacd584e5
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/islessequal.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool islessequal(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::islessequal(lim::max(), T(0)));
+    assert(std::islessequal(T(0), lim::max()));
+    assert(std::islessequal(lim::max(), lim::max()));
+
+    assert(!std::islessequal(lim::infinity(), lim::max()));
+    assert(std::islessequal(-lim::infinity(), lim::lowest()));
+    assert(std::islessequal(lim::infinity(), lim::infinity()));
+
+    assert(!std::islessequal(lim::quiet_NaN(), T(0)));
+    assert(!std::islessequal(T(0), lim::quiet_NaN()));
+    assert(!std::islessequal(lim::signaling_NaN(), T(0)));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::islessequal(lim::max(), T(0)));
+    assert(std::islessequal(T(0), lim::max()));
+    assert(std::islessequal(lim::max(), lim::max()));
+
+    assert(std::islessequal(T(1), T(1)));
+
+    if (lim::is_signed) {
+      assert(!std::islessequal(T(-1), lim::lowest()));
+      assert(std::islessequal(lim::lowest(), T(-1)));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::islessequal` with mixed-type promotions.
+  {
+    assert(!std::islessequal(2.0, 1));              // double vs int
+    assert(std::islessequal(1, 2.0f));              // int vs float
+    assert(!std::islessequal(2.0L, 1.0f));          // long double vs float
+    assert(!std::islessequal(lim::quiet_NaN(), 0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/numerics/c.math/islessgreater.pass.cpp b/libcxx/test/std/numerics/c.math/islessgreater.pass.cpp
new file mode 100644
index 0000000000000..86495f4a5b527
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/islessgreater.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool islessgreater(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(std::islessgreater(T(1), T(2)));
+    assert(std::islessgreater(T(2), T(1)));
+    assert(!std::islessgreater(T(1), T(1)));
+
+    assert(!std::islessgreater(lim::infinity(), lim::infinity()));
+    assert(std::islessgreater(lim::infinity(), lim::max()));
+
+    assert(!std::islessgreater(lim::quiet_NaN(), T(0)));
+    assert(!std::islessgreater(T(0), lim::quiet_NaN()));
+    assert(!std::islessgreater(lim::quiet_NaN(), lim::quiet_NaN()));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    if (!std::is_same<T, bool>::value) {
+      assert(std::islessgreater(T(1), T(2)));
+      assert(std::islessgreater(T(2), T(1)));
+    }
+
+    assert(!std::islessgreater(T(1), T(1)));
+    assert(std::islessgreater(lim::max(), T(0)));
+    assert(!std::islessgreater(lim::max(), lim::max()));
+
+    if (lim::is_signed) {
+      assert(std::islessgreater(T(-1), T(1)));
+      assert(std::islessgreater(lim::lowest(), T(0)));
+      assert(std::islessgreater(T(0), lim::lowest()));
+      assert(!std::islessgreater(lim::lowest(), lim::lowest()));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::islessgreater` with mixed-type promotions.
+  {
+    assert(std::islessgreater(2.0, 1));                 // double vs int
+    assert(std::islessgreater(1, 2.0f));                // int vs float
+    assert(std::islessgreater(2.0L, 1.0f));             // long double vs float
+    assert(!std::islessgreater(lim::quiet_NaN(), 1.0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}

diff  --git a/libcxx/test/std/numerics/c.math/isunordered.pass.cpp b/libcxx/test/std/numerics/c.math/isunordered.pass.cpp
new file mode 100644
index 0000000000000..bb13d46768a69
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/isunordered.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// bool isunordered(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::isunordered(T(1), T(2)));
+    assert(!std::isunordered(T(1), T(1)));
+
+    assert(std::isunordered(lim::quiet_NaN(), T(0)));
+    assert(std::isunordered(T(0), lim::quiet_NaN()));
+    assert(std::isunordered(lim::quiet_NaN(), lim::quiet_NaN()));
+
+    assert(std::isunordered(lim::signaling_NaN(), T(0)));
+    assert(!std::isunordered(lim::infinity(), lim::infinity()));
+    assert(!std::isunordered(lim::max(), lim::lowest()));
+  }
+};
+
+struct TestInt {
+  template <class T>
+  TEST_CONSTEXPR_CXX23 void operator()() const {
+    using lim = std::numeric_limits<T>;
+
+    assert(!std::isunordered(T(1), T(2)));
+    assert(!std::isunordered(T(1), T(1)));
+    assert(!std::isunordered(lim::max(), T(0)));
+    assert(!std::isunordered(lim::max(), lim::max()));
+  }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  using lim = std::numeric_limits<double>;
+
+  types::for_each(types::floating_point_types(), TestFloat());
+  types::for_each(types::integral_types(), TestInt());
+
+  // Make sure we can call `std::isunordered` with mixed-type promotions.
+  {
+    assert(!std::isunordered(2.0, 1));               // double vs int
+    assert(!std::isunordered(1, 2.0f));              // int vs float
+    assert(!std::isunordered(2.0L, 1.0f));           // long double vs float
+    assert(std::isunordered(lim::quiet_NaN(), 1.0)); // NaN vs int
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}


        


More information about the libcxx-commits mailing list