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

Robin Caloudis via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 29 14:27:13 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 01/21] 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 02/21] 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 03/21] 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 04/21] 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 05/21] 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 ec48ccaa67f682885bf27e583a6f40dc3b983694 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 06/21] Respect C++ standard

---
 libcxx/include/__math/traits.h | 36 +++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index c23fdb7d8f475..49e0046d2256c 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -69,16 +69,17 @@ _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>
+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;
 }
 
+#ifndef _LIBCPP_CXX03_LANG
+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);
 }
@@ -90,19 +91,26 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(long double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
-
-// isnan
-
+#else
 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 _LIBCPP_CONSTEXPR_SINCE_CXX23 _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_integral<_A1>::value, int> = 0>
 _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) _NOEXCEPT {
   return false;
 }
 
+#ifndef _LIBCPP_CXX03_LANG
+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);
 }
@@ -114,6 +122,12 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 _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_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT {
+  return __builtin_isnan((typename __promote<_A1>::type)__x);
+}
+#endif
 
 // isnormal
 

>From c6646f6ecdb378315940d7824f7f936a07ce7f7b Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Thu, 25 Jul 2024 00:04:51 +0200
Subject: [PATCH 07/21] Fix templates

---
 libcxx/include/__math/traits.h | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 49e0046d2256c..14f12661cecae 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -74,12 +74,12 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf
   return false;
 }
 
-#ifndef _LIBCPP_CXX03_LANG
 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);
+  return __builtin_isinf((typename __promote<_A1>::type)__x);
 }
 
+#ifndef _LIBCPP_CXX03_LANG
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
@@ -91,11 +91,6 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 _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_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1 __x) _NOEXCEPT {
-  return __builtin_isinf((typename __promote<_A1>::type)__x);
-}
 #endif
 
 // isnan
@@ -105,12 +100,12 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan
   return false;
 }
 
-#ifndef _LIBCPP_CXX03_LANG
 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);
 }
 
+#ifndef _LIBCPP_CXX03_LANG
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
@@ -122,11 +117,6 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 _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_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT {
-  return __builtin_isnan((typename __promote<_A1>::type)__x);
-}
 #endif
 
 // isnormal

>From 3b01107d903f038de3481c89fb382a8cdb188aac Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Thu, 25 Jul 2024 00:23:11 +0200
Subject: [PATCH 08/21] Change ordering

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 14f12661cecae..72069aee92081 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -69,16 +69,16 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 
 // isinf
 
-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((typename __promote<_A1>::type)__x);
 }
 
+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;
+}
+
 #ifndef _LIBCPP_CXX03_LANG
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
   return __builtin_isinf(__x);
@@ -95,16 +95,16 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 
 // isnan
 
-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);
 }
 
+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;
+}
+
 #ifndef _LIBCPP_CXX03_LANG
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT {
   return __builtin_isnan(__x);

>From caddfd478767d3a16d0d0d60df210df2495c49f0 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Thu, 25 Jul 2024 00:51:01 +0200
Subject: [PATCH 09/21] Tolerate return type 'int' for cxx03

---
 libcxx/test/std/numerics/c.math/cmath.pass.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/cmath.pass.cpp b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
index 9379084499792..bd827e1d058f3 100644
--- a/libcxx/test/std/numerics/c.math/cmath.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
@@ -705,7 +705,7 @@ 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__)
+#if !defined(_LIBCPP_CXX03_LANG)
     static_assert((std::is_same<DoubleRetType, bool>::value), "");
 #else
     // GLIBC < 2.23 defines 'isinf(double)' with a return type of 'int' in
@@ -791,10 +791,10 @@ 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__)
+#if !defined(_LIBCPP_CXX03_LANG)
     static_assert((std::is_same<DoubleRetType, bool>::value), "");
 #else
-    // GLIBC < 2.23 defines 'isinf(double)' with a return type of 'int' in
+    // 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.
     // See: https://sourceware.org/bugzilla/show_bug.cgi?id=19439

>From cff34030f4ed19cd81aca7bdf27a477a1ff99bff Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Thu, 25 Jul 2024 07:25:11 +0200
Subject: [PATCH 10/21] Tighten guard

---
 libcxx/test/std/numerics/c.math/cmath.pass.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/cmath.pass.cpp b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
index bd827e1d058f3..ae2757c31ad48 100644
--- a/libcxx/test/std/numerics/c.math/cmath.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
@@ -705,15 +705,15 @@ void test_isinf()
     static_assert((std::is_same<decltype(std::isinf((float)0)), bool>::value), "");
 
     typedef decltype(std::isinf((double)0)) DoubleRetType;
