[libcxx-commits] [libcxx] [libc++][math] Generalize workaround for UCRT to `signbit` (PR #212398)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 27 21:15:17 PDT 2026
https://github.com/frederick-vs-ja created https://github.com/llvm/llvm-project/pull/212398
As drive-by, also update `libcxx/test/std/numerics/c.math/signbit.pass.cpp` to use the conventional manner to run test case in both compile time and run time.
>From 160598960405af2b71e849f7d50f1c96bd7d415e Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 28 Jul 2026 12:11:05 +0800
Subject: [PATCH] [libc++][math] Generalize workaround for UCRT to `signbit`
As drive-by, also update
`libcxx/test/std/numerics/c.math/signbit.pass.cpp` to use the
conventional manner to run test case in both compile time and run time.
---
libcxx/include/__math/traits.h | 32 +++++++++++++++++--
.../test/std/numerics/c.math/signbit.pass.cpp | 20 ++++++------
2 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index ff22cee7305d7..2cc6920a0fac1 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -25,9 +25,34 @@ namespace __math {
// signbit
-// The universal C runtime (UCRT) in the WinSDK provides floating point overloads
-// for std::signbit(). By defining our overloads as templates, we can work around
-// this issue as templates are less preferred than non-template functions.
+// MS UCRT provides non-template signbit overloads for float, double, and long double that are unconditionally
+// non-constexpr.
+// To workaround this, we use _LIBCPP_PREFERRED_OVERLOAD to make our overloads stronger those overloads, which is
+// necessary for constexpr addition in C++23. When _LIBCPP_PREFERRED_OVERLOAD is not supported, we use template
+// overloads as workaround to avoid conflicts.
+
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool signbit(float __x) _NOEXCEPT {
+ return __builtin_signbit(__x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
+signbit(double __x) _NOEXCEPT {
+ return __builtin_signbit(__x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
+signbit(long double __x) _NOEXCEPT {
+ return __builtin_signbit(__x);
+}
+
+template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
+signbit(_A1 __x) _NOEXCEPT {
+ return __x < 0;
+}
+#else
template <class = void>
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(float __x) _NOEXCEPT {
return __builtin_signbit(__x);
@@ -47,6 +72,7 @@ template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT {
return __x < 0;
}
+#endif
// isfinite
diff --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
index ce219b3a35c0b..2fd316bf773ff 100644
--- a/libcxx/test/std/numerics/c.math/signbit.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
@@ -8,9 +8,6 @@
// bool signbit(floating-point-type x); // constexpr since C++23
-// We don't control the implementation on windows
-// UNSUPPORTED: windows
-
// GCC warns about signbit comparing `bool_v < 0`, which we're testing
// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-bool-compare
@@ -42,9 +39,6 @@ struct TestFloat {
template <class T>
TEST_CONSTEXPR_CXX23 void operator()() {
test<T>();
-#if TEST_STD_VER >= 23
- static_assert(test<T>());
-#endif
}
};
@@ -65,9 +59,6 @@ struct TestInt {
template <class T>
TEST_CONSTEXPR_CXX23 void operator()() {
test<T>();
-#if TEST_STD_VER >= 23
- static_assert(test<T>());
-#endif
}
};
@@ -76,7 +67,7 @@ struct ConvertibleTo {
operator T() const { return T(); }
};
-int main(int, char**) {
+TEST_CONSTEXPR_CXX23 bool test() {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());
@@ -88,5 +79,14 @@ int main(int, char**) {
assert(!std::signbit(ConvertibleTo<double>()));
assert(!std::signbit(ConvertibleTo<long double>()));
}
+
+ 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