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 <jwak...@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>");
commit f4bd35b818f0acbbb879fd7ca9aa6bd7ec955b5c Author: Jonathan Wakely <jwak...@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; }