This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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++/69893 make <tr1/cmath> work with C++11


The <tr1/cmath> header was implicitly relying on the fact that the
additional overloads defined by C++11 were not added to the global
namespace, so that it could do "using ::acosh;" to get the C library's
acosh(double) declaration only, and not the C++11 overloads.

With the new <math.h> in GCC 6 that no longer works, because including
<math.h> before <tr1/cmath> means that "using ::acosh;" adds all the
C++11 overloads to namespace std::tr1, and then adding new overloads
with the same signatures is an error. (The same error can be triggered
in earlier versions of GCC with an explicit "using std::acosh;" at
global scope before including <tr1/cmath>).

The solution is to use the C++11 functions when possible, via "using
std::acosh;", and not add anything extra to namespace std::tr1. For
C++03 the additional overloads aren't in namespace std, so we continue
to define them explicitly in namespace std::tr1.

The new <math.h> also breaks the special handling for tr1::fabs,
because "using ::fabs;" might now bring in the unwanted std::fabs
overload for std::complex<>. The solution is similar to what is
already done for tr1::pow. I reworded the comment for tr1::pow,
because the problem being solved wasn't very clear to me at first
(even though I was already dealing with the same issue for fabs!)

Tested x86_64-linux, committed to trunk.

commit e8c6279426372f6b4469ee09e61d8c95422d3aa7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Feb 22 23:52:26 2016 +0000

    libstdc++/69893 make <tr1/cmath> work with C++11
    
    	PR libstdc++/69893
    	* include/tr1/cmath (acosh, asinh, atanh, cbrt, copysign, erf, erfc,
    	exp2, expm1, fdim, fma, fmax, fmin, hypot, ilogb, lgamma, llrint,
    	llround, log1p, log2, logb, lrint, lround, nan, nearbyint, nextafter,
    	nexttoward, remainder, remquo, rint, round, scalbln, scalbn, tgamma,
    	trunc) [__cplusplus >= 201103L]: Import from namespace std.
    	(fabs) [__cplusplus < 201103L]: Import from namespace std.
    	* include/tr1/complex (acosh, asinh, atanh) [__cplusplus >= 201103L]:
    	Likewise.
    	* testsuite/tr1/headers/c++200x/complex.cc: Add std::fabs to global
    	namespace before including TR1 headers.
    	* testsuite/tr1/headers/c++200x/math.cc: New test.

diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index 14737e3..48466a0 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -151,6 +151,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if _GLIBCXX_USE_C99_MATH_TR1
 
+  // Using declarations to bring names from libc's <math.h> into std::tr1.
+
   // types
   using ::double_t;
   using ::float_t;
@@ -416,8 +418,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if _GLIBCXX_USE_C99_MATH_TR1
 
-  /// Additional overloads [8.16.4].
+  /** Additional overloads [8.16.4].
+   *  @{
+   */
+
+  // For functions defined in C++03 the additional overloads are already
+  // declared in <cmath> so we can just re-declare them in std::tr1.
+
   using std::acos;
+  using std::asin;
+  using std::atan;
+  using std::atan2;
+  using std::ceil;
+  using std::cos;
+  using std::cosh;
+  using std::exp;
+  using std::floor;
+  using std::fmod;
+  using std::frexp;
+  using std::ldexp;
+  using std::log;
+  using std::log10;
+  using std::sin;
+  using std::sinh;
+  using std::sqrt;
+  using std::tan;
+  using std::tanh;
+
+#if __cplusplus >= 201103L
+
+  // Since C++11, <cmath> defines additional overloads for these functions
+  // in namespace std.
+
+  using std::acosh;
+  using std::asinh;
+  using std::atanh;
+  using std::cbrt;
+  using std::copysign;
+  using std::erf;
+  using std::erfc;
+  using std::exp2;
+  using std::expm1;
+  using std::fdim;
+  using std::fma;
+  using std::fmax;
+  using std::fmin;
+  using std::hypot;
+  using std::ilogb;
+  using std::lgamma;
+  using std::llrint;
+  using std::llround;
+  using std::log1p;
+  using std::log2;
+  using std::logb;
+  using std::lrint;
+  using std::lround;
+  using std::nan;
+  using std::nearbyint;
+  using std::nextafter;
+  using std::nexttoward;
+  using std::remainder;
+  using std::remquo;
+  using std::rint;
+  using std::round;
+  using std::scalbln;
+  using std::scalbn;
+  using std::tgamma;
+  using std::trunc;
+
+#else // __cplusplus < 201103L
+
+  // In C++03 we need to provide the additional overloads.
 
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
@@ -435,8 +506,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     acosh(_Tp __x)
     { return __builtin_acosh(__x); }
 
