[libcxx-commits] [libcxx] [libc++] Fix acceptance of convertible-to-{float, double, long double} in std::isnan() and std::isinf() (PR #98952)

Robin Caloudis via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jul 24 14:07:21 PDT 2024


https://github.com/robincaloudis updated https://github.com/llvm/llvm-project/pull/98952

>From aaee052ece0f91693b4299cd30f3a59a7ce685b2 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 22:04:22 +0200
Subject: [PATCH 1/6] Test convertibles in std::isinf()

---
 .../test/std/numerics/c.math/isinf.pass.cpp   | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/libcxx/test/std/numerics/c.math/isinf.pass.cpp b/libcxx/test/std/numerics/c.math/isinf.pass.cpp
index e935b53187fe6..99aab191c4977 100644
--- a/libcxx/test/std/numerics/c.math/isinf.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isinf.pass.cpp
@@ -62,9 +62,30 @@ struct TestInt {
   }
 };
 
+struct ConvertibleFloat {
+  int value;
+  ConvertibleFloat(int v) : value(v) {}
+  operator float() const { return static_cast<float>(value); }
+};
+
+struct ConvertibleDouble {
+  int value;
+  ConvertibleDouble(int v) : value(v) {}
+  operator double() const { return static_cast<double>(value); }
+};
+
+struct ConvertibleLongDouble {
+  int value;
+  ConvertibleLongDouble(int v) : value(v) {}
+  operator long double() const { return static_cast<long double>(value); }
+};
+
 int main(int, char**) {
   types::for_each(types::floating_point_types(), TestFloat());
   types::for_each(types::integral_types(), TestInt());
+  assert(!std::isinf(ConvertibleFloat(0)));
+  assert(!std::isinf(ConvertibleDouble(0)));
+  assert(!std::isinf(ConvertibleLongDouble(0)));
 
   return 0;
 }

>From fa552a98a57a8c34b904059f4cb471a9c043c459 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 22:05:02 +0200
Subject: [PATCH 2/6] Remove preprocessor directive

---
 libcxx/include/__math/traits.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 27ec52ecef022..3ba2ee31140c2 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -79,20 +79,17 @@ _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 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
 

>From 9360f2d3e2902f72f977942440fdcaf93b8acacb Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 22:05:20 +0200
Subject: [PATCH 3/6] Test convertibles in std::isnan()

---
 .../test/std/numerics/c.math/isnan.pass.cpp   | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/libcxx/test/std/numerics/c.math/isnan.pass.cpp b/libcxx/test/std/numerics/c.math/isnan.pass.cpp
index fffb124645862..374aa08a600d6 100644
--- a/libcxx/test/std/numerics/c.math/isnan.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isnan.pass.cpp
@@ -62,9 +62,30 @@ struct TestInt {
   }
 };
 
+struct ConvertibleFloat {
+  int value;
+  ConvertibleFloat(int v) : value(v) {}
+  operator float() const { return static_cast<float>(value); }
+};
+
+struct ConvertibleDouble {
+  int value;
+  ConvertibleDouble(int v) : value(v) {}
+  operator double() const { return static_cast<double>(value); }
+};
+
+struct ConvertibleLongDouble {
+  int value;
+  ConvertibleLongDouble(int v) : value(v) {}
+  operator long double() const { return static_cast<long double>(value); }
+};
+
 int main(int, char**) {
   types::for_each(types::floating_point_types(), TestFloat());
   types::for_each(types::integral_types(), TestInt());
+  assert(!std::isnan(ConvertibleFloat(0)));
+  assert(!std::isnan(ConvertibleDouble(0)));
+  assert(!std::isnan(ConvertibleLongDouble(0)));
 
   return 0;
 }

>From 18face057f90043528f158b490670598d618521b Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Tue, 16 Jul 2024 20:58:15 +0200
Subject: [PATCH 4/6] Remove preprocessor directive in std::isnan()

---
 libcxx/include/__math/traits.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 3ba2ee31140c2..c23fdb7d8f475 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -103,20 +103,17 @@ _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 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
 

>From 24decb2ae217f0ffd8c7ee1099cfd535cccdcd22 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Tue, 16 Jul 2024 20:58:37 +0200
Subject: [PATCH 5/6] Extract template and leave comment

