Skip to content

Commit 1670772

Browse files
committed
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
1 parent f945429 commit 1670772

File tree

7 files changed

+242
-52
lines changed

7 files changed

+242
-52
lines changed

libcxx/include/math.h

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ long double truncl(long double x);
297297
#pragma GCC system_header
298298
#endif
299299

300+
#define _LIBCPP_STDLIB_INCLUDE_NEXT
301+
#include <stdlib.h>
302+
300303
#include_next <math.h>
301304

302305
#ifdef __cplusplus
@@ -754,20 +757,61 @@ isunordered(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
754757

755758
// abs
756759

760+
#undef abs
761+
#undef labs
762+
#ifndef _LIBCPP_HAS_NO_LONG_LONG
763+
#undef llabs
764+
#endif
765+
766+
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
767+
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
768+
inline _LIBCPP_INLINE_VISIBILITY long abs(long __x) _NOEXCEPT {
769+
return ::labs(__x);
770+
}
771+
#ifndef _LIBCPP_HAS_NO_LONG_LONG
772+
inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {
773+
return ::llabs(__x);
774+
}
775+
#endif // _LIBCPP_HAS_NO_LONG_LONG
776+
#endif // !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
777+
778+
757779
#if !(defined(_AIX) || defined(__sun__))
758-
inline _LIBCPP_INLINE_VISIBILITY
759-
float
760-
abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);}
780+
inline _LIBCPP_INLINE_VISIBILITY float abs(float __lcpp_x) _NOEXCEPT {
781+
return ::fabsf(__lcpp_x);
782+
}
761783

762-
inline _LIBCPP_INLINE_VISIBILITY
763-
double
764-
abs(double __lcpp_x) _NOEXCEPT {return ::fabs(__lcpp_x);}
784+
inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
785+
return ::fabs(__lcpp_x);
786+
}
765787

766-
inline _LIBCPP_INLINE_VISIBILITY
767-
long double
768-
abs(long double __lcpp_x) _NOEXCEPT {return ::fabsl(__lcpp_x);}
788+
inline _LIBCPP_INLINE_VISIBILITY long double
789+
abs(long double __lcpp_x) _NOEXCEPT {
790+
return ::fabsl(__lcpp_x);
791+
}
769792
#endif // !(defined(_AIX) || defined(__sun__))
770793

794+
// div
795+
796+
#undef div
797+
#undef ldiv
798+
#ifndef _LIBCPP_HAS_NO_LONG_LONG
799+
#undef lldiv
800+
#endif
801+
802+
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
803+
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
804+
inline _LIBCPP_INLINE_VISIBILITY ldiv_t div(long __x, long __y) _NOEXCEPT {
805+
return ::ldiv(__x, __y);
806+
}
807+
#ifndef _LIBCPP_HAS_NO_LONG_LONG
808+
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x,
809+
long long __y) _NOEXCEPT {
810+
return ::lldiv(__x, __y);
811+
}
812+
#endif // _LIBCPP_HAS_NO_LONG_LONG
813+
#endif // _LIBCPP_MSVCRT / __sun__ / _AIX
814+
771815
// acos
772816

773817
#if !(defined(_AIX) || defined(__sun__))

libcxx/include/stdlib.h

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10-
#if defined(__need_malloc_and_calloc)
10+
#if defined(__need_malloc_and_calloc) || defined(_LIBCPP_STDLIB_INCLUDE_NEXT)
1111

1212
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1313
#pragma GCC system_header
1414
#endif
1515

16+
#if defined(_LIBCPP_STDLIB_INCLUDE_NEXT)
17+
#undef _LIBCPP_STDLIB_INCLUDE_NEXT
18+
#endif
19+
1620
#include_next <stdlib.h>
1721

1822
#elif !defined(_LIBCPP_STDLIB_H)
@@ -93,33 +97,7 @@ void *aligned_alloc(size_t alignment, size_t size); // C11
9397
#include_next <stdlib.h>
9498

