[PATCH v3] Provide a C++ version of iseqsig

Florian Weimer fweimer@redhat.com
Tue Nov 14 13:35:00 GMT 2017


On 11/14/2017 02:21 PM, Gabriel F. T. Gomes wrote:

> diff --git a/math/math.h b/math/math.h
> index 326fd8ebe1..acc909d37f 100644
> --- a/math/math.h
> +++ b/math/math.h
> @@ -1152,8 +1152,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.  */

> +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 */

Would these two expressions have the same types, assuming _T1 and _T2 
are the template parameters from the iseqsig definition?

   __MATH_EVAL_FMT2 (__x, __y)
   __MATH_EVAL_FMT2 (_T1 (), _T2 ())

I believe the second expression would be safe to evaluate, so it could 
be used to select a suitable inline function.  This would then work with 
any C++ version.

But the current approach is okay as well.

> diff --git a/math/test-math-iseqsig.cc b/math/test-math-iseqsig.cc
> new file mode 100644
> index 0000000000..0316340638
> --- /dev/null
> +++ b/math/test-math-iseqsig.cc

> +static bool errors;

Maybe use support_record_failure from <support/check.h> instead?

> +static void
> +check (int actual, int expected, const char *actual_expr, int line)
> +{
> +  if (actual != expected)
> +    {
> +      errors = true;
> +      printf ("%s:%d: error: %s\n", __FILE__, line, actual_expr);
> +      printf ("%s:%d:   expected: %d\n", __FILE__, line, expected);
> +      printf ("%s:%d:   actual: %d\n", __FILE__, line, actual);
> +    }
> +}
> +
> +#define CHECK(actual, expected) \
> +  check ((actual), (expected), #actual, __LINE__)

I think my memory protection key patches contain a more general 
implementation of this called TEST_COMPARE.  Adhemerval requested just a 
minor documentation change, so I could commit that separately if you 
want to use it.

Thanks,
Florian



More information about the Libc-alpha mailing list