-#if !defined(_LIBCPP_CXX03_LANG)
-    static_assert((std::is_same<DoubleRetType, bool>::value), "");
-#else
+#if defined(__linux__) && defined(_LIBCPP_CXX03_LANG)
     // 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.
     // 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), "");
@@ -791,15 +791,15 @@ void test_isnan()
     static_assert((std::is_same<decltype(std::isnan((float)0)), bool>::value), "");
 
     typedef decltype(std::isnan((double)0)) DoubleRetType;
-#if !defined(_LIBCPP_CXX03_LANG)
-    static_assert((std::is_same<DoubleRetType, bool>::value), "");
-#else
+#if defined(__linux__) && defined(_LIBCPP_CXX03_LANG)
     // 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.
     // 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), "");

>From c5b8c82af126fa0f95a50fefdc8770d0f3fa80b4 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 10:26:44 +0200
Subject: [PATCH 11/21] Allow overloads for apple platforms

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 72069aee92081..5774ac80a431b 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -79,7 +79,7 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf
   return false;
 }
 
-#ifndef _LIBCPP_CXX03_LANG
+#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
@@ -105,7 +105,7 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan
   return false;
 }
 
-#ifndef _LIBCPP_CXX03_LANG
+#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }

>From 88894143b2c2d5aa07be69bced42b31ed62db316 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 11:24:02 +0200
Subject: [PATCH 12/21] Only guard double overload

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 5774ac80a431b..12598e133f1e9 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -79,19 +79,19 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf
   return false;
 }
 
-#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
 
+#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
+#endif
 
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(long double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
-#endif
 
 // isnan
 
@@ -105,19 +105,19 @@ _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan
   return false;
 }
 
-#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
 
+#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
+#endif
 
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(long double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
-#endif
 
 // isnormal
 

>From fb833d2b56c12c5a750154e52483805fe726255b Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 11:50:16 +0200
Subject: [PATCH 13/21] Add comment

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 12598e133f1e9..9eee5906985db 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -83,6 +83,12 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
   return __builtin_isinf(__x);
 }
 
+// When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
+// `-std=c++03`, this header brings the function declaration of `isinf(double)` into scope. This differs
+// from the C99 standard as only a macro of the form `#define isinf(arg)`is expected. Therefore, libc++
+// needs to respect the presense of this `double` overload and cannot redefine it, as it will conflict
+// with the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc
+// guards the `double` overload of `isinf` by preprocessor macros.
 #if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
@@ -109,6 +115,12 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
   return __builtin_isnan(__x);
 }
 
+// When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
+// `-std=c++03`, this header brings the function declaration of `isnan(double)` into scope. This differs
+// from the C99 standard as only a macro of the form `#define isnan(arg)`is expected. Therefore, libc++
+// needs to respect the presense of this `double` overload and cannot redefine it, as it will conflict
+// with the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc
+// guards the `double` overload of `isnan` by preprocessor macros.
 #if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);

>From e0e6997b74b14d759504a6340e90d1fa4a869495 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 13:02:45 +0200
Subject: [PATCH 14/21] Guard double overload with respect to bionic

---
 libcxx/include/__math/traits.h | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 9eee5906985db..82059c7d20792 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -84,12 +84,16 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 }
 
 // When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
-// `-std=c++03`, this header brings the function declaration of `isinf(double)` into scope. This differs
-// from the C99 standard as only a macro of the form `#define isinf(arg)`is expected. Therefore, libc++
-// needs to respect the presense of this `double` overload and cannot redefine it, as it will conflict
-// with the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc
-// guards the `double` overload of `isinf` by preprocessor macros.
-#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
+// `-std=c++03`, this header brings the function declaration of `isinf(double)` with return type of
+// `int` into scope. This differs from the C99 standard as only a macro of the form `#define isinf(arg)`
+// is expected. Therefore, libc++ needs to respect the presense of this `double` overload with return type
+// `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
+// the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
+// `double` overload of `isinf` by preprocessor macros.
+//
+// When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isinf(double)`
+// with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
+#if !defined(_LIBCPP_CXX03_LANG) || !defined(__BIONIC__) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
@@ -116,12 +120,16 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 }
 
 // When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
-// `-std=c++03`, this header brings the function declaration of `isnan(double)` into scope. This differs
-// from the C99 standard as only a macro of the form `#define isnan(arg)`is expected. Therefore, libc++
-// needs to respect the presense of this `double` overload and cannot redefine it, as it will conflict
-// with the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc
-// guards the `double` overload of `isnan` by preprocessor macros.
-#if !defined(_LIBCPP_CXX03_LANG) || defined(__APPLE__)
+// `-std=c++03`, this header brings the function declaration of `isnan(double)` with return type of
+// `int` into scope. This differs from the C99 standard as only a macro of the form `#define isnan(arg)`
+// is expected. Therefore, libc++ needs to respect the presense of this `double` overload with return type
+// `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
+// the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
+// `double` overload of `isnan` by preprocessor macros.
+//
+// When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
+// with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
+#if !defined(_LIBCPP_CXX03_LANG) || !defined(__BIONIC__) || defined(__APPLE__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }

