diff mbox

libstdc++/14608 Add C++-conforming wrappers for stdlib.h and math.h

Message ID 20160108191852.GN30323@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Jan. 8, 2016, 7:18 p.m. UTC
This resolves the longstanding issue that #include <math.h> uses the C
library header, which on most targets doesn't declare the additional
overloads required by C++11 26.8 [c.math], and similarly for
<stdlib.h>.

With this patch libstdc++ provides its own <math.h> and <stdlib.h>
wrappers, which are equivalent to <cmath> or <cstdlib> followed by
using-directives for all standard names. This means there are no more
inconsistencies in the contents of the <cxxx> and <xxx.h> headers.

This check might be surprising:
#if !defined __cplusplus || defined _GLIBCXX_INCLUDE_NEXT_C_HEADERS

Checking for __cplusplus is necessary to bootstrap because the new
libstdc++ math.h wrapper is in the header search path when
libstdc++/cp-demangle.c is built, but that's a C file and so wants the
C header not the wrapper.

The second condition ensures that when the <cxxx> headers say
#include_next <xxx.h> they really find the C library version, not some
other libstdc++ <xxx.h> wrapper that is already installed elsewhere on
the system. That can happen if you build libstdc++ with this patch and
install it, then build again with the same prefix. The directory
$PREFIX/include/c++/6.0.0 ends up in the header search path when
running the testsuite, and without _GLIBCXX_INCLUDE_NEXT_C_HEADERS
the #include_next <math.h> finds the previously installed wrapper
$PREFIX/include/c++/6.0.0/math.h, which then tries to #include <cmath>
again and add using-directives for functions which haven't been
declared yet because we haven't found the real C library header.

It's possible that this is only a problem when building and testing
libstdc++ itself, so we could remove the check and solve the problem
by adjusting paths used during build/test so that our own wrapper is
never found. I'm not confident of that, so it seems safer to have this
macro so that <cstdlib> and <cmath> can define it to ensure they get
the real C header, even if they go through one or more wrappers to get
there!

It's also possible that include/c/cstdlib and include/c/cmath need to
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS before they use #include_next,
to prevent them finding the wrapper. I have only really considered  the
--enable-cheaders=c_global configuration, because I don't understand
the other ones.

This patch cannot be applied without the patch at
https://gcc.gnu.org/ml/gcc-patches/2016-01/msg00416.html because with
the new <math.h> wrapper we *always* hit the bug where <cmath> #undefs
the C99 macros and then collides with the obsolete isinf and isnan
functions.