9599
#ifdef __cplusplus
96-
97-
extern "C++" {
98-
99-
#undef abs
100-
#undef div
101-
#undef labs
102-
#undef ldiv
103-
#ifndef _LIBCPP_HAS_NO_LONG_LONG
104-
#undef llabs
105-
#undef lldiv
106-
#endif
107-
108-
// MSVCRT already has the correct prototype in <stdlib.h> if __cplusplus is defined
109-
#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_AIX)
110-
inline _LIBCPP_INLINE_VISIBILITY long abs( long __x) _NOEXCEPT {return labs(__x);}
111-
#ifndef _LIBCPP_HAS_NO_LONG_LONG
112-
inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {return llabs(__x);}
113-
#endif // _LIBCPP_HAS_NO_LONG_LONG
114-
115-
inline _LIBCPP_INLINE_VISIBILITY ldiv_t div( long __x, long __y) _NOEXCEPT {return ldiv(__x, __y);}
116-
#ifndef _LIBCPP_HAS_NO_LONG_LONG
117-
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x, long long __y) _NOEXCEPT {return lldiv(__x, __y);}
118-
#endif // _LIBCPP_HAS_NO_LONG_LONG
119-
#endif // _LIBCPP_MSVCRT / __sun__ / _AIX
120-
121-
} // extern "C++"
122-
100+
#include <math.h>
123101
#endif // __cplusplus
124102

125103
#endif // _LIBCPP_STDLIB_H

libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,45 @@ Ambiguous scalbn(Ambiguous, Ambiguous){ return Ambiguous(); }
9797
Ambiguous tgamma(Ambiguous){ return Ambiguous(); }
9898
Ambiguous trunc(Ambiguous){ return Ambiguous(); }
9999

100+
template <class T, class = decltype(::abs(std::declval<T>()))>
101+
std::true_type has_abs_imp(int);
102+
template <class T>
103+
std::false_type has_abs_imp(...);
104+
105+
template <class T>
106+
struct has_abs : decltype(has_abs_imp<T>(0)) {};
107+
100108
void test_abs()
101109
{
102-
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
103-
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
104-
static_assert((std::is_same<decltype(abs((long double)0)), long double>::value), "");
105-
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
106-
assert(abs(-1.) == 1);
110+
#ifdef __clang__
111+
#pragma clang diagnostic push
112+
#pragma clang diagnostic ignored "-Wabsolute-value"
113+
#endif
114+
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
115+
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
116+
static_assert(
117+
(std::is_same<decltype(abs((long double)0)), long double>::value), "");
118+
static_assert((std::is_same<decltype(abs((int)0)), int>::value), "");
119+
static_assert((std::is_same<decltype(abs((long)0)), long>::value), "");
120+
static_assert((std::is_same<decltype(abs((long long)0)), long long>::value),
121+
"");
122+
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
123+
"");
124+
static_assert((std::is_same<decltype(abs((unsigned short)0)), int>::value),
125+
"");
126+
127+
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value),
128+
"");
129+
130+
static_assert(!has_abs<unsigned>::value, "");
131+
static_assert(!has_abs<unsigned long>::value, "");
132+
static_assert(!has_abs<unsigned long long>::value, "");
133+
134+
#ifdef __clang__
135+
#pragma clang diagnostic pop
136+
#endif
137+
138+
assert(abs(-1.) == 1);
107139
}
108140

109141
void test_acos()

libcxx/test/std/depr/depr.c.headers/stdlib_h.pass.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <stdlib.h>
1212
#include <type_traits>
13+
#include <cassert>
1314

1415
#include "test_macros.h"
1516

@@ -63,6 +64,52 @@
6364
#error RAND_MAX not defined
6465
#endif
6566

