Skip to content

[libc++] Workaround for a bug of overloads in MS UCRT's <math.h> #149234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions libcxx/include/__math/traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,82 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
return __builtin_isunordered((type)__x, (type)__y);
}

// MS UCRT incorrectly defines some functions in a way not working with integer types. Until C++20, this was worked
// around by -fdelayed-template-parsing. Since C++20, we can use standard feature "requires" instead.

// TODO: Remove the workaround once UCRT fixes these functions. Note that this doesn't seem planned as of 2025-07 per
// https://developercommunity.visualstudio.com/t/10294165.

#if defined(_LIBCPP_MSVCRT) && _LIBCPP_STD_VER >= 20
namespace __ucrt {
template <class _A1>
requires is_integral_v<_A1>
[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1) noexcept {
return true;
}

template <class _A1>
requires is_integral_v<_A1>
[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1) noexcept {
return false;
}

template <class _A1>
requires is_integral_v<_A1>
[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) noexcept {
return false;
}

template <class _A1>
requires is_integral_v<_A1>
[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) noexcept {
return __x != 0;
}

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 {
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 {
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 {
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 {
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 {
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 {
using type = __promote_t<_A1, _A2>;
return __builtin_isunordered((type)__x, (type)__y);
}
} // namespace __ucrt
#endif

} // namespace __math

_LIBCPP_END_NAMESPACE_STD
Expand Down
17 changes: 17 additions & 0 deletions libcxx/include/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,23 @@ using std::__math::islessgreater;
using std::__math::isnan;
using std::__math::isnormal;
using std::__math::isunordered;
# elif _LIBCPP_STD_VER >= 20
// MS UCRT incorrectly defines some functions in a way not working with integer types. Until C++20, this was worked
// around by -fdelayed-template-parsing. Since C++20, we can use standard feature "requires" instead.

// TODO: Remove the workaround once UCRT fixes these functions. Note that this doesn't seem planned as of 2025-07 per
// https://developercommunity.visualstudio.com/t/10294165.

using std::__math::__ucrt::isfinite;
using std::__math::__ucrt::isgreater;
using std::__math::__ucrt::isgreaterequal;
using std::__math::__ucrt::isinf;
using std::__math::__ucrt::isless;
using std::__math::__ucrt::islessequal;
using std::__math::__ucrt::islessgreater;
using std::__math::__ucrt::isnan;
using std::__math::__ucrt::isnormal;
using std::__math::__ucrt::isunordered;
# endif // _LIBCPP_MSVCRT

// We have to provide double overloads for <math.h> to work on platforms that don't provide the full set of math
Expand Down
4 changes: 0 additions & 4 deletions libcxx/test/libcxx/fuzzing/random.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//

// This test fails because Clang no longer enables -fdelayed-template-parsing
// by default on Windows with C++20 (#69431).
// XFAIL: msvc && (clang-18 || clang-19 || clang-20 || clang-21)

// UNSUPPORTED: c++03, c++11

#include <cassert>
Expand Down
4 changes: 0 additions & 4 deletions libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//

// This test fails because Clang no longer enables -fdelayed-template-parsing
// by default on Windows with C++20 (#69431).
// XFAIL: msvc && (clang-18 || clang-19 || clang-20 || clang-21)

// <math.h>

// GCC warns about signbit comparing `bool_v < 0`, which we're testing
Expand Down
4 changes: 0 additions & 4 deletions libcxx/test/std/numerics/c.math/cmath.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//

// This test fails because Clang no longer enables -fdelayed-template-parsing
// by default on Windows with C++20 (#69431).
// XFAIL: msvc && (clang-18 || clang-19 || clang-20 || clang-21)

// <cmath>

#include <cmath>
Expand Down
Loading