>From fe5daa60b625ca4f07188aeea0863b3ed6cf2a82 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 13:35:01 +0200
Subject: [PATCH 15/21] Only exclude what is truly understood

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 82059c7d20792..2be3f76a8f346 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -93,7 +93,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 //
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isinf(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if !defined(_LIBCPP_CXX03_LANG) || !defined(__BIONIC__) || defined(__APPLE__)
+#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
@@ -129,7 +129,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 //
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if !defined(_LIBCPP_CXX03_LANG) || !defined(__BIONIC__) || defined(__APPLE__)
+#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }

>From b7ced0b42d26f0dec85f427632f53e86e13cab49 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Fri, 26 Jul 2024 16:12:53 +0200
Subject: [PATCH 16/21] Allow overload for C++ >= 23 regardless of the platform

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 2be3f76a8f346..92a758e527183 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -93,7 +93,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 //
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isinf(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)
+#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)) || _LIBCPP_STD_VER >= 23
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
@@ -129,7 +129,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 //
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)
+#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)) || _LIBCPP_STD_VER >= 23
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }

>From 2861cd0a326a412ff290bf3464f5bbaf271181e4 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 29 Jul 2024 21:54:25 +0200
Subject: [PATCH 17/21] Filter more specifically in tests

---
 libcxx/test/std/numerics/c.math/cmath.pass.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/cmath.pass.cpp b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
index ae2757c31ad48..6f660445fce29 100644
--- a/libcxx/test/std/numerics/c.math/cmath.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
@@ -705,10 +705,11 @@ 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(_LIBCPP_CXX03_LANG)
+#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(__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), "");
@@ -791,10 +792,11 @@ 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(_LIBCPP_CXX03_LANG)
+#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(__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), "");

>From b5fad2644bc89e6802fdfd71cbc572f5f30c4eb2 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 29 Jul 2024 22:28:56 +0200
Subject: [PATCH 18/21] Use _LIBCPP_PREFERRED_OVERLOAD for bionic

---
 libcxx/include/__math/traits.h | 32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 92a758e527183..419916db5e811 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -90,11 +90,20 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 // `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
 // the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
 // `double` overload of `isinf` by preprocessor macros.
-//
-// When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isinf(double)`
+#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__))
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+// When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)) || _LIBCPP_STD_VER >= 23
-_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(double __x) _NOEXCEPT {
+// `_LIBCPP_PREFERRED_OVERLOAD` specifies that a given overload is a better match than an otherwise equally good
+// function declaration. This is implemented in modern versions of Clang via __attribute__((__enable_if__)), and
+// not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
+// details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
+// overloads provided by the C libraries mentioned above.
+#  if defined(__BIONIC__) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+_LIBCPP_PREFERRED_OVERLOAD
+#  endif
+    bool
+    isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
 #endif
@@ -126,11 +135,20 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 // `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
 // the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
 // `double` overload of `isnan` by preprocessor macros.
-//
+#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__))
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
-#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) && !defined(__BIONIC__)) || _LIBCPP_STD_VER >= 23
-_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(double __x) _NOEXCEPT {
+// `_LIBCPP_PREFERRED_OVERLOAD` specifies that a given overload is a better match than an otherwise equally good
+// function declaration. This is implemented in modern versions of Clang via __attribute__((__enable_if__)), and
+// not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
+// details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
+// overloads provided by the C libraries mentioned above.
+#  if defined(__BIONIC__) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+_LIBCPP_PREFERRED_OVERLOAD
+#  endif
+    bool
+    isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
 #endif

>From 7a4c15c4165a67cfd233a8b869b3bb7e90d952ca Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 29 Jul 2024 23:17:09 +0200
Subject: [PATCH 19/21] Use _LIBCPP_PREFERRED_OVERLOAD only for glibc + cxx03
 and bionic

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 419916db5e811..889bd4ba3b29d 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -83,6 +83,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
   return __builtin_isinf(__x);
 }
 
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
 // `-std=c++03`, this header brings the function declaration of `isinf(double)` with return type of
 // `int` into scope. This differs from the C99 standard as only a macro of the form `#define isinf(arg)`
@@ -90,8 +91,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 // `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
 // the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
 // `double` overload of `isinf` by preprocessor macros.
-#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__))
-_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+//
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
 // `_LIBCPP_PREFERRED_OVERLOAD` specifies that a given overload is a better match than an otherwise equally good
@@ -99,14 +99,13 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
 // details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
 // overloads provided by the C libraries mentioned above.
-#  if defined(__BIONIC__) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+#  if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
 _LIBCPP_PREFERRED_OVERLOAD
 #  endif
     bool
     isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
 }