-  using std::asin;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   asinh(float __x)
@@ -453,9 +522,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     asinh(_Tp __x)
     { return __builtin_asinh(__x); }
 
-  using std::atan;
-  using std::atan2;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   atanh(float __x)
@@ -488,8 +554,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     cbrt(_Tp __x)
     { return __builtin_cbrt(__x); }
 
-  using std::ceil;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   copysign(float __x, float __y)
@@ -508,9 +572,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return copysign(__type(__x), __type(__y));
     }
 
-  using std::cos;
-  using std::cosh;  
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   erf(float __x)
@@ -543,8 +604,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     erfc(_Tp __x)
     { return __builtin_erfc(__x); }
 
-  using std::exp;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   exp2(float __x)
@@ -577,32 +636,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     expm1(_Tp __x)
     { return __builtin_expm1(__x); }
 
-  // Note: we deal with fabs in a special way, because an using std::fabs
-  // would bring in also the overloads for complex types, which in C++0x
-  // mode have a different return type.
-  // With __CORRECT_ISO_CPP_MATH_H_PROTO, math.h imports std::fabs in the
-  // global namespace after the declarations of the float / double / long
-  // double overloads but before the std::complex overloads.
-  using ::fabs;
-
-#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
-#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
-  inline float
-  fabs(float __x)
-  { return __builtin_fabsf(__x); }
-
-  inline long double
-  fabs(long double __x)
-  { return __builtin_fabsl(__x); }
-#endif
-
-  template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, 
-					   double>::__type
-    fabs(_Tp __x)
-    { return __builtin_fabs(__x); }
-#endif
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   fdim(float __x, float __y)
@@ -621,8 +654,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return fdim(__type(__x), __type(__y));
     }
 
-  using std::floor;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   fma(float __x, float __y, float __z)
@@ -677,9 +708,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return fmin(__type(__x), __type(__y));
     }
 
-  using std::fmod;
-  using std::frexp;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   hypot(float __x, float __y)
@@ -714,8 +742,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     ilogb(_Tp __x)
     { return __builtin_ilogb(__x); }
 
-  using std::ldexp;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   lgamma(float __x)
@@ -764,9 +790,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     llround(_Tp __x)
     { return __builtin_llround(__x); }
 
-  using std::log;
-  using std::log10;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   log1p(float __x)
@@ -1000,12 +1023,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     scalbn(_Tp __x, int __ex)
     { return __builtin_scalbn(__x, __ex); }
 
-  using std::sin;
-  using std::sinh;
-  using std::sqrt;
-  using std::tan;
-  using std::tanh;
-
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
   inline float
   tgamma(float __x)
@@ -1038,6 +1055,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     trunc(_Tp __x)
     { return __builtin_trunc(__x); }
 
+#endif // __cplusplus < 201103L
+
+  // @}
+
 #endif
 _GLIBCXX_END_NAMESPACE_VERSION
 }
@@ -1050,17 +1071,16 @@ namespace tr1
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // DR 550. What should the return type of pow(float,int) be?
-  // NB: C++0x and TR1 != C++03.
+  // NB: C++11 and TR1 != C++03.
 
-  // The std::tr1::pow(double, double) overload cannot be provided
-  // here, because it would clash with ::pow(double,double) declared
-  // in <math.h>, if <tr1/math.h> is included at the same time (raised
-  // by the fix of PR c++/54537). It is not possible either to use the
-  // using-declaration 'using ::pow;' here, because if the user code
-  // has a 'using std::pow;', it would bring the pow(*,int) averloads
-  // in the tr1 namespace, which is undesirable. Consequently, the
-  // solution is to forward std::tr1::pow(double,double) to
-  // std::pow(double,double) via the templatized version below. See
+  // We cannot do "using std::pow;" because that would bring in unwanted
+  // pow(*, int) overloads in C++03, with the wrong return type. Instead we
+  // define all the necessary overloads, but the std::tr1::pow(double, double)
+  // overload cannot be provided here, because <tr1/math.h> would add it to
+  // the global namespace where it would clash with ::pow(double,double) from
+  // libc (revealed by the fix of PR c++/54537).
+  // The solution is to forward std::tr1::pow(double,double) to
+  // std::pow(double,double) via the function template below. See
   // the discussion about this issue here:
   // http://gcc.gnu.org/ml/gcc-patches/2012-09/msg01278.html
 
