forked from OSchip/llvm-project
Fix implementation of ::abs and std::abs LWG 2192.
Summary: All overloads of `::abs` and `std::abs` must be present in both `<cmath>` and `<cstdlib>`. This is problematic to implement because C defines `fabs` in `math.h` and `labs` in `stdlib.h`. This introduces a circular dependency between the two headers. This patch implements that requirement by moving `abs` into `math.h` and making `stdlib.h` include `math.h`. In order to get the underlying C declarations from the "real" `stdlib.h` inside our `math.h` we need some trickery. Specifically we need to make `stdlib.h` include next itself. Suggestions for a cleaner implementation are welcome. Reviewers: mclow.lists, ldionne Reviewed By: ldionne Subscribers: krytarowski, fedor.sergeev, dexonsmith, jdoerfert, jsji, libcxx-commits Differential Revision: https://reviews.llvm.org/D60097 llvm-svn: 359020
This commit is contained in:
parent
f945429fed
commit
1670772adc
|
@ -297,6 +297,9 @@ long double truncl(long double x);
|
|||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#define _LIBCPP_STDLIB_INCLUDE_NEXT
|
||||
#include <stdlib.h>
|
||||
|
||||
#include_next <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -754,20 +757,61 @@ isunordered(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
|
|||
|
||||
// abs
|
||||
|
||||
#undef abs
|
||||
#undef labs
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
#undef llabs
|
||||
#endif
|
||||
|
||||
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
|
||||
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
|
||||
inline _LIBCPP_INLINE_VISIBILITY long abs(long __x) _NOEXCEPT {
|
||||
return ::labs(__x);
|
||||
}
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {
|
||||
return ::llabs(__x);
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_LONG_LONG
|
||||
#endif // !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
|
||||
|
||||
|
||||
#if !(defined(_AIX) || defined(__sun__))
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
float
|
||||
abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);}
|
||||
inline _LIBCPP_INLINE_VISIBILITY float abs(float __lcpp_x) _NOEXCEPT {
|
||||
return ::fabsf(__lcpp_x);
|
||||
}
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
double
|
||||
abs(double __lcpp_x) _NOEXCEPT {return ::fabs(__lcpp_x);}
|
||||
inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
|
||||
return ::fabs(__lcpp_x);
|
||||
}
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
long double
|
||||
abs(long double __lcpp_x) _NOEXCEPT {return ::fabsl(__lcpp_x);}
|
||||
inline _LIBCPP_INLINE_VISIBILITY long double
|
||||
abs(long double __lcpp_x) _NOEXCEPT {
|
||||
return ::fabsl(__lcpp_x);
|
||||
}
|
||||
#endif // !(defined(_AIX) || defined(__sun__))
|
||||
|
||||
// div
|
||||
|
||||
#undef div
|
||||
#undef ldiv
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
#undef lldiv
|
||||
#endif
|
||||
|
||||
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
|
||||
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
|
||||
inline _LIBCPP_INLINE_VISIBILITY ldiv_t div(long __x, long __y) _NOEXCEPT {
|
||||
return ::ldiv(__x, __y);
|
||||
}
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x,
|
||||
long long __y) _NOEXCEPT {
|
||||
return ::lldiv(__x, __y);
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_LONG_LONG
|
||||
#endif // _LIBCPP_MSVCRT / __sun__ / _AIX
|
||||
|
||||
// acos
|
||||
|
||||
#if !(defined(_AIX) || defined(__sun__))
|
||||
|
|
|
@ -7,12 +7,16 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__need_malloc_and_calloc)
|
||||
#if defined(__need_malloc_and_calloc) || defined(_LIBCPP_STDLIB_INCLUDE_NEXT)
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if defined(_LIBCPP_STDLIB_INCLUDE_NEXT)
|
||||
#undef _LIBCPP_STDLIB_INCLUDE_NEXT
|
||||
#endif
|
||||
|
||||
#include_next <stdlib.h>
|
||||
|
||||
#elif !defined(_LIBCPP_STDLIB_H)
|
||||
|
@ -93,33 +97,7 @@ void *aligned_alloc(size_t alignment, size_t size); // C11
|
|||
#include_next <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C++" {
|
||||
|
||||
#undef abs
|
||||
#undef div
|
||||
#undef labs
|
||||
#undef ldiv
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
#undef llabs
|
||||
#undef lldiv
|
||||
#endif
|
||||
|
||||
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
|
||||
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
|
||||
inline _LIBCPP_INLINE_VISIBILITY long abs( long __x) _NOEXCEPT {return labs(__x);}
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {return llabs(__x);}
|
||||
#endif // _LIBCPP_HAS_NO_LONG_LONG
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY ldiv_t div( long __x, long __y) _NOEXCEPT {return ldiv(__x, __y);}
|
||||
#ifndef _LIBCPP_HAS_NO_LONG_LONG
|
||||
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x, long long __y) _NOEXCEPT {return lldiv(__x, __y);}
|
||||
#endif // _LIBCPP_HAS_NO_LONG_LONG
|
||||
#endif // _LIBCPP_MSVCRT / __sun__ / _AIX
|
||||
|
||||
} // extern "C++"
|
||||
|
||||
#include <math.h>
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _LIBCPP_STDLIB_H
|
||||
|
|
|
@ -97,13 +97,45 @@ Ambiguous scalbn(Ambiguous, Ambiguous){ return Ambiguous(); }
|
|||
Ambiguous tgamma(Ambiguous){ return Ambiguous(); }
|
||||
Ambiguous trunc(Ambiguous){ return Ambiguous(); }
|
||||
|
||||
template <class T, class = decltype(::abs(std::declval<T>()))>
|
||||
std::true_type has_abs_imp(int);
|
||||
template <class T>
|
||||
std::false_type has_abs_imp(...);
|
||||
|
||||
template <class T>
|
||||
struct has_abs : decltype(has_abs_imp<T>(0)) {};
|
||||
|
||||
void test_abs()
|
||||
{
|
||||
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
|
||||
assert(abs(-1.) == 1);
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||
#endif
|
||||
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
|
||||
static_assert(
|
||||
(std::is_same<decltype(abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((int)0)), int>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((long)0)), long>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((long long)0)), long long>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((unsigned short)0)), int>::value),
|
||||
"");
|
||||
|
||||
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value),
|
||||
"");
|
||||
|
||||
static_assert(!has_abs<unsigned>::value, "");
|
||||
static_assert(!has_abs<unsigned long>::value, "");
|
||||
static_assert(!has_abs<unsigned long long>::value, "");
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
assert(abs(-1.) == 1);
|
||||
}
|
||||
|
||||
void test_acos()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
|
@ -63,6 +64,52 @@
|
|||
#error RAND_MAX not defined
|
||||
#endif
|
||||
|
||||
template <class T, class = decltype(::abs(std::declval<T>()))>
|
||||
std::true_type has_abs_imp(int);
|
||||
template <class T>
|
||||
std::false_type has_abs_imp(...);
|
||||
|
||||
template <class T>
|
||||
struct has_abs : decltype(has_abs_imp<T>(0)) {};
|
||||
|
||||
void test_abs() {
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||
#endif
|
||||
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
|
||||
static_assert(
|
||||
(std::is_same<decltype(abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((int)0)), int>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((long)0)), long>::value), "");
|
||||
static_assert((std::is_same<decltype(abs((long long)0)), long long>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((unsigned short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((signed char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs((char)0)), int>::value),
|
||||
"");
|
||||
|
||||
static_assert(!has_abs<unsigned>::value, "");
|
||||
static_assert(!has_abs<unsigned long>::value, "");
|
||||
static_assert(!has_abs<unsigned long long>::value, "");
|
||||
static_assert(!has_abs<size_t>::value, "");
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
assert(abs(-1.) == 1);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
size_t s = 0; ((void)s);
|
||||
|
@ -117,5 +164,7 @@ int main(int, char**)
|
|||
static_assert((std::is_same<decltype(mbstowcs(pw,"",0)), size_t>::value), "");
|
||||
static_assert((std::is_same<decltype(wcstombs(pc,pwc,0)), size_t>::value), "");
|
||||
|
||||
return 0;
|
||||
test_abs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,52 @@ void test_div_struct() {
|
|||
((void) obj);
|
||||
};
|
||||
|
||||
template <class T, class = decltype(std::abs(std::declval<T>()))>
|
||||
std::true_type has_abs_imp(int);
|
||||
template <class T>
|
||||
std::false_type has_abs_imp(...);
|
||||
|
||||
template <class T>
|
||||
struct has_abs : decltype(has_abs_imp<T>(0)) {};
|
||||
|
||||
void test_abs() {
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||
#endif
|
||||
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
|
||||
static_assert(
|
||||
(std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((int)0)), int>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((long)0)), long>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((long long)0)), long long>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((signed char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((char)0)), int>::value),
|
||||
"");
|
||||
|
||||
static_assert(!has_abs<unsigned>::value, "");
|
||||
static_assert(!has_abs<unsigned long>::value, "");
|
||||
static_assert(!has_abs<unsigned long long>::value, "");
|
||||
static_assert(!has_abs<size_t>::value, "");
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
assert(std::abs(-1.) == 1);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
@ -109,5 +155,7 @@ int main(int, char**)
|
|||
static_assert((std::is_same<decltype(std::mbstowcs(pw,"",0)), std::size_t>::value), "");
|
||||
static_assert((std::is_same<decltype(std::wcstombs(pc,pwc,0)), std::size_t>::value), "");
|
||||
|
||||
return 0;
|
||||
test_abs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -100,15 +100,54 @@ Ambiguous scalbn(Ambiguous, Ambiguous){ return Ambiguous(); }
|
|||
Ambiguous tgamma(Ambiguous){ return Ambiguous(); }
|
||||
Ambiguous trunc(Ambiguous){ return Ambiguous(); }
|
||||
|
||||
void test_abs()
|
||||
{
|
||||
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
|
||||
assert(std::abs(-1.) == 1);
|
||||
template <class T, class = decltype(std::abs(std::declval<T>()))>
|
||||
std::true_type has_abs_imp(int);
|
||||
template <class T>
|
||||
std::false_type has_abs_imp(...);
|
||||
|
||||
template <class T>
|
||||
struct has_abs : decltype(has_abs_imp<T>(0)) {};
|
||||
|
||||
void test_abs() {
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||
#endif
|
||||
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
|
||||
static_assert(
|
||||
(std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((int)0)), int>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((long)0)), long>::value), "");
|
||||
static_assert((std::is_same<decltype(std::abs((long long)0)), long long>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((signed char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((short)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(std::abs((char)0)), int>::value),
|
||||
"");
|
||||
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
|
||||
|
||||
static_assert(!has_abs<unsigned>::value, "");
|
||||
static_assert(!has_abs<unsigned long>::value, "");
|
||||
static_assert(!has_abs<unsigned long long>::value, "");
|
||||
static_assert(!has_abs<size_t>::value, "");
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
assert(std::abs(-1.) == 1);
|
||||
}
|
||||
|
||||
|
||||
void test_acos()
|
||||
{
|
||||
static_assert((std::is_same<decltype(std::acos((float)0)), float>::value), "");
|
||||
|
|
|
@ -281,7 +281,7 @@
|
|||
<tr><td><a href="https://wg21.link/LWG2492">2492</a></td><td>Clarify requirements for <tt>comp</tt></td><td>Kona</td><td>Complete</td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2495">2495</a></td><td>There is no such thing as an Exception Safety element</td><td>Kona</td><td>Complete</td></tr>
|
||||
<tr><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2192">2192</a></td><td>Validity and return type of <tt>std::abs(0u)</tt> is unclear</td><td>Jacksonville</td><td></td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2192">2192</a></td><td>Validity and return type of <tt>std::abs(0u)</tt> is unclear</td><td>Jacksonville</td><td>Complete</td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2276">2276</a></td><td>Missing requirement on <tt>std::promise::set_exception</tt></td><td>Jacksonville</td><td>Complete</td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2296">2296</a></td><td><tt>std::addressof</tt> should be <tt>constexpr</td><td>Jacksonville</td><td>Complete (Clang Only)</td></tr>
|
||||
<tr><td><a href="https://wg21.link/LWG2450">2450</a></td><td><tt>(greater|less|greater_equal|less_equal)<void></tt> do not yield a total order for pointers</td><td>Jacksonville</td><td>Complete</td></tr>
|
||||
|
|
Loading…
Reference in New Issue