diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h index 0638a6949580eb..3d4f14fc9cd552 100644 --- a/libcxx/include/__math/traits.h +++ b/libcxx/include/__math/traits.h @@ -27,18 +27,25 @@ namespace __math { // signbit +// TODO(LLVM 22): Remove conditional once support for Clang 19 is dropped. +#if defined(_LIBCPP_COMPILER_GCC) || __has_constexpr_builtin(__builtin_signbit) +# define _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_CONSTEXPR_SINCE_CXX23 +#else +# define _LIBCPP_SIGNBIT_CONSTEXPR +#endif + template ::value, int> = 0> -_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { +_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { return __builtin_signbit(__x); } template ::value && is_signed<_A1>::value, int> = 0> -_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { +_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { return __x < 0; } template ::value && !is_signed<_A1>::value, int> = 0> -_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1) _NOEXCEPT { +_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1) _NOEXCEPT { return false; } 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 a07260a34516f1..3f17f21e8c1087 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 @@ -220,9 +220,16 @@ int main(int, char**) { ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0) == 1); ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0L) == 1); +// TODO(LLVM 22): Remove `__has_constexpr_builtin` conditional once support for Clang 19 is dropped. +#if !__has_constexpr_builtin(__builtin_signbit) ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1); ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1); ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1); +#else + ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1); + ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1); + ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1); +#endif ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0); ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0); 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 8c481f41a945ed..d8779706bcee22 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 @@ -217,9 +217,9 @@ int main(int, char**) { ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0) == 1); ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0L) == 1); - ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1); - ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1); - ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1); + ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1); + 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); diff --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp new file mode 100644 index 00000000000000..c85033e363ce55 --- /dev/null +++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 signbit(floating-point-type x); // constexpr since C++23 + +// We don't control the implementation on windows +// UNSUPPORTED: windows + +// These compilers don't support constexpr `__builtin_signbit` yet. +// UNSUPPORTED: clang-17, clang-18, clang-19, apple-clang-15, apple-clang-16 + +#include +#include +#include + +#include "test_macros.h" +#include "type_algorithms.h" + +struct TestFloat { + template + static TEST_CONSTEXPR_CXX23 bool test() { + assert(!std::signbit(T(0))); + assert(!std::signbit(std::numeric_limits::min())); + assert(!std::signbit(std::numeric_limits::denorm_min())); + assert(!std::signbit(std::numeric_limits::max())); + assert(!std::signbit(std::numeric_limits::infinity())); + assert(!std::signbit(std::numeric_limits::quiet_NaN())); + assert(!std::signbit(std::numeric_limits::signaling_NaN())); + assert(std::signbit(-T(0))); + assert(std::signbit(-std::numeric_limits::infinity())); + assert(std::signbit(std::numeric_limits::lowest())); + + return true; + } + + template + TEST_CONSTEXPR_CXX23 void operator()() { + test(); +#if TEST_STD_VER >= 23 + static_assert(test()); +#endif + } +}; + +struct TestInt { + template + static TEST_CONSTEXPR_CXX23 bool test() { + assert(!std::signbit(std::numeric_limits::max())); + assert(!std::signbit(T(0))); + if (std::is_unsigned::value) { + assert(!std::signbit(std::numeric_limits::lowest())); + } else { + assert(std::signbit(std::numeric_limits::lowest())); + } + + return true; + } + + template + TEST_CONSTEXPR_CXX23 void operator()() { + test(); +#if TEST_STD_VER >= 23 + static_assert(test()); +#endif + } +}; + +int main(int, char**) { + types::for_each(types::floating_point_types(), TestFloat()); + types::for_each(types::integral_types(), TestInt()); + + return 0; +}