From c85e54ac6cef0faed7b7ffc722f52523dec59bf5 Mon Sep 17 00:00:00 2001 From: "Gabriel F. T. Gomes" Date: Fri, 3 Nov 2017 10:44:36 -0200 Subject: 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. --- math/math.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'math/math.h') 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 struct __iseqsig_type; + +template<> struct __iseqsig_type +{ + static int __call (float __x, float __y) throw () + { + return __iseqsigf (__x, __y); + } +}; + +template<> struct __iseqsig_type +{ + static int __call (double __x, double __y) throw () + { + return __iseqsig (__x, __y); + } +}; + +template<> struct __iseqsig_type +{ + 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 +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 -- cgit v1.2.3