---
 .../test/std/numerics/c.math/isinf.pass.cpp   | 29 +++++++------------
 .../test/std/numerics/c.math/isnan.pass.cpp   | 29 +++++++------------
 2 files changed, 20 insertions(+), 38 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/isinf.pass.cpp b/libcxx/test/std/numerics/c.math/isinf.pass.cpp
index 99aab191c4977..e5169e8056c2e 100644
--- a/libcxx/test/std/numerics/c.math/isinf.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isinf.pass.cpp
@@ -62,30 +62,21 @@ struct TestInt {
   }
 };
 
-struct ConvertibleFloat {
-  int value;
-  ConvertibleFloat(int v) : value(v) {}
-  operator float() const { return static_cast<float>(value); }
-};
-
-struct ConvertibleDouble {
-  int value;
-  ConvertibleDouble(int v) : value(v) {}
-  operator double() const { return static_cast<double>(value); }
-};
-
-struct ConvertibleLongDouble {
-  int value;
-  ConvertibleLongDouble(int v) : value(v) {}
-  operator long double() const { return static_cast<long double>(value); }
+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());
-  assert(!std::isinf(ConvertibleFloat(0)));
-  assert(!std::isinf(ConvertibleDouble(0)));
-  assert(!std::isinf(ConvertibleLongDouble(0)));
+
+  // 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;
 }
diff --git a/libcxx/test/std/numerics/c.math/isnan.pass.cpp b/libcxx/test/std/numerics/c.math/isnan.pass.cpp
index 374aa08a600d6..e4ccab1243e56 100644
--- a/libcxx/test/std/numerics/c.math/isnan.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isnan.pass.cpp
@@ -62,30 +62,21 @@ struct TestInt {
   }
 };
 
-struct ConvertibleFloat {
-  int value;
-  ConvertibleFloat(int v) : value(v) {}
-  operator float() const { return static_cast<float>(value); }
-};
-
-struct ConvertibleDouble {
-  int value;
-  ConvertibleDouble(int v) : value(v) {}
-  operator double() const { return static_cast<double>(value); }
-};
-
-struct ConvertibleLongDouble {
-  int value;
-  ConvertibleLongDouble(int v) : value(v) {}
-  operator long double() const { return static_cast<long double>(value); }
+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());
-  assert(!std::isnan(ConvertibleFloat(0)));
-  assert(!std::isnan(ConvertibleDouble(0)));
-  assert(!std::isnan(ConvertibleLongDouble(0)));
+
+  // 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;
 }

>From 418d8e8dbeea09a2def321b14887e55361fd7004 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Wed, 24 Jul 2024 22:53:42 +0200
Subject: [PATCH 6/6] Respect C++11 overloads

---
 libcxx/include/__math/traits.h | 98 +++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 42 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index c23fdb7d8f475..001bf1f52d5a5 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -69,51 +69,65 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 
 // isinf
 
-template <class _A1, __enable_if_t<is_arithmetic<_A1>::value && numeric_limits<_A1>::has_infinity, int> = 0>
-_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1 __x) _NOEXCEPT {
-  return __builtin_isinf((typename __promote<_A1>::type)__x);
-}
-
-template <class _A1, __enable_if_t<is_arithmetic<_A1>::value && !numeric_limits<_A1>::has_infinity, int> = 0>
-_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1) _NOEXCEPT {
-  return false;
-}
-
-_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 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);
-}
+#ifndef _LIBCPP_CXX03_LANG
+    template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
+    _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1) _NOEXCEPT {
+      return false;
+    }
+
+    template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
+    _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1 __x) _NOEXCEPT {
+      return __builtin_isinf(__x);
+    }
+
+    _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 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);
+    }
+#else
+    template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
+    _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI bool isinf(_A1 __x) _NOEXCEPT {
+      return __builtin_isinf((typename __promote<_A1>::type)__x);
+    }
+#endif
 
 // isnan
 
-template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
-_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT {
-  return __builtin_isnan(__x);
-}
-
-template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
-_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) _NOEXCEPT {
-  return false;
-}
-
-_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 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);
-}
+#ifndef _LIBCPP_CXX03_LANG
+    template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
+    _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) _NOEXCEPT {
+      return false;
+    }
+
+    template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
+    _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT {
+      return __builtin_isnan(__x);
+    }
+
+    _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 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);
+    }
+#else
+    template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
+    _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT {
+      return __builtin_isnan((typename __promote<_A1>::type)__x);
+    }
+#endif
 
 // isnormal
 



More information about the libcxx-commits mailing list