This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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 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>");

Attachment: lwg2294.txt
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]