From d41295da72e2f264699672c97aeaff55fff219a2 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Fri, 3 Jan 2014 18:21:14 +0000 Subject: [PATCH] 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 . Also, a drive-by fix for the test - now actually calls test_abs() llvm-svn: 198431 --- libcxx/include/__config | 5 +++ libcxx/include/cmath | 71 +++++++++++++++++++++++------- libcxx/include/type_traits | 45 +++++++++++++++---- libcxx/test/numerics/c.math/cmath.pass.cpp | 14 ++++++ 4 files changed, 111 insertions(+), 24 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index f992bd5..8aa57ac 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -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 __attribute__((__strong__)); #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 diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 75087ae..4f27978 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -419,12 +419,25 @@ __libcpp_isnan(_A1 __x) _NOEXCEPT #undef isnan -template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::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 +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::type, type>::value), ""); + return __libcpp_isnan(static_cast(_VSTD::forward<_A1>(__x))); +} + // abs #if !defined(_AIX) @@ -952,21 +985,27 @@ inline _LIBCPP_INLINE_VISIBILITY long double pow(long double __x, long double __ template 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 +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, _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); + typedef typename __promote<_A1>::type _D1; + typedef typename __promote<_A2>::type _D2; + typedef typename __promote<_D1, _D2>::type type; + static_assert((!(is_same::type, type>::value && + is_same::type, type>::value)), ""); + return pow(static_cast(static_cast<_D1>(_VSTD::forward<_A1>(__x))), + static_cast(static_cast<_D2>(_VSTD::forward<_A2>(__y)))); } - // sin using ::sin; diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 0ad7b7f..04e5fd1 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -1151,13 +1151,41 @@ template using aligned_union_t = typename aligned #endif // _LIBCPP_HAS_NO_VARIADICS +template +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::value; +}; + +template <> +struct __numeric_type +{ + static const bool value = true; +}; + // __promote template ::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 __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 @@ -1178,16 +1207,16 @@ private: typedef typename __promote<_A2>::type __type2; public: typedef decltype(__type1() + __type2()) type; + static const bool value = true; }; template class __promote<_A1, void, void, true> { public: - typedef typename conditional::value, - typename conditional::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(declval<_A1>())); }; #ifdef _LIBCPP_STORE_AS_OPTIMIZATION diff --git a/libcxx/test/numerics/c.math/cmath.pass.cpp b/libcxx/test/numerics/c.math/cmath.pass.cpp index 10b0993..13d872c 100644 --- a/libcxx/test/numerics/c.math/cmath.pass.cpp +++ b/libcxx/test/numerics/c.math/cmath.pass.cpp @@ -15,6 +15,12 @@ #include "hexfloat.h" +// convertible to int/float/double/etc +template +struct Value { + operator T () { return T(N); } +}; + void test_abs() { static_assert((std::is_same::value), ""); @@ -333,7 +339,14 @@ void test_pow() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); + static_assert((std::is_same(), (int)0)), double>::value), ""); + static_assert((std::is_same(), (float)0)), long double>::value), ""); + static_assert((std::is_same())), float>::value), ""); assert(std::pow(1,1) == 1); + assert(std::pow(Value(), Value()) == 1); + assert(std::pow(1.0f, Value()) == 1); + assert(std::pow(1.0, Value()) == 1); + assert(std::pow(Value(), 1LL) == 1); } void test_sin() @@ -1279,6 +1292,7 @@ void test_trunc() int main() { + test_abs(); test_acos(); test_asin(); test_atan(); -- 2.7.4