[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