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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@359020 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/math.h b/include/math.h
index 6f9a76b..9558321 100644
--- a/include/math.h
+++ b/include/math.h
@@ -297,6 +297,9 @@
 #pragma GCC system_header
 #endif
 
+#define _LIBCPP_STDLIB_INCLUDE_NEXT
+#include <stdlib.h>
+
 #include_next <math.h>
 
 #ifdef __cplusplus
@@ -754,20 +757,61 @@
 
 // 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__))
diff --git a/include/stdlib.h b/include/stdlib.h
index 2087544..1d68275 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -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 @@
 #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
diff --git a/test/std/depr/depr.c.headers/math_h.pass.cpp b/test/std/depr/depr.c.headers/math_h.pass.cpp
index b0b6c0c..2077a07 100644
--- a/test/std/depr/depr.c.headers/math_h.pass.cpp
+++ b/test/std/depr/depr.c.headers/math_h.pass.cpp
@@ -97,13 +97,45 @@
 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()
diff --git a/test/std/depr/depr.c.headers/stdlib_h.pass.cpp b/test/std/depr/depr.c.headers/stdlib_h.pass.cpp
index 4c0218d..d1fde66 100644
--- a/test/std/depr/depr.c.headers/stdlib_h.pass.cpp
+++ b/test/std/depr/depr.c.headers/stdlib_h.pass.cpp
@@ -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 @@
     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;
 }
diff --git a/test/std/language.support/support.runtime/cstdlib.pass.cpp b/test/std/language.support/support.runtime/cstdlib.pass.cpp
index d8b6636..8e63573 100644
--- a/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -49,6 +49,52 @@
     ((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 @@
     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;
 }
diff --git a/test/std/numerics/c.math/cmath.pass.cpp b/test/std/numerics/c.math/cmath.pass.cpp
index 3f9a5f5..fc95395 100644
--- a/test/std/numerics/c.math/cmath.pass.cpp
+++ b/test/std/numerics/c.math/cmath.pass.cpp
@@ -100,15 +100,54 @@
 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), "");
diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html
index a4ef757..b8357ff 100644
--- a/www/cxx1z_status.html
+++ b/www/cxx1z_status.html
@@ -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)&lt;void&gt;</tt> do not yield a total order for pointers</td><td>Jacksonville</td><td>Complete</td></tr>