Skip to content
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

[libc++][math] Fix acceptance of convertible types in std::isnan() and std::isinf() #98952

Merged
merged 7 commits into from
Aug 16, 2024
Merged
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
20 changes: 12 additions & 8 deletions libcxx/include/__math/traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,22 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf
return false;
}

#ifdef _LIBCPP_PREFERRED_OVERLOAD
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
return __builtin_isinf(__x);
}

_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
isinf(double __x) _NOEXCEPT {
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
#ifdef _LIBCPP_PREFERRED_OVERLOAD
_LIBCPP_PREFERRED_OVERLOAD
#endif
bool
isinf(double __x) _NOEXCEPT {
return __builtin_isinf(__x);
}

_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(long double __x) _NOEXCEPT {
return __builtin_isinf(__x);
}
#endif

// isnan

Expand All @@ -106,20 +108,22 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan
return false;
}

#ifdef _LIBCPP_PREFERRED_OVERLOAD
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT {
return __builtin_isnan(__x);
}

_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
isnan(double __x) _NOEXCEPT {
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
#ifdef _LIBCPP_PREFERRED_OVERLOAD
_LIBCPP_PREFERRED_OVERLOAD
#endif
bool
isnan(double __x) _NOEXCEPT {
return __builtin_isnan(__x);
}

_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(long double __x) _NOEXCEPT {
return __builtin_isnan(__x);
}
#endif

// isnormal

Expand Down
20 changes: 11 additions & 9 deletions libcxx/test/std/numerics/c.math/cmath.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,15 +708,16 @@ void test_isinf()
static_assert((std::is_same<decltype(std::isinf((float)0)), bool>::value), "");

typedef decltype(std::isinf((double)0)) DoubleRetType;
#if !defined(__linux__) || defined(__clang__)
static_assert((std::is_same<DoubleRetType, bool>::value), "");
#else
#if defined(__GLIBC__) && TEST_STD_VER == 03 && defined(TEST_COMPILER_CLANG)
// GLIBC < 2.23 defines 'isinf(double)' with a return type of 'int' in
// all C++ dialects. The test should tolerate this when libc++ can't work
// around it.
// around it via `_LIBCPP_PREFERRED_OVERLOAD`, which is only available
// in modern versions of Clang, and not elsewhere.
// See: https://sourceware.org/bugzilla/show_bug.cgi?id=19439
static_assert((std::is_same<DoubleRetType, bool>::value
|| std::is_same<DoubleRetType, int>::value), "");
#else
static_assert((std::is_same<DoubleRetType, bool>::value), "");
#endif

static_assert((std::is_same<decltype(std::isinf(0)), bool>::value), "");
Expand Down Expand Up @@ -794,15 +795,16 @@ void test_isnan()
static_assert((std::is_same<decltype(std::isnan((float)0)), bool>::value), "");

typedef decltype(std::isnan((double)0)) DoubleRetType;
#if !defined(__linux__) || defined(__clang__)
static_assert((std::is_same<DoubleRetType, bool>::value), "");
#else
// GLIBC < 2.23 defines 'isinf(double)' with a return type of 'int' in
#if defined(__GLIBC__) && TEST_STD_VER == 03 && defined(TEST_COMPILER_CLANG)
// GLIBC < 2.23 defines 'isnan(double)' with a return type of 'int' in
// all C++ dialects. The test should tolerate this when libc++ can't work
// around it.
// around it via `_LIBCPP_PREFERRED_OVERLOAD`, which is only available
// in modern versions of Clang, and not elsewhere.
// See: https://sourceware.org/bugzilla/show_bug.cgi?id=19439
static_assert((std::is_same<DoubleRetType, bool>::value
|| std::is_same<DoubleRetType, int>::value), "");
#else
static_assert((std::is_same<DoubleRetType, bool>::value), "");
#endif

static_assert((std::is_same<decltype(std::isnan(0)), bool>::value), "");
Expand Down
12 changes: 12 additions & 0 deletions libcxx/test/std/numerics/c.math/isinf.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,21 @@ struct TestInt {
}
};

template <typename T>
struct ConvertibleTo {
operator T() const { return T(); }
};

int main(int, char**) {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());

// Make sure we can call `std::isinf` with convertible types
{
assert(!std::isinf(ConvertibleTo<float>()));
assert(!std::isinf(ConvertibleTo<double>()));
assert(!std::isinf(ConvertibleTo<long double>()));
}

return 0;
}
12 changes: 12 additions & 0 deletions libcxx/test/std/numerics/c.math/isnan.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,21 @@ struct TestInt {
}
};

template <typename T>
struct ConvertibleTo {
operator T() const { return T(); }
};

int main(int, char**) {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());

// Make sure we can call `std::isnan` with convertible types
{
assert(!std::isnan(ConvertibleTo<float>()));
assert(!std::isnan(ConvertibleTo<double>()));
assert(!std::isnan(ConvertibleTo<long double>()));
}

return 0;
}
Loading