about summary refs log tree commit diff
path: root/math/math.h
diff options
context:
space:
mode:
authorGabriel F. T. Gomes <gabriel@inconstante.eti.br>2017-11-03 10:44:36 -0200
committerGabriel F. T. Gomes <gabriel@inconstante.eti.br>2017-12-19 23:26:59 -0200
commitc85e54ac6cef0faed7b7ffc722f52523dec59bf5 (patch)
tree594a7a95e759e7035ee80ea0dee46b09f917f9aa /math/math.h
parent10e93d968716ab82931d593bada121c17c0a4b93 (diff)
downloadglibc-c85e54ac6cef0faed7b7ffc722f52523dec59bf5.tar.gz
glibc-c85e54ac6cef0faed7b7ffc722f52523dec59bf5.tar.xz
glibc-c85e54ac6cef0faed7b7ffc722f52523dec59bf5.zip
Provide a C++ version of iseqsig (bug 22377)
In C++ mode, __MATH_TG cannot be used for defining iseqsig, because
__MATH_TG relies on __builtin_types_compatible_p, which is a C-only
builtin.  This is true when float128 is provided as an ABI-distinct type
from long double.

Moreover, the comparison macros from ISO C take two floating-point
arguments, which need not have the same type.  Choosing what underlying
function to call requires evaluating the formats of the arguments, then
selecting which is wider.  The macro __MATH_EVAL_FMT2 provides this
information, however, only the type of the macro expansion is relevant
(actually evaluating the expression would be incorrect).

This patch provides a C++ version of iseqsig, in which only the type of
__MATH_EVAL_FMT2 (__typeof or decltype) is used as a template parameter
for __iseqsig_type.  This function calls the appropriate underlying
function.

Tested for powerpc64le and x86_64.

	[BZ #22377]
	* math/Makefile [C++] (tests): Add test for iseqsig.
	* math/math.h [C++] (iseqsig): New implementation, which does
	not rely on __MATH_TG/__builtin_types_compatible_p.
	* math/test-math-iseqsig.cc: New file.
	* sysdeps/powerpc/powerpc64le/Makefile
	(CFLAGS-test-math-iseqsig.cc): New variable.
Diffstat (limited to 'math/math.h')
-rw-r--r--math/math.h72
1 files changed, 70 insertions, 2 deletions
diff --git a/math/math.h b/math/math.h
index f6d1feed78..72d7dc5939 100644
--- a/math/math.h
+++ b/math/math.h
@@ -1182,8 +1182,76 @@ iszero (__T __val)
 
 /* Return X == Y but raising "invalid" and setting errno if X or Y is
    a NaN.  */
-# define iseqsig(x, y) \
-  __MATH_TG (__MATH_EVAL_FMT2 (x, y), __iseqsig, ((x), (y)))
+# if !defined __cplusplus || (__cplusplus < 201103L && !defined __GNUC__)
+#  define iseqsig(x, y) \
+   __MATH_TG (__MATH_EVAL_FMT2 (x, y), __iseqsig, ((x), (y)))
+# else
+/* In C++ mode, __MATH_TG cannot be used, because it relies on
+   __builtin_types_compatible_p, which is a C-only builtin.  Moreover,
+   the comparison macros from ISO C take two floating-point arguments,
+   which need not have the same type.  Choosing what underlying function
+   to call requires evaluating the formats of the arguments, then
+   selecting which is wider.  The macro __MATH_EVAL_FMT2 provides this
+   information, however, only the type of the macro expansion is
+   relevant (actually evaluating the expression would be incorrect).
+   Thus, the type is used as a template parameter for __iseqsig_type,
+   which calls the appropriate underlying function.  */
+extern "C++" {
+template<typename> struct __iseqsig_type;
+
+template<> struct __iseqsig_type<float>
+{
+  static int __call (float __x, float __y) throw ()
+  {
+    return __iseqsigf (__x, __y);
+  }
+};
+
+template<> struct __iseqsig_type<double>
+{
+  static int __call (double __x, double __y) throw ()
+  {
+    return __iseqsig (__x, __y);
+  }
+};
+
+template<> struct __iseqsig_type<long double>
+{
+  static int __call (double __x, double __y) throw ()
+  {
+#  ifndef __NO_LONG_DOUBLE_MATH
+    return __iseqsigl (__x, __y);
+#  else
+    return __iseqsig (__x, __y);
+#  endif
+  }
+};
+
+#  if __HAVE_DISTINCT_FLOAT128
+template<> struct __iseqsig_type<_Float128>
+{
+  static int __call (_Float128 __x, _Float128 __y) throw ()
+  {
+    return __iseqsigf128 (__x, __y);
+  }
+};
+#  endif
+
+template<typename _T1, typename _T2>
+inline int
+iseqsig (_T1 __x, _T2 __y) throw ()
+{
+#  if __cplusplus >= 201103L
+  typedef decltype (__MATH_EVAL_FMT2 (__x, __y)) _T3;
+#  else
+  typedef __typeof (__MATH_EVAL_FMT2 (__x, __y)) _T3;
+#  endif
+  return __iseqsig_type<_T3>::__call (__x, __y);
+}
+
+} /* extern "C++" */
+# endif /* __cplusplus */
+
 #endif
 
 __END_DECLS