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

Robin Caloudis via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 16 11:41:25 PDT 2024


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

>From 3827e6fd8b58a2d57a18095c732bdbcc374bcfe5 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Sun, 14 Jul 2024 23:59:05 +0200
Subject: [PATCH 1/9] Reproduce error by a test

The following error is raised if
convertibles are used as arguments
to isfinite(): "error: "no matching
function for call to 'isfinite'".
---
 libcxx/test/std/numerics/c.math/isfinite.pass.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
index 6bbc3aaac6d13..04457062bedec 100644
--- a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
@@ -62,9 +62,20 @@ struct TestInt {
   }
 };
 
+struct ConvertibleFloat {
+    int value;
+
+    ConvertibleFloat(int v) : value(v) {}
+
+    operator float() const {
+        return static_cast<float>(value);
+    }
+};
+
 int main(int, char**) {
   types::for_each(types::floating_point_types(), TestFloat());
   types::for_each(types::integral_types(), TestInt());
+  assert(std::isfinite(ConvertibleFloat(0)));
 
   return 0;
 }

>From 9dcd0cf3bbd9a44e2bffec38457a6ddbbec180d7 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:02:12 +0200
Subject: [PATCH 2/9] Provide float overload

---
 libcxx/include/__math/traits.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index a448266797557..29e31dfb2e6d0 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -55,6 +55,12 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfin
   return true;
 }
 
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(float __x) _NOEXCEPT {
+  return __builtin_isfinite(__x);
+}
+
+#endif
 // isinf
 
 template <class _A1, __enable_if_t<is_arithmetic<_A1>::value && numeric_limits<_A1>::has_infinity, int> = 0>

>From 121bad4a5594b692d8693622388db25e743cb293 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:06:18 +0200
Subject: [PATCH 3/9] Reproduce error by a test for double overload

---
 libcxx/test/std/numerics/c.math/isfinite.pass.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
index 04457062bedec..5ca9b5e369690 100644
--- a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
@@ -72,10 +72,21 @@ struct ConvertibleFloat {
     }
 };
 
+struct ConvertibleDouble {
+    int value;
+
+    ConvertibleDouble(int v) : value(v) {}
+
+    operator double() const {
+        return static_cast<double>(value);
+    }
+};
+
 int main(int, char**) {
   types::for_each(types::floating_point_types(), TestFloat());
   types::for_each(types::integral_types(), TestInt());
   assert(std::isfinite(ConvertibleFloat(0)));
+  assert(std::isfinite(ConvertibleDouble(0)));
 
   return 0;
 }

>From 23f4a4cf72efdc32231337e1e538be44473187cf Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:07:07 +0200
Subject: [PATCH 4/9] Provide double overload for isfinite()

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 29e31dfb2e6d0..df761a130d425 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -60,6 +60,10 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
   return __builtin_isfinite(__x);
 }
 
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
+isfinite(double __x) _NOEXCEPT {
+  return __builtin_isfinite(__x);
+}
 #endif
 // isinf
 

>From 90d273741643d78e51422d9171583cc2049dc72a Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:09:41 +0200
Subject: [PATCH 5/9] Reproduce another error by a test

This time, we test for the overload
long double.
---
 libcxx/test/std/numerics/c.math/isfinite.pass.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
index 5ca9b5e369690..56d9550348a9b 100644
--- a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
@@ -82,11 +82,22 @@ struct ConvertibleDouble {
     }
 };
 
+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::isfinite(ConvertibleFloat(0)));
   assert(std::isfinite(ConvertibleDouble(0)));
+  assert(std::isfinite(ConvertibleLongDouble(0)));
 
   return 0;
 }

>From 9df4a55da66dea7c875530fc11c25e648426cfb5 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:10:17 +0200
Subject: [PATCH 6/9] Provide long double overload

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index df761a130d425..07e5a74ac2362 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -64,6 +64,10 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LI
 isfinite(double __x) _NOEXCEPT {
   return __builtin_isfinite(__x);
 }
+
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(long double __x) _NOEXCEPT {
+  return __builtin_isfinite(__x);
+}
 #endif
 // isinf
 

>From 86f5933420a7194b72efd2916bf977a3d1590cbc Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 00:20:08 +0200
Subject: [PATCH 7/9] Fix formatting

---
 .../std/numerics/c.math/isfinite.pass.cpp     | 30 ++++++-------------
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
index 56d9550348a9b..35a054c5bcd52 100644
--- a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
@@ -63,33 +63,21 @@ struct TestInt {
 };
 
 struct ConvertibleFloat {
-    int value;
-
-    ConvertibleFloat(int v) : value(v) {}
-
-    operator float() const {
-        return static_cast<float>(value);
-    }
+  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);
-    }
+  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 value;
+  ConvertibleLongDouble(int v) : value(v) {}
+  operator long double() const { return static_cast<long double>(value); }
 };
 
 int main(int, char**) {

>From c858bb6429216f78b92813c6ee09711ad51c812f Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 15 Jul 2024 21:44:16 +0200
Subject: [PATCH 8/9] Remove preprocessor directive

---
 libcxx/include/__math/traits.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 07e5a74ac2362..27ec52ecef022 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -55,20 +55,18 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfin
   return true;
 }
 
-#ifdef _LIBCPP_PREFERRED_OVERLOAD
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(float __x) _NOEXCEPT {
   return __builtin_isfinite(__x);
 }
 
-_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool
-isfinite(double __x) _NOEXCEPT {
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(double __x) _NOEXCEPT {
   return __builtin_isfinite(__x);
 }
 
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(long double __x) _NOEXCEPT {
   return __builtin_isfinite(__x);
 }
-#endif
+
 // isinf
 
 template <class _A1, __enable_if_t<is_arithmetic<_A1>::value && numeric_limits<_A1>::has_infinity, int> = 0>

>From 2e6a04dddd2c2200780fa1dc8eae9e4f215c3063 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Tue, 16 Jul 2024 20:41:02 +0200
Subject: [PATCH 9/9] Extract template and leave comment

---
 .../std/numerics/c.math/isfinite.pass.cpp     | 29 +++++++------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp b/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
index 35a054c5bcd52..318814d3c4b26 100644
--- a/libcxx/test/std/numerics/c.math/isfinite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/isfinite.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 {}; }
 };
 
 int main(int, char**) {
   types::for_each(types::floating_point_types(), TestFloat());
   types::for_each(types::integral_types(), TestInt());
-  assert(std::isfinite(ConvertibleFloat(0)));
-  assert(std::isfinite(ConvertibleDouble(0)));
-  assert(std::isfinite(ConvertibleLongDouble(0)));
+
+  // Make sure we can call `std::isfinite` with convertible types
+  {
+    assert(std::isfinite(ConvertibleTo<float>()));
+    assert(std::isfinite(ConvertibleTo<double>()));
+    assert(std::isfinite(ConvertibleTo<long double>()));
+  }
 
   return 0;
 }



More information about the libcxx-commits mailing list