@@ -1082,6 +1102,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return std::pow(__type(__x), __type(__y));
     }
 
+#if __cplusplus >= 201103L
+  // We also deal with fabs in a special way, because "using std::fabs;"
+  // could bring in C++11's std::fabs<T>(const std::complex<T>&) with a
+  // different return type from std::tr1::fabs<T>(const std::complex<T>&).
+  // We define the necessary overloads, except std::tr1::fabs(double) which
+  // could clash with ::fabs(double) from libc.
+  // The function template handles double as well as integers, forwarding
+  // to std::fabs.
+
+#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO
+#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
+  inline float
+  fabs(float __x)
+  { return __builtin_fabsf(__x); }
+
+  inline long double
+  fabs(long double __x)
+  { return __builtin_fabsl(__x); }
+#endif
+#endif
+
+  template<typename _Tp>
+    inline typename __gnu_cxx::__promote<_Tp>::__type
+    fabs(_Tp __x)
+    { return std::fabs(__x); }
+
+#else  // ! C++11
+
+  // For C++03 just use std::fabs as there is no overload for std::complex<>.
+  using std::fabs;
+
+#endif // C++11
+
+
+
 _GLIBCXX_END_NAMESPACE_VERSION
 }
 }
diff --git a/libstdc++-v3/include/tr1/complex b/libstdc++-v3/include/tr1/complex
index 281bce0..9d2de1a 100644
--- a/libstdc++-v3/include/tr1/complex
+++ b/libstdc++-v3/include/tr1/complex
@@ -48,17 +48,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using std::acos;
   using std::asin;
   using std::atan;
+  using std::acosh;
+  using std::asinh;
+  using std::atanh;
 #else
   template<typename _Tp> std::complex<_Tp> acos(const std::complex<_Tp>&);
   template<typename _Tp> std::complex<_Tp> asin(const std::complex<_Tp>&);
   template<typename _Tp> std::complex<_Tp> atan(const std::complex<_Tp>&);
-#endif
-
   template<typename _Tp> std::complex<_Tp> acosh(const std::complex<_Tp>&);
   template<typename _Tp> std::complex<_Tp> asinh(const std::complex<_Tp>&);
   template<typename _Tp> std::complex<_Tp> atanh(const std::complex<_Tp>&);
+#endif
 
-  // The std::fabs return type in C++0x mode is different (just _Tp).
+  // The std::fabs return type in C++11 mode is different (just _Tp).
   template<typename _Tp> std::complex<_Tp> fabs(const std::complex<_Tp>&);
 
 #if __cplusplus < 201103L
@@ -178,8 +180,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __complex_atan(__z); }
 #endif
 
-#endif // C++11
-
   template<typename _Tp>
     std::complex<_Tp>
     __complex_acosh(const std::complex<_Tp>& __z)
@@ -299,6 +299,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __complex_atanh(__z); }
 #endif
 
+#endif // C++11
+
   template<typename _Tp>
     inline std::complex<_Tp>
     /// fabs(__z) [8.1.8].
diff --git a/libstdc++-v3/testsuite/tr1/headers/c++200x/complex.cc b/libstdc++-v3/testsuite/tr1/headers/c++200x/complex.cc
index 4c442bb..dbf01f5 100644
--- a/libstdc++-v3/testsuite/tr1/headers/c++200x/complex.cc
+++ b/libstdc++-v3/testsuite/tr1/headers/c++200x/complex.cc
@@ -21,6 +21,8 @@
 // check for duplicates of complex overloads of acos, asin, atan and fabs
 
 #include <complex>
+using std::fabs;
 #include <tr1/cmath>
 #include <tr1/complex>
 
+auto c = std::tr1::fabs(std::complex<double>{});
diff --git a/libstdc++-v3/testsuite/tr1/headers/c++200x/math.cc b/libstdc++-v3/testsuite/tr1/headers/c++200x/math.cc
new file mode 100644
index 0000000..29b89a4
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr1/headers/c++200x/math.cc
@@ -0,0 +1,25 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// 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/>.
+
+// PR libstdc++/69893
+// check for duplicate overloads of acosh, asinh, etc.
+
+#include <math.h>
+#include <tr1/cmath>

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