[libcxx-commits] [libcxx] [libc++][math] Provide overloads for cv-unqualified floating point types for `std::isnormal` (PR #104773)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 22 13:16:48 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Robin Caloudis (robincaloudis)

<details>
<summary>Changes</summary>

## Why
Currently, the following does not work when compiled with clang:

```c++
#include <cmath>

struct ConvertibleToFloat {
    operator float();
};

bool test(ConvertibleToFloat x) {
    return std::isnormal(x);
}
```
See https://godbolt.org/z/5bos8v67T for differences with respect to msvc, gcc or icx. If fails for `double` and `long double` as well. As the classification/comparison function `isnormal` is defined since C++11 until C++23 as 
```c++
bool isnormal( float num );
bool isnormal( double num );
bool isnormal( long double num );
```
and since C++23 as
```c++
constexpr bool isnormal( /* floating-point-type */ num );
```
for which "the library provides overloads for all cv-unqualified floating-point types as the type of the parameter num", it is actually expected that convertibles types work due to the present of the overloads for all cv-unqualified floating point types. See §28.7.1/1 in the [ISO C++ standard](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf) or check [cppreference](https://en.cppreference.com/w/cpp/numeric/math/isnormal).

## What
Test and provide overloads as expected by the ISO C++ standard.

---
Full diff: https://github.com/llvm/llvm-project/pull/104773.diff


2 Files Affected:

- (modified) libcxx/include/__math/traits.h (+12) 
- (modified) libcxx/test/std/numerics/c.math/isnormal.pass.cpp (+14) 


``````````diff
diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 35c283cc9e21ce..9fe1de66a80985 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -137,6 +137,18 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnor
   return __x != 0;
 }
 
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(float __x) _NOEXCEPT {
+  return __builtin_isnormal(__x);
+}
+
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(double __x) _NOEXCEPT {
+  return __builtin_isnormal(__x);
+}
+
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(long double __x) _NOEXCEPT {
+  return __builtin_isnormal(__x);
+}
+
 // isgreater
 
 template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
diff --git a/libcxx/test/std/numerics/c.math/isnormal.pass.cpp b/libcxx/test/std/numerics/c.math/isnormal.pass.cpp
index c3b8f31359f988..76c3d13520d996 100644
--- a/libcxx/test/std/numerics/c.math/isnormal.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isnormal.pass.cpp
@@ -62,9 +62,23 @@ struct TestInt {
   }
 };
 
+template <typename T>
+struct ConvertibleTo {
+  operator T() const { return T(1); }
+};
+
 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::isnormal` with convertible types. This checks
+  // whether overloads for all cv-unqualified floating-point types are working
+  // as expected.
+  {
+    assert(std::isnormal(ConvertibleTo<float>()));
+    assert(std::isnormal(ConvertibleTo<double>()));
+    assert(std::isnormal(ConvertibleTo<long double>()));
+  }
+
   return 0;
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/104773


More information about the libcxx-commits mailing list