[libcxx] r198431 - Patch by Howard. First part of fix for PR18218; add type traits needed to do the right thing. Fix the problems in PR18218 for isnan and pow - they also need to be applied to the other functions in <cmath>. Also, a drive-by fix for the test - now actually calls test_abs()

Marshall Clow mclow.lists at gmail.com
Fri Jan 3 10:21:14 PST 2014


Author: marshall
Date: Fri Jan  3 12:21:14 2014
New Revision: 198431

URL: http://llvm.org/viewvc/llvm-project?rev=198431&view=rev
Log:
Patch by Howard. First part of fix for PR18218; add type traits needed to do the right thing. Fix the problems in PR18218 for isnan and pow - they also need to be applied to the other functions in <cmath>. Also, a drive-by fix for the test - now actually calls test_abs()

Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/cmath
    libcxx/trunk/include/type_traits
    libcxx/trunk/test/numerics/c.math/cmath.pass.cpp

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=198431&r1=198430&r2=198431&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Fri Jan  3 12:21:14 2014
@@ -326,9 +326,11 @@ typedef __char32_t char32_t;
 #if (__has_feature(cxx_noexcept))
 #  define _NOEXCEPT noexcept
 #  define _NOEXCEPT_(x) noexcept(x)
+#  define _NOEXCEPT_OR_FALSE(x) noexcept(x)
 #else
 #  define _NOEXCEPT throw()
 #  define _NOEXCEPT_(x)
+#  define _NOEXCEPT_OR_FALSE(x) false
 #endif
 
 #if __has_feature(underlying_type)
