[libcxx-commits] [libcxx] 4eeff3e - [libc++][math] Add `constexpr` to `std::fpclassify` (#210993)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Jul 25 23:30:30 PDT 2026
Author: Lucas Mellone
Date: 2026-07-26T14:30:25+08:00
New Revision: 4eeff3e309da3a5d827aadc6fb6915b968b23ad5
URL: https://github.com/llvm/llvm-project/commit/4eeff3e309da3a5d827aadc6fb6915b968b23ad5
DIFF: https://github.com/llvm/llvm-project/commit/4eeff3e309da3a5d827aadc6fb6915b968b23ad5.diff
LOG: [libc++][math] Add `constexpr` to `std::fpclassify` (#210993)
Adds `constexpr` to `std::fpclassify` as required 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
8889a3d3b5154d7d5bd4e58ab10d3df503544742.
Added:
libcxx/test/std/numerics/c.math/fpclassify.pass.cpp
Modified:
libcxx/include/cmath
libcxx/include/math.h
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/cmath b/libcxx/include/cmath
index 208791ca0804c..992854b0490a3 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -138,7 +138,7 @@ long double tanhl(long double x);
bool signbit(arithmetic x);
-int fpclassify(arithmetic x);
+int fpclassify(arithmetic x); // constexpr since C++23
bool isfinite(arithmetic x);
bool isinf(arithmetic x);
diff --git a/libcxx/include/math.h b/libcxx/include/math.h
index 1db61538e995f..0aed0db87270c 100644
--- a/libcxx/include/math.h
+++ b/libcxx/include/math.h
@@ -387,26 +387,50 @@ namespace __math {
// fpclassify
+# ifdef _LIBCPP_PREFERRED_OVERLOAD
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int fpclassify(float __x) _NOEXCEPT {
+ return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
+fpclassify(double __x) _NOEXCEPT {
+ return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
+fpclassify(long double __x) _NOEXCEPT {
+ return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
+}
+
+template <class _A1, std::__enable_if_t<std::is_integral<_A1>::value, int> = 0>
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD int
+fpclassify(_A1 __x) _NOEXCEPT {
+ return __x == 0 ? FP_ZERO : FP_NORMAL;
+}
+# else
+
// template on non-double overloads to make them weaker than same overloads from MSVC runtime
template <class = int>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(float __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(float __x) _NOEXCEPT {
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
}
template <class = int>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(double __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(double __x) _NOEXCEPT {
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
}
template <class = int>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(long double __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(long double __x) _NOEXCEPT {
return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x);
}
template <class _A1, std::__enable_if_t<std::is_integral<_A1>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI int fpclassify(_A1 __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int fpclassify(_A1 __x) _NOEXCEPT {
return __x == 0 ? FP_ZERO : FP_NORMAL;
}
+# endif
} // namespace __math
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 93865afc5e68b..926ff37cddbfc 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
@@ -203,9 +203,9 @@ int main(int, char**) {
ASSERT_NOT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0f) == 1);
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0) == 1);
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 d8779706bcee2..455c03ef58d18 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
@@ -197,9 +197,9 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
+ ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0L) == FP_NORMAL);
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0f) == 1);
ASSERT_CONSTEXPR_CXX23(std::isfinite(-1.0) == 1);
diff --git a/libcxx/test/std/numerics/c.math/fpclassify.pass.cpp b/libcxx/test/std/numerics/c.math/fpclassify.pass.cpp
new file mode 100644
index 0000000000000..10b2297fce105
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/fpclassify.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 fpclassify(floating-point-type x); // 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>;
+ TEST_CONSTEXPR_CXX23 T max = lim::max();
+ TEST_CONSTEXPR_CXX23 T min = lim::min();
+ TEST_CONSTEXPR_CXX23 T d_min = lim::denorm_min();
+ TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
+ TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
+ TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
+
+ assert(std::fpclassify(nan) == FP_NAN);
+ assert(std::fpclassify(s_nan) == FP_NAN);
+
+ assert(std::fpclassify(inf) == FP_INFINITE);
+ assert(std::fpclassify(-inf) == FP_INFINITE);
+
+ assert(std::fpclassify(T(1)) == FP_NORMAL);
+ assert(std::fpclassify(T(-1)) == FP_NORMAL);
+ assert(std::fpclassify(max) == FP_NORMAL);
+ assert(std::fpclassify(min) == FP_NORMAL);
+
+ assert(std::fpclassify(d_min) == FP_SUBNORMAL);
+
+ assert(std::fpclassify(T(0)) == FP_ZERO);
+ assert(std::fpclassify(T(-0.0)) == FP_ZERO);
+ }
+};
+
+struct TestInt {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T max = lim::max();
+ TEST_CONSTEXPR_CXX23 T low = lim::lowest();
+
+ assert(std::fpclassify(T(0)) == FP_ZERO);
+ assert(std::fpclassify(T(1)) == FP_NORMAL);
+ assert(std::fpclassify(max) == FP_NORMAL);
+
+ if (std::is_signed<T>::value) {
+ assert(std::fpclassify(low) == FP_NORMAL);
+ assert(std::fpclassify(T(-1)) == FP_NORMAL);
+ }
+ }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+ types::for_each(types::floating_point_types(), TestFloat());
+ types::for_each(types::integral_types(), TestInt());
+
+ 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