The second patch (which requires both the previous patches) then
implements the proposed resolution of LWG 2294, ensuring that all
std::abs() overloads for integers and floating-point types are
available when you include either of <cmath> or <cstdlib>. That issue
is still open (and LWG 2291 adds a constraint on the generic
std::abs(T) function template which I haven't implemented yet). I
might commit it anyway, as the committee's direction is clear.

All tested x86_64-linux and x86_64-freebsd10.2, I don't plan to commit
any of these patches until next week, to give people time to digest
them and point out any problems I've missed.
commit f4bd35b818f0acbbb879fd7ca9aa6bd7ec955b5c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jan 7 16:01:09 2016 +0000

    Define all std::abs overloads in both <cmath> and <cstdlib>
    
    	* include/Makefile.am: Add bits/std_abs.h.
    	* include/Makefile.in: Regenerate.
    	* include/bits/std_abs.h: New header defining all required overloads
    	of std::abs in one place (LWG 2294).
    	* include/c_global/cmath (abs(double), abs(float), abs(long double)):
    	Move to bits/std_abs.h.
    	* include/c_global/cstdlib (abs(long), abs(long long)): Move to
    	bits/std_abs.h.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 84cb8b1..bd7c8d7 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -122,6 +122,7 @@ bits_headers = \
 	${bits_srcdir}/mask_array.h \
 	${bits_srcdir}/memoryfwd.h \
 	${bits_srcdir}/move.h \
+	${bits_srcdir}/std_abs.h \
 	${bits_srcdir}/std_mutex.h \
 	${bits_srcdir}/ostream.tcc \
 	${bits_srcdir}/ostream_insert.h \
diff --git a/libstdc++-v3/include/bits/std_abs.h b/libstdc++-v3/include/bits/std_abs.h
new file mode 100644
index 0000000..beb09b9
--- /dev/null
+++ b/libstdc++-v3/include/bits/std_abs.h
@@ -0,0 +1,80 @@
+// -*- C++ -*- C library enhancements header.
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/std_abs.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{cmath, cstdlib}
+ */
+
+#ifndef _GLIBCXX_BITS_STD_ABS_H
+#define _GLIBCXX_BITS_STD_ABS_H
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include_next <stdlib.h>
+
+#ifdef __CORRECT_ISO_CPP_MATH_H_PROTO
+# include_next <math.h>
+#endif
+
+#undef abs
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  using ::abs;
+
+#ifndef __CORRECT_ISO_CPP_STDLIB_H_PROTO
+  inline long
+  abs(long __i) { return __builtin_labs(__i); }
+#endif
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+  inline long long
+  abs(long long __x) { return __builtin_llabs (__x); }
+#endif
+
+// _GLIBCXX_RESOLVE_LIB_DEFECTS
+// 2294. <cstdlib> should declare abs(double)
+
+#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
+  inline _GLIBCXX_CONSTEXPR double
+  abs(double __x)
+  { return __builtin_fabs(__x); }
+
+  inline _GLIBCXX_CONSTEXPR float
+  abs(float __x)
+  { return __builtin_fabsf(__x); }
+
+  inline _GLIBCXX_CONSTEXPR long double
+  abs(long double __x)
+  { return __builtin_fabsl(__x); }
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#endif // _GLIBCXX_BITS_STD_ABS_H
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 7eed8e1..095ecd7 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -43,6 +43,7 @@
 #include <ext/type_traits.h>
 #define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 #include_next <math.h>
+#include <bits/std_abs.h>
 #undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 
 #ifndef _GLIBCXX_CMATH
@@ -78,22 +79,6 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
-  inline _GLIBCXX_CONSTEXPR double
-  abs(double __x)
-  { return __builtin_fabs(__x); }
-#endif
-
-#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
-  inline _GLIBCXX_CONSTEXPR float
-  abs(float __x)
-  { return __builtin_fabsf(__x); }
-
-  inline _GLIBCXX_CONSTEXPR long double
-  abs(long double __x)
-  { return __builtin_fabsl(__x); }
-#endif
-
   template<typename _Tp>
     inline _GLIBCXX_CONSTEXPR
     typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
diff --git a/libstdc++-v3/include/c_global/cstdlib b/libstdc++-v3/include/c_global/cstdlib
index 44b6e5c..bba4ce5 100644
--- a/libstdc++-v3/include/c_global/cstdlib
+++ b/libstdc++-v3/include/c_global/cstdlib
@@ -73,6 +73,7 @@ namespace std
 // wrapper that might already be installed later in the include search path.
 #define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 #include_next <stdlib.h>
+#include <bits/std_abs.h>
 #undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 
 // Get rid of those macros defined in <stdlib.h> in lieu of real functions.
@@ -166,18 +167,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // _GLIBCXX_USE_WCHAR_T
 
 #ifndef __CORRECT_ISO_CPP_STDLIB_H_PROTO
-  inline long
-  abs(long __i) { return __builtin_labs(__i); }
-
   inline ldiv_t
   div(long __i, long __j) { return ldiv(__i, __j); }
 #endif
 
-#ifdef _GLIBCXX_USE_LONG_LONG
-  inline long long
-  abs(long long __x) { return __builtin_llabs (__x); }
-#endif
-
 #if defined(__GLIBCXX_TYPE_INT_N_0)
   inline __GLIBCXX_TYPE_INT_N_0
   abs(__GLIBCXX_TYPE_INT_N_0 __x) { return __x >= 0 ? __x : -__x; }
diff mbox

Patch

commit ead087854b669262ee258ff3835d96a593dd9e65
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jan 8 15:43:14 2016 +0000

    Add C++-conforming wrappers for stdlib.h and math.h
    
    	PR libstdc++/14608
    	PR libstdc++/60401
    	* include/Makefile.am: Use c_compatibility math.h and stdlib.h for
    	--enable-cheaders=c_global configs.
    	* include/Makefile.in: Regenerate.
    	* include/c_compatibility/math.h: Remove obsolete _GLIBCXX_NAMESPACE_C
    	test and allow inclusion from C files.
    	* include/c_compatibility/stdlib.h: Likewise. Support freestanding.
    	(at_quick_exit, quick_exit): Add using directives.
    	* include/c_global/cmath: Use #include_next for math.h.
    	* include/c_global/cstdlib: Use #include_next for stdlib.h.
    	* testsuite/26_numerics/headers/cmath/14608.cc: New.
    	* testsuite/26_numerics/headers/cmath/c99_classification_macros_c.cc:
    	Remove xfail for most targets.
    	* testsuite/26_numerics/headers/cstdlib/60401.cc: New.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index b0a9373..84cb8b1 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -739,7 +739,9 @@  if GLIBCXX_C_HEADERS_C_GLOBAL
 c_compatibility_headers = \
 	${c_compatibility_srcdir}/complex.h \
 	${c_compatibility_srcdir}/fenv.h \
-	${c_compatibility_srcdir}/tgmath.h
+	${c_compatibility_srcdir}/tgmath.h \
+	${c_compatibility_srcdir}/math.h \
+	${c_compatibility_srcdir}/stdlib.h
 endif
 
 if GLIBCXX_C_HEADERS_C
diff --git a/libstdc++-v3/include/c_compatibility/math.h b/libstdc++-v3/include/c_compatibility/math.h
index 7617a31..67f5ef1 100644
--- a/libstdc++-v3/include/c_compatibility/math.h
+++ b/libstdc++-v3/include/c_compatibility/math.h
@@ -26,12 +26,15 @@ 
  *  This is a Standard C++ Library header.
  */
 
-#include <cmath>
 
 #ifndef _GLIBCXX_MATH_H
 #define _GLIBCXX_MATH_H 1
 
-#ifdef _GLIBCXX_NAMESPACE_C
+#if !defined __cplusplus || defined _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+# include_next <math.h>
+#else
+# include <cmath>
+
 using std::abs;
 using std::acos;
 using std::asin;
@@ -72,5 +75,4 @@  using std::isunordered;
 #endif
 
 #endif
-
 #endif
diff --git a/libstdc++-v3/include/c_compatibility/stdlib.h b/libstdc++-v3/include/c_compatibility/stdlib.h
index bd666d6..bd72580 100644
--- a/libstdc++-v3/include/c_compatibility/stdlib.h
+++ b/libstdc++-v3/include/c_compatibility/stdlib.h
@@ -26,25 +26,37 @@ 
  *  This is a Standard C++ Library header.
  */
 
-#include <cstdlib>
-
 #ifndef _GLIBCXX_STDLIB_H
 #define _GLIBCXX_STDLIB_H 1
 
-#ifdef _GLIBCXX_NAMESPACE_C
+#if !defined __cplusplus || defined _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+# include_next <stdlib.h>
+#else
+# include <cstdlib>
+
+using std::abort;
+using std::atexit;
+using std::exit;
+#if __cplusplus >= 201103L
+# ifdef _GLIBCXX_HAVE_AT_QUICK_EXIT
+  using std::at_quick_exit;
+# endif
+# ifdef _GLIBCXX_HAVE_QUICK_EXIT
+  using std::quick_exit;
+# endif
+#endif
+
+#if _GLIBCXX_HOSTED
 using std::div_t;
 using std::ldiv_t;
 
-using std::abort;
 using std::abs;
-using std::atexit;
 using std::atof;
 using std::atoi;
 using std::atol;
 using std::bsearch;
 using std::calloc;
 using std::div;
-using std::exit;
 using std::free;
 using std::getenv;
 using std::labs;
@@ -66,3 +78,4 @@  using std::wctomb;
 #endif
 
 #endif
+#endif
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6269e32..7eed8e1 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -41,7 +41,9 @@ 
 #include <bits/c++config.h>
 #include <bits/cpp_type_traits.h>
 #include <ext/type_traits.h>
-#include <math.h>
+#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+#include_next <math.h>
+#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 
 #ifndef _GLIBCXX_CMATH
 #define _GLIBCXX_CMATH 1
diff --git a/libstdc++-v3/include/c_global/cstdlib b/libstdc++-v3/include/c_global/cstdlib
index 0f506a4..44b6e5c 100644
--- a/libstdc++-v3/include/c_global/cstdlib
+++ b/libstdc++-v3/include/c_global/cstdlib
@@ -69,7 +69,11 @@  namespace std
 
 #else
 
-#include <stdlib.h>
+// Need to ensure this finds the C library's <stdlib.h> not a libstdc++
+// wrapper that might already be installed later in the include search path.
+#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+#include_next <stdlib.h>
+#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 
 // Get rid of those macros defined in <stdlib.h> in lieu of real functions.
 #undef abort
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/14608.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/14608.cc
new file mode 100644
index 0000000..65f5c6c
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/14608.cc
@@ -0,0 +1,38 @@ 
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+#include <cmath>
+// Also make names from <cmath> available in the global namespace:
+#include <math.h>
+
+bool foo(double d)
+{
+  return ::isfinite(d); // PR libstdc++/14608
+}
+
+int bar(double d)
+{
+  return ::signbit(d); // PR libstdc++/44611
+}
+
+constexpr bool is_double(double) { return true; }
+template<typename T> constexpr bool is_double(T) { return false; }
+using type = decltype(::abs(1.5));
+static_assert(is_double(type{}), "::abs(double) overload exists in <math.h>");
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c.cc
index ead3018..cbced7d 100644
--- a/libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c.cc
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c.cc
@@ -17,12 +17,10 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-do compile }
+// { dg-do compile { xfail uclibc } }
+// { dg-excess-errors "" { target uclibc } }
 // { dg-add-options no_pch }
 
-// { dg-xfail-if "" { { *-*-linux* *-*-gnu* *-*-darwin* *-*-solaris2.1[01]* hppa*-*-hpux* *-*-mingw* *-*-aix* } || { uclibc || newlib } } { "*" } { "" } }
-// { dg-excess-errors "" { target { { *-*-linux* *-*-gnu* *-*-darwin* *-*-solaris2.1[01]* hppa*-*-hpux* *-*-mingw* *-*-aix* } || { uclibc || newlib } } } }
-
 #include <math.h>
 
 void fpclassify() { }
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/60401.cc b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/60401.cc
new file mode 100644
index 0000000..f0cff33
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/60401.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// PR libstdc++/60401
+
+#include <stdlib.h>
+
+constexpr bool is_long(long) { return true; }
+template<typename T> constexpr bool is_long(T) { return false; }
+using type = decltype(::abs(1L));
+static_assert(is_long(type{}), "::abs(long) overload exists in <stdlib.h>");