67+
template <class T, class = decltype(::abs(std::declval<T>()))>
68+
std::true_type has_abs_imp(int);
69+
template <class T>
70+
std::false_type has_abs_imp(...);
71+
72+
template <class T>
73+
struct has_abs : decltype(has_abs_imp<T>(0)) {};
74+
75+
void test_abs() {
76+
#ifdef __clang__
77+
#pragma clang diagnostic push
78+
#pragma clang diagnostic ignored "-Wabsolute-value"
79+
#endif
80+
static_assert((std::is_same<decltype(abs((float)0)), float>::value), "");
81+
static_assert((std::is_same<decltype(abs((double)0)), double>::value), "");
82+
static_assert(
83+
(std::is_same<decltype(abs((long double)0)), long double>::value), "");
84+
static_assert((std::is_same<decltype(abs((int)0)), int>::value), "");
85+
static_assert((std::is_same<decltype(abs((long)0)), long>::value), "");
86+
static_assert((std::is_same<decltype(abs((long long)0)), long long>::value),
87+
"");
88+
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
89+
"");
90+
static_assert((std::is_same<decltype(abs((unsigned short)0)), int>::value),
91+
"");
92+
static_assert((std::is_same<decltype(abs((signed char)0)), int>::value),
93+
"");
94+
static_assert((std::is_same<decltype(abs((short)0)), int>::value),
95+
"");
96+
static_assert((std::is_same<decltype(abs((unsigned char)0)), int>::value),
97+
"");
98+
static_assert((std::is_same<decltype(abs((char)0)), int>::value),
99+
"");
100+
101+
static_assert(!has_abs<unsigned>::value, "");
102+
static_assert(!has_abs<unsigned long>::value, "");
103+
static_assert(!has_abs<unsigned long long>::value, "");
104+
static_assert(!has_abs<size_t>::value, "");
105+
106+
#ifdef __clang__
107+
#pragma clang diagnostic pop
108+
#endif
109+
110+
assert(abs(-1.) == 1);
111+
}
112+
66113
int main(int, char**)
67114
{
68115
size_t s = 0; ((void)s);
@@ -117,5 +164,7 @@ int main(int, char**)
117164
static_assert((std::is_same<decltype(mbstowcs(pw,"",0)), size_t>::value), "");
118165
static_assert((std::is_same<decltype(wcstombs(pc,pwc,0)), size_t>::value), "");
119166

120-
return 0;
167+
test_abs();
168+
169+
return 0;
121170
}

libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,52 @@ void test_div_struct() {
4949
((void) obj);
5050
};
5151

52+
template <class T, class = decltype(std::abs(std::declval<T>()))>
53+
std::true_type has_abs_imp(int);
54+
template <class T>
55+
std::false_type has_abs_imp(...);
56+
57+
template <class T>
58+
struct has_abs : decltype(has_abs_imp<T>(0)) {};
59+
60+
void test_abs() {
61+
#ifdef __clang__
62+
#pragma clang diagnostic push
63+
#pragma clang diagnostic ignored "-Wabsolute-value"
64+
#endif
65+
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
66+
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
67+
static_assert(
68+
(std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
69+
static_assert((std::is_same<decltype(std::abs((int)0)), int>::value), "");
70+
static_assert((std::is_same<decltype(std::abs((long)0)), long>::value), "");
71+
static_assert((std::is_same<decltype(std::abs((long long)0)), long long>::value),
72+
"");
73+
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
74+
"");
75+
static_assert((std::is_same<decltype(std::abs((unsigned short)0)), int>::value),
76+
"");
77+
static_assert((std::is_same<decltype(std::abs((signed char)0)), int>::value),
78+
"");
79+
static_assert((std::is_same<decltype(std::abs((short)0)), int>::value),
80+
"");
81+
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
82+
"");
83+
static_assert((std::is_same<decltype(std::abs((char)0)), int>::value),
84+
"");
85+
86+
static_assert(!has_abs<unsigned>::value, "");
87+
static_assert(!has_abs<unsigned long>::value, "");
88+
static_assert(!has_abs<unsigned long long>::value, "");
89+
static_assert(!has_abs<size_t>::value, "");
90+
91+
#ifdef __clang__
92+
#pragma clang diagnostic pop
93+
#endif
94+
95+
assert(std::abs(-1.) == 1);
96+
}
97+
5298
int main(int, char**)
5399
{
54100
std::size_t s = 0;
@@ -109,5 +155,7 @@ int main(int, char**)
109155
static_assert((std::is_same<decltype(std::mbstowcs(pw,"",0)), std::size_t>::value), "");
110156
static_assert((std::is_same<decltype(std::wcstombs(pc,pwc,0)), std::size_t>::value), "");
111157

112-
return 0;
158+
test_abs();
159+
160+
return 0;
113161
}