-#endif
 
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(long double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
@@ -128,6 +127,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
   return __builtin_isnan(__x);
 }
 
+_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // When libc++ is layered on top of glibc on Linux, glibc's `math.h` is included. When compiling with
 // `-std=c++03`, this header brings the function declaration of `isnan(double)` with return type of
 // `int` into scope. This differs from the C99 standard as only a macro of the form `#define isnan(arg)`
@@ -135,8 +135,7 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
 // `int` and cannot redefine it with return type `bool` like it is supposed to be, as it will conflict with
 // the declaration already in scope. For `-std=c++11` and beyond this issue is fixed, as glibc guards the
 // `double` overload of `isnan` by preprocessor macros.
-#if !(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__))
-_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+//
 // When libc++ is layered on top of Bionic's libc, `math.h` exposes a function prototype for `isnan(double)`
 // with return type `int`. This function prototype in Bionic's libc is not guarded by any preprocessor macros.
 // `_LIBCPP_PREFERRED_OVERLOAD` specifies that a given overload is a better match than an otherwise equally good
@@ -144,14 +143,13 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
 // details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
 // overloads provided by the C libraries mentioned above.
-#  if defined(__BIONIC__) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+#  if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
 _LIBCPP_PREFERRED_OVERLOAD
 #  endif
     bool
     isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);
 }
-#endif
 
 _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(long double __x) _NOEXCEPT {
   return __builtin_isnan(__x);

>From 50a9a878d2d20415d8307605b7efb3c12851ea29 Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 29 Jul 2024 23:20:39 +0200
Subject: [PATCH 20/21] Restrict test to Clang attribute

---
 libcxx/test/std/numerics/c.math/cmath.pass.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/cmath.pass.cpp b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
index 6f660445fce29..8e1bb42b3ddee 100644
--- a/libcxx/test/std/numerics/c.math/cmath.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/cmath.pass.cpp
@@ -705,7 +705,7 @@ void test_isinf()
     static_assert((std::is_same<decltype(std::isinf((float)0)), bool>::value), "");
 
     typedef decltype(std::isinf((double)0)) DoubleRetType;
-#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(__clang__)
+#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(_LIBCPP_PREFERRED_OVERLOAD)
     // 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 via `_LIBCPP_PREFERRED_OVERLOAD`, which is only available
@@ -792,7 +792,7 @@ void test_isnan()
     static_assert((std::is_same<decltype(std::isnan((float)0)), bool>::value), "");
 
     typedef decltype(std::isnan((double)0)) DoubleRetType;
-#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(__clang__)
+#if defined(__GLIBC__) && defined(_LIBCPP_CXX03_LANG) && !defined(_LIBCPP_PREFERRED_OVERLOAD)
     // 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 via `_LIBCPP_PREFERRED_OVERLOAD`, which is only available

>From 924f6abee3ceec3b36c05c4b207a68c15b0ecdcd Mon Sep 17 00:00:00 2001
From: Robin Caloudis <robin.caloudis at gmx.de>
Date: Mon, 29 Jul 2024 23:26:39 +0200
Subject: [PATCH 21/21] Fix formatting

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

diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 889bd4ba3b29d..079c7c2eee670 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -99,9 +99,9 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
 // details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
 // overloads provided by the C libraries mentioned above.
-#  if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
 _LIBCPP_PREFERRED_OVERLOAD
-#  endif
+#endif
     bool
     isinf(double __x) _NOEXCEPT {
   return __builtin_isinf(__x);
@@ -143,9 +143,9 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
 // not elsewhere. See https://github.com/llvm/llvm-project/commit/5fd17ab1b093f6b59aabb27f6c2c2278e65c2707 for
 // details. We use `_LIBCPP_PREFERRED_OVERLOAD` to define overloads in the global namespace that displace the
 // overloads provided by the C libraries mentioned above.
-#  if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
+#if (!(defined(_LIBCPP_CXX03_LANG) && defined(__GLIBC__)) || defined(__BIONIC__)) && defined(_LIBCPP_PREFERRED_OVERLOAD)
 _LIBCPP_PREFERRED_OVERLOAD
-#  endif
+#endif
     bool
     isnan(double __x) _NOEXCEPT {
   return __builtin_isnan(__x);



More information about the libcxx-commits mailing list