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 2 commits 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StephanTLavavej Do you think there is any way we might be able to get a fix in UCRT for this?

@frederick-vs-ja Since this is a bug in UCRT which has been reported and closed as "not to be fixed", I am tempted to say that keeping these tests as XFAIL and being non-conforming on UCRT might be acceptable. If they don't think it's worth fixing the issue, I'm not sure it's worth us doing a (pretty involved) workaround for it either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've brought this up to the UCRT team since we're (very likely) going to have to alter math.h for constexpr cmath, and it would be nice to have a set of changes that fixes everything once and for all.

That said, I would not hold my breath expecting this to change any time soon. MSVC's STL also has workarounds for the UCRT issues here.

// 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
5 changes: 0 additions & 5 deletions libcxx/test/libcxx/fuzzing/random.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
//
//===----------------------------------------------------------------------===//

// This doesn't work on Windows because in the MSVC UCRT headers the math.h is
// actually intended to implement the full C++ spec requirements. For details
// see https://github.com/llvm/llvm-project/issues/70225#issuecomment-1992528828
// XFAIL: msvc

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

#include <cassert>
Expand Down
5 changes: 0 additions & 5 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,11 +6,6 @@
//
//===----------------------------------------------------------------------===//

// This doesn't work on Windows because in the MSVC UCRT headers the math.h is
// actually intended to implement the full C++ spec requirements. For details
// see https://github.com/llvm/llvm-project/issues/70225#issuecomment-1992528828
// XFAIL: msvc

// <math.h>

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

// This doesn't work on Windows because in the MSVC UCRT headers the math.h is
// actually intended to implement the full C++ spec requirements. For details
// see https://github.com/llvm/llvm-project/issues/70225#issuecomment-1992528828
// XFAIL: msvc

// <cmath>

#include <cmath>
Expand Down
Loading