libcxx/test/std/numerics/c.math/cmath.pass.cpp

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,54 @@ Ambiguous scalbn(Ambiguous, Ambiguous){ return Ambiguous(); }
100100
Ambiguous tgamma(Ambiguous){ return Ambiguous(); }
101101
Ambiguous trunc(Ambiguous){ return Ambiguous(); }
102102

103-
void test_abs()
104-
{
105-
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
106-
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
107-
static_assert((std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
108-
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
109-
assert(std::abs(-1.) == 1);
103+
template <class T, class = decltype(std::abs(std::declval<T>()))>
104+
std::true_type has_abs_imp(int);
105+
template <class T>
106+
std::false_type has_abs_imp(...);
107+
108+
template <class T>
109+
struct has_abs : decltype(has_abs_imp<T>(0)) {};
110+
111+
void test_abs() {
112+
#ifdef __clang__
113+
#pragma clang diagnostic push
114+
#pragma clang diagnostic ignored "-Wabsolute-value"
115+
#endif
116+
static_assert((std::is_same<decltype(std::abs((float)0)), float>::value), "");
117+
static_assert((std::is_same<decltype(std::abs((double)0)), double>::value), "");
118+
static_assert(
119+
(std::is_same<decltype(std::abs((long double)0)), long double>::value), "");
120+
static_assert((std::is_same<decltype(std::abs((int)0)), int>::value), "");
121+
static_assert((std::is_same<decltype(std::abs((long)0)), long>::value), "");
122+
static_assert((std::is_same<decltype(std::abs((long long)0)), long long>::value),
123+
"");
124+
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
125+
"");
126+
static_assert((std::is_same<decltype(std::abs((unsigned short)0)), int>::value),
127+
"");
128+
static_assert((std::is_same<decltype(std::abs((signed char)0)), int>::value),
129+
"");
130+
static_assert((std::is_same<decltype(std::abs((short)0)), int>::value),
131+
"");
132+
static_assert((std::is_same<decltype(std::abs((unsigned char)0)), int>::value),
133+
"");
134+
static_assert((std::is_same<decltype(std::abs((char)0)), int>::value),
135+
"");
136+
static_assert((std::is_same<decltype(abs(Ambiguous())), Ambiguous>::value), "");
137+
138+
static_assert(!has_abs<unsigned>::value, "");
139+
static_assert(!has_abs<unsigned long>::value, "");
140+
static_assert(!has_abs<unsigned long long>::value, "");
141+
static_assert(!has_abs<size_t>::value, "");
142+
143+
#ifdef __clang__
144+
#pragma clang diagnostic pop
145+
#endif
146+
147+
assert(std::abs(-1.) == 1);
110148
}
111149

150+
112151
void test_acos()
113152
{
114153
static_assert((std::is_same<decltype(std::acos((float)0)), float>::value), "");

libcxx/www/cxx1z_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ <h3>Library Working group Issues Status</h3>
281281
<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>
282282
<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>
283283
<tr><td></td><td></td><td></td><td></td></tr>
284-
<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>
284+
<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>
285285
<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>
286286
<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>
287287
<tr><td><a href="https://wg21.link/LWG2450">2450</a></td><td><tt>(greater|less|greater_equal|less_equal)&lt;void&gt;</tt> do not yield a total order for pointers</td><td>Jacksonville</td><td>Complete</td></tr>

0 commit comments

Comments
 (0)