@@ -361,6 +363,7 @@ namespace std {
 
 #define _NOEXCEPT throw()
 #define _NOEXCEPT_(x)
+#define _NOEXCEPT_OR_FALSE(x) false
 
 #ifndef __GXX_EXPERIMENTAL_CXX0X__
 
@@ -433,6 +436,7 @@ using namespace _LIBCPP_NAMESPACE __attr
 
 #define _NOEXCEPT throw()
 #define _NOEXCEPT_(x)
+#define _NOEXCEPT_OR_FALSE(x) false
 
 #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std {
 #define _LIBCPP_END_NAMESPACE_STD  }
@@ -451,6 +455,7 @@ namespace std {
 
 #define _NOEXCEPT throw()
 #define _NOEXCEPT_(x)
+#define _NOEXCEPT_OR_FALSE(x) false
 
 #define _LIBCPP_HAS_NO_TEMPLATE_ALIASES
 #define _LIBCPP_HAS_NO_ADVANCED_SFINAE

Modified: libcxx/trunk/include/cmath
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/cmath?rev=198431&r1=198430&r2=198431&view=diff
==============================================================================
--- libcxx/trunk/include/cmath (original)
+++ libcxx/trunk/include/cmath Fri Jan  3 12:21:14 2014
@@ -419,12 +419,25 @@ __libcpp_isnan(_A1 __x) _NOEXCEPT
 
 #undef isnan
 
-template <class _A1>
 inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
-isnan(_A1 __x) _NOEXCEPT
+bool
+isnan(float __x) _NOEXCEPT
+{
+    return __libcpp_isnan(__x);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+isnan(double __x) _NOEXCEPT
 {
-    return __libcpp_isnan((typename std::__promote<_A1>::type)__x);
+    return __libcpp_isnan(__x);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+isnan(long double __x) _NOEXCEPT
+{
+    return __libcpp_isnan(__x);
 }
 
 #endif  // isnan
@@ -652,6 +665,26 @@ using ::isunordered;
 using ::float_t;
 using ::double_t;
 
+// isnan
+
+template <class _A1>
+inline _LIBCPP_INLINE_VISIBILITY
+typename std::enable_if<__promote<_A1>::value, bool>::type
+#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+isnan(_A1 __x)
+#else
+isnan(_A1&& __x)
+    _NOEXCEPT_
+    (
+        _NOEXCEPT_(__promote<_A1>::__does_not_throw)
+    )
+#endif
+{
+    typedef typename __promote<_A1>::type type;
+    static_assert(!(is_same<typename remove_reference<_A1>::type, type>::value), "");
+    return __libcpp_isnan(static_cast<type>(_VSTD::forward<_A1>(__x)));
+}
+
 // abs
 
 #if !defined(_AIX)
@@ -952,21 +985,27 @@ inline _LIBCPP_INLINE_VISIBILITY long do
 
 template <class _A1, class _A2>
 inline _LIBCPP_INLINE_VISIBILITY
-typename enable_if
-<
-    is_arithmetic<_A1>::value &&
-    is_arithmetic<_A2>::value,
-    typename __promote<_A1, _A2>::type
->::type
-pow(_A1 __x, _A2 __y) _NOEXCEPT
-{
-    typedef typename __promote<_A1, _A2>::type __result_type;
-    static_assert((!(is_same<_A1, __result_type>::value &&
-                      is_same<_A2, __result_type>::value)), "");
-    return pow((__result_type)__x, (__result_type)__y);
+typename __promote<_A1, _A2>::type
+#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+pow(_A1 __x, _A2 __y)
+#else
+pow(_A1&& __x, _A2&& __y)
+    _NOEXCEPT_
+    (
+        _NOEXCEPT_(__promote<_A1>::__does_not_throw) &&
+        _NOEXCEPT_(__promote<_A2>::__does_not_throw)
+    )
+#endif
+{
+    typedef typename __promote<_A1>::type _D1;
+    typedef typename __promote<_A2>::type _D2;
+    typedef typename __promote<_D1, _D2>::type type;
+    static_assert((!(is_same<typename remove_reference<_A1>::type, type>::value &&
+                     is_same<typename remove_reference<_A2>::type, type>::value)), "");
+    return pow(static_cast<type>(static_cast<_D1>(_VSTD::forward<_A1>(__x))),
+               static_cast<type>(static_cast<_D2>(_VSTD::forward<_A2>(__y))));
 }
 
-
 // sin
 
 using ::sin;

Modified: libcxx/trunk/include/type_traits
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=198431&r1=198430&r2=198431&view=diff
==============================================================================
--- libcxx/trunk/include/type_traits (original)
+++ libcxx/trunk/include/type_traits Fri Jan  3 12:21:14 2014
@@ -1151,13 +1151,41 @@ template <size_t _Len, class ..._Types>
 
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
+template <class _Tp>
+struct __numeric_type
+{
+   static void __test(...);
+   static float __test(float);
+   static double __test(char);
+   static double __test(int);
+   static double __test(unsigned);
+   static double __test(long);
+   static double __test(unsigned long);
+   static double __test(long long);
+   static double __test(unsigned long long);
+   static double __test(double);
+   static long double __test(long double);
+
+   typedef decltype(__test(declval<_Tp>())) type;
+   static const bool value = !is_same<type, void>::value;
+};
+
+template <>
+struct __numeric_type<void>
+{
+   static const bool value = true;
+};
+
 // __promote
 
 template <class _A1, class _A2 = void, class _A3 = void,
-          bool = (is_arithmetic<_A1>::value || is_void<_A1>::value) &&
-                 (is_arithmetic<_A2>::value || is_void<_A2>::value) &&
-                 (is_arithmetic<_A3>::value || is_void<_A3>::value)>
-class __promote {};
+          bool = __numeric_type<_A1>::value &&
+                 __numeric_type<_A2>::value &&
+                 __numeric_type<_A3>::value>
+class __promote
+{
+    static const bool value = false;
+};
 
 template <class _A1, class _A2, class _A3>
 class __promote<_A1, _A2, _A3, true>
@@ -1168,6 +1196,7 @@ private:
     typedef typename __promote<_A3>::type __type3;
 public:
     typedef decltype(__type1() + __type2() + __type3()) type;
+    static const bool value = true;
 };
 
 template <class _A1, class _A2>
@@ -1178,16 +1207,16 @@ private:
     typedef typename __promote<_A2>::type __type2;
 public:
     typedef decltype(__type1() + __type2()) type;
+    static const bool value = true;
 };
 
 template <class _A1>
 class __promote<_A1, void, void, true>
 {
 public:
-    typedef typename conditional<is_arithmetic<_A1>::value,
-                     typename conditional<is_integral<_A1>::value, double, _A1>::type,
-                     void
-            >::type type;
+    typedef typename __numeric_type<_A1>::type type;
+    static const bool value = true;
+    static const bool __does_not_throw = _NOEXCEPT_OR_FALSE(static_cast<type>(declval<_A1>()));
 };
 
 #ifdef _LIBCPP_STORE_AS_OPTIMIZATION

Modified: libcxx/trunk/test/numerics/c.math/cmath.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/numerics/c.math/cmath.pass.cpp?rev=198431&r1=198430&r2=198431&view=diff
==============================================================================
--- libcxx/trunk/test/numerics/c.math/cmath.pass.cpp (original)
+++ libcxx/trunk/test/numerics/c.math/cmath.pass.cpp Fri Jan  3 12:21:14 2014
@@ -15,6 +15,12 @@
 
 #include "hexfloat.h"
 
+// convertible to int/float/double/etc
+template <class T, int N=0>
+struct Value {
+    operator T () { return T(N); }
+};
+
 void test_abs()
 {
     static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
@@ -333,7 +339,14 @@ void test_pow()
     static_assert((std::is_same<decltype(std::powf(0,0)), float>::value), "");
     static_assert((std::is_same<decltype(std::powl(0,0)), long double>::value), "");
     static_assert((std::is_same<decltype(std::pow((int)0, (int)0)), double>::value), "");
+    static_assert((std::is_same<decltype(std::pow(Value<int>(), (int)0)), double>::value), "");
+    static_assert((std::is_same<decltype(std::pow(Value<long double>(), (float)0)), long double>::value), "");
+    static_assert((std::is_same<decltype(std::pow((float) 0, Value<float>())), float>::value), "");
     assert(std::pow(1,1) == 1);
+    assert(std::pow(Value<int,1>(), Value<float,1>())  == 1);
+    assert(std::pow(1.0f, Value<double,1>()) == 1);
+    assert(std::pow(1.0, Value<int,1>()) == 1);
+    assert(std::pow(Value<long double,1>(), 1LL) == 1);
 }
 
 void test_sin()
@@ -1279,6 +1292,7 @@ void test_trunc()
 
 int main()
 {
+    test_abs();
     test_acos();
     test_asin();
     test_atan();





More information about the cfe-commits mailing list