aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-common.c1
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/c/ChangeLog7
-rw-r--r--gcc/c/c-parser.c564
-rw-r--r--gcc/doc/extend.texi57
-rw-r--r--gcc/ginclude/tgmath.h82
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/builtin-tgmath-1.c322
-rw-r--r--gcc/testsuite/gcc.dg/builtin-tgmath-2.c51
-rw-r--r--gcc/testsuite/gcc.dg/builtin-tgmath-err-1.c76
-rw-r--r--gcc/testsuite/gcc.dg/builtin-tgmath-err-2.c19
-rw-r--r--gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp-err.c33
-rw-r--r--gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp.c263
15 files changed, 1441 insertions, 63 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 288e163..22431e5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2017-11-15 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/81156
+ * doc/extend.texi (Other Builtins): Document __builtin_tgmath.
+ * ginclude/tgmath.h (__tg_cplx, __tg_ldbl, __tg_dbl, __tg_choose)
+ (__tg_choose_2, __tg_choose_3, __TGMATH_REAL_1_2)
+ (__TGMATH_REAL_2_3): Remove macros.
+ (__TGMATH_CPLX, __TGMATH_CPLX_2, __TGMATH_REAL, __TGMATH_REAL_2)
+ (__TGMATH_REAL_3, __TGMATH_CPLX_ONLY): Define using
+ __builtin_tgmath.
+ (frexp, ldexp, nexttoward, scalbn, scalbln): Define using
+ __TGMATH_REAL_2.
+ (remquo): Define using __TGMATH_REAL_3.
+
2017-11-14 Jeff Law <law@redhat.com>
* vr-values.c: New file with contents extracted from tree-vrp.c.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 7e47cb8..3127635 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2017-11-15 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/81156
+ * c-common.c (c_common_reswords): Add __builtin_tgmath.
+ * c-common.h (enum rid): Add RID_BUILTIN_TGMATH.
+
2017-11-10 Martin Sebor <msebor@redhat.com>
PR c/81117
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index a76fae7..65d37c6 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -376,6 +376,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
{ "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
{ "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
+ { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
{ "__builtin_offsetof", RID_OFFSETOF, 0 },
{ "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
{ "__builtin_va_arg", RID_VA_ARG, 0 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 7e1877e..5bb8619 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -101,6 +101,7 @@ enum rid
RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
+ RID_BUILTIN_TGMATH,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
/* TS 18661-3 keywords, in the same sequence as the TI_* values. */
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 60feeea..5622c8a 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-15 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/81156
+ * c-parser.c (check_tgmath_function): New function.
+ (enum tgmath_parm_kind): New enum.
+ (c_parser_postfix_expression): Handle __builtin_tgmath.
+
2017-10-31 David Malcolm <dmalcolm@redhat.com>
* c-decl.c (implicit_decl_warning): Update for renaming of
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 7bca5f1..3d90e28 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -7829,6 +7829,61 @@ c_parser_generic_selection (c_parser *parser)
return matched_assoc.expression;
}
+/* Check the validity of a function pointer argument *EXPR (argument
+ position POS) to __builtin_tgmath. Return the number of function
+ arguments if possibly valid; return 0 having reported an error if
+ not valid. */
+
+static unsigned int
+check_tgmath_function (c_expr *expr, unsigned int pos)
+{
+ tree type = TREE_TYPE (expr->value);
+ if (!FUNCTION_POINTER_TYPE_P (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> is not a function pointer",
+ pos);
+ return 0;
+ }
+ type = TREE_TYPE (type);
+ if (!prototype_p (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> is unprototyped", pos);
+ return 0;
+ }
+ if (stdarg_p (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> has variable arguments",
+ pos);
+ return 0;
+ }
+ unsigned int nargs = 0;
+ function_args_iterator iter;
+ tree t;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ nargs++;
+ }
+ if (nargs == 0)
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> has no arguments", pos);
+ return 0;
+ }
+ return nargs;
+}
+
+/* Ways in which a parameter or return value of a type-generic macro
+ may vary between the different functions the macro may call. */
+enum tgmath_parm_kind
+ {
+ tgmath_fixed, tgmath_real, tgmath_complex
+ };
+
/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2,
C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to
call c_parser_postfix_expression_after_paren_type on encountering them.
@@ -7869,6 +7924,7 @@ c_parser_generic_selection (c_parser *parser)
assignment-expression ,
assignment-expression )
__builtin_types_compatible_p ( type-name , type-name )
+ __builtin_tgmath ( expr-list )
__builtin_complex ( assignment-expression , assignment-expression )
__builtin_shuffle ( assignment-expression , assignment-expression )
__builtin_shuffle ( assignment-expression ,
@@ -8295,6 +8351,513 @@ c_parser_postfix_expression (c_parser *parser)
set_c_expr_source_range (&expr, loc, close_paren_loc);
}
break;
+ case RID_BUILTIN_TGMATH:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_tgmath",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) < 3)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+
+ unsigned int i;
+ c_expr_t *p;
+ FOR_EACH_VEC_ELT (*cexpr_list, i, p)
+ *p = convert_lvalue_to_rvalue (loc, *p, true, true);
+ unsigned int nargs = check_tgmath_function (&(*cexpr_list)[0], 1);
+ if (nargs == 0)
+ {
+ expr.set_error ();
+ break;
+ }
+ if (vec_safe_length (cexpr_list) < nargs)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+ unsigned int num_functions = vec_safe_length (cexpr_list) - nargs;
+ if (num_functions < 2)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+
+ /* The first NUM_FUNCTIONS expressions are the function
+ pointers. The remaining NARGS expressions are the
+ arguments that are to be passed to one of those
+ functions, chosen following <tgmath.h> rules. */
+ for (unsigned int j = 1; j < num_functions; j++)
+ {
+ unsigned int this_nargs
+ = check_tgmath_function (&(*cexpr_list)[j], j + 1);
+ if (this_nargs == 0)
+ {
+ expr.set_error ();
+ goto out;
+ }
+ if (this_nargs != nargs)
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "argument %u of %<__builtin_tgmath%> has "
+ "wrong number of arguments", j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+
+ /* The functions all have the same number of arguments.
+ Determine whether arguments and return types vary in
+ ways permitted for <tgmath.h> functions. */
+ /* The first entry in each of these vectors is for the
+ return type, subsequent entries for parameter
+ types. */
+ auto_vec<enum tgmath_parm_kind> parm_kind (nargs + 1);
+ auto_vec<tree> parm_first (nargs + 1);
+ auto_vec<bool> parm_complex (nargs + 1);
+ auto_vec<bool> parm_varies (nargs + 1);
+ tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value));
+ tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type));
+ parm_first.quick_push (first_ret);
+ parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE);
+ parm_varies.quick_push (false);
+ function_args_iterator iter;
+ tree t;
+ unsigned int argpos;
+ FOREACH_FUNCTION_ARGS (first_type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ parm_first.quick_push (TYPE_MAIN_VARIANT (t));
+ parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE);
+ parm_varies.quick_push (false);
+ }
+ for (unsigned int j = 1; j < num_functions; j++)
+ {
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ if (ret != parm_first[0])
+ {
+ parm_varies[0] = true;
+ if (!SCALAR_FLOAT_TYPE_P (parm_first[0])
+ && !COMPLEX_FLOAT_TYPE_P (parm_first[0]))
+ {
+ error_at ((*cexpr_list)[0].get_location (),
+ "invalid type-generic return type for "
+ "argument %u of %<__builtin_tgmath%>",
+ 1);
+ expr.set_error ();
+ goto out;
+ }
+ if (!SCALAR_FLOAT_TYPE_P (ret)
+ && !COMPLEX_FLOAT_TYPE_P (ret))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "invalid type-generic return type for "
+ "argument %u of %<__builtin_tgmath%>",
+ j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+ if (TREE_CODE (ret) == COMPLEX_TYPE)
+ parm_complex[0] = true;
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ t = TYPE_MAIN_VARIANT (t);
+ if (t != parm_first[argpos])
+ {
+ parm_varies[argpos] = true;
+ if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos])
+ && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos]))
+ {
+ error_at ((*cexpr_list)[0].get_location (),
+ "invalid type-generic type for "
+ "argument %u of argument %u of "
+ "%<__builtin_tgmath%>", argpos, 1);
+ expr.set_error ();
+ goto out;
+ }
+ if (!SCALAR_FLOAT_TYPE_P (t)
+ && !COMPLEX_FLOAT_TYPE_P (t))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "invalid type-generic type for "
+ "argument %u of argument %u of "
+ "%<__builtin_tgmath%>", argpos, j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+ if (TREE_CODE (t) == COMPLEX_TYPE)
+ parm_complex[argpos] = true;
+ argpos++;
+ }
+ }
+ enum tgmath_parm_kind max_variation = tgmath_fixed;
+ for (unsigned int j = 0; j <= nargs; j++)
+ {
+ enum tgmath_parm_kind this_kind;
+ if (parm_varies[j])
+ {
+ if (parm_complex[j])
+ max_variation = this_kind = tgmath_complex;
+ else
+ {
+ this_kind = tgmath_real;
+ if (max_variation != tgmath_complex)
+ max_variation = tgmath_real;
+ }
+ }
+ else
+ this_kind = tgmath_fixed;
+ parm_kind.quick_push (this_kind);
+ }
+ if (max_variation == tgmath_fixed)
+ {
+ error_at (loc, "function arguments of %<__builtin_tgmath%> "
+ "all have the same type");
+ expr.set_error ();
+ break;
+ }
+
+ /* Identify a parameter (not the return type) that varies,
+ including with complex types if any variation includes
+ complex types; there must be at least one such
+ parameter. */
+ unsigned int tgarg = 0;
+ for (unsigned int j = 1; j <= nargs; j++)
+ if (parm_kind[j] == max_variation)
+ {
+ tgarg = j;
+ break;
+ }
+ if (tgarg == 0)
+ {
+ error_at (loc, "function arguments of %<__builtin_tgmath%> "
+ "lack type-generic parameter");
+ expr.set_error ();
+ break;
+ }
+
+ /* Determine the type of the relevant parameter for each
+ function. */
+ auto_vec<tree> tg_type (num_functions);
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (argpos == tgarg)
+ {
+ tg_type.quick_push (TYPE_MAIN_VARIANT (t));
+ break;
+ }
+ argpos++;
+ }
+ }
+
+ /* Verify that the corresponding types are different for
+ all the listed functions. Also determine whether all
+ the types are complex, whether all the types are
+ standard or binary, and whether all the types are
+ decimal. */
+ bool all_complex = true;
+ bool all_binary = true;
+ bool all_decimal = true;
+ hash_set<tree> tg_types;
+ FOR_EACH_VEC_ELT (tg_type, i, t)
+ {
+ if (TREE_CODE (t) == COMPLEX_TYPE)
+ all_decimal = false;
+ else
+ {
+ all_complex = false;
+ if (DECIMAL_FLOAT_TYPE_P (t))
+ all_binary = false;
+ else
+ all_decimal = false;
+ }
+ if (tg_types.add (t))
+ {
+ error_at ((*cexpr_list)[i].get_location (),
+ "duplicate type-generic parameter type for "
+ "function argument %u of %<__builtin_tgmath%>",
+ i + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+
+ /* Verify that other parameters and the return type whose
+ types vary have their types varying in the correct
+ way. */
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ tree exp_type = tg_type[j];
+ tree exp_real_type = exp_type;
+ if (TREE_CODE (exp_type) == COMPLEX_TYPE)
+ exp_real_type = TREE_TYPE (exp_type);
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ if ((parm_kind[0] == tgmath_complex && ret != exp_type)
+ || (parm_kind[0] == tgmath_real && ret != exp_real_type))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "bad return type for function argument %u "
+ "of %<__builtin_tgmath%>", j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ t = TYPE_MAIN_VARIANT (t);
+ if ((parm_kind[argpos] == tgmath_complex
+ && t != exp_type)
+ || (parm_kind[argpos] == tgmath_real
+ && t != exp_real_type))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "bad type for argument %u of "
+ "function argument %u of "
+ "%<__builtin_tgmath%>", argpos, j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ argpos++;
+ }
+ }
+
+ /* The functions listed are a valid set of functions for a
+ <tgmath.h> macro to select between. Identify the
+ matching function, if any. First, the argument types
+ must be combined following <tgmath.h> rules. Integer
+ types are treated as _Decimal64 if any type-generic
+ argument is decimal, or if the only alternatives for
+ type-generic arguments are of decimal types, and are
+ otherwise treated as double (or _Complex double for
+ complex integer types). After that adjustment, types
+ are combined following the usual arithmetic
+ conversions. If the function only accepts complex
+ arguments, a complex type is produced. */
+ bool arg_complex = all_complex;
+ bool arg_binary = all_binary;
+ bool arg_int_decimal = all_decimal;
+ for (unsigned int j = 1; j <= nargs; j++)
+ {
+ if (parm_kind[j] == tgmath_fixed)
+ continue;
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1];
+ tree type = TREE_TYPE (ce->value);
+ if (!INTEGRAL_TYPE_P (type)
+ && !SCALAR_FLOAT_TYPE_P (type)
+ && TREE_CODE (type) != COMPLEX_TYPE)
+ {
+ error_at (ce->get_location (),
+ "invalid type of argument %u of type-generic "
+ "function", j);
+ expr.set_error ();
+ goto out;
+ }
+ if (DECIMAL_FLOAT_TYPE_P (type))
+ {
+ arg_int_decimal = true;
+ if (all_complex)
+ {
+ error_at (ce->get_location (),
+ "decimal floating-point argument %u to "
+ "complex-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (all_binary)
+ {
+ error_at (ce->get_location (),
+ "decimal floating-point argument %u to "
+ "binary-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_complex)
+ {
+ error_at (ce->get_location (),
+ "both complex and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_binary)
+ {
+ error_at (ce->get_location (),
+ "both binary and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ arg_complex = true;
+ if (COMPLEX_FLOAT_TYPE_P (type))
+ arg_binary = true;
+ if (all_decimal)
+ {
+ error_at (ce->get_location (),
+ "complex argument %u to "
+ "decimal-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_int_decimal)
+ {
+ error_at (ce->get_location (),
+ "both complex and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ arg_binary = true;
+ if (all_decimal)
+ {
+ error_at (ce->get_location (),
+ "binary argument %u to "
+ "decimal-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_int_decimal)
+ {
+ error_at (ce->get_location (),
+ "both binary and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ }
+ tree arg_real = NULL_TREE;
+ for (unsigned int j = 1; j <= nargs; j++)
+ {
+ if (parm_kind[j] == tgmath_fixed)
+ continue;
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1];
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value));
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ type = TREE_TYPE (type);
+ if (INTEGRAL_TYPE_P (type))
+ type = (arg_int_decimal
+ ? dfloat64_type_node
+ : double_type_node);
+ if (arg_real == NULL_TREE)
+ arg_real = type;
+ else
+ arg_real = common_type (arg_real, type);
+ if (arg_real == error_mark_node)
+ {
+ expr.set_error ();
+ goto out;
+ }
+ }
+ tree arg_type = (arg_complex
+ ? build_complex_type (arg_real)
+ : arg_real);
+
+ /* Look for a function to call with type-generic parameter
+ type ARG_TYPE. */
+ c_expr_t *fn = NULL;
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ if (tg_type[j] == arg_type)
+ {
+ fn = &(*cexpr_list)[j];
+ break;
+ }
+ }
+ if (fn == NULL
+ && parm_kind[0] == tgmath_fixed
+ && SCALAR_FLOAT_TYPE_P (parm_first[0]))
+ {
+ /* Presume this is a macro that rounds its result to a
+ narrower type, and look for the first function with
+ at least the range and precision of the argument
+ type. */
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ if (arg_complex
+ != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE))
+ continue;
+ tree real_tg_type = (arg_complex
+ ? TREE_TYPE (tg_type[j])
+ : tg_type[j]);
+ if (DECIMAL_FLOAT_TYPE_P (arg_real)
+ != DECIMAL_FLOAT_TYPE_P (real_tg_type))
+ continue;
+ scalar_float_mode arg_mode
+ = SCALAR_FLOAT_TYPE_MODE (arg_real);
+ scalar_float_mode tg_mode
+ = SCALAR_FLOAT_TYPE_MODE (real_tg_type);
+ const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode);
+ const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode);
+ if (arg_fmt->b == tg_fmt->b
+ && arg_fmt->p <= tg_fmt->p
+ && arg_fmt->emax <= tg_fmt->emax
+ && (arg_fmt->emin - arg_fmt->p
+ >= tg_fmt->emin - tg_fmt->p))
+ {
+ fn = &(*cexpr_list)[j];
+ break;
+ }
+ }
+ }
+ if (fn == NULL)
+ {
+ error_at (loc, "no matching function for type-generic call");
+ expr.set_error ();
+ break;
+ }
+
+ /* Construct a call to FN. */
+ vec<tree, va_gc> *args;
+ vec_alloc (args, nargs);
+ vec<tree, va_gc> *origtypes;
+ vec_alloc (origtypes, nargs);
+ auto_vec<location_t> arg_loc (nargs);
+ for (unsigned int j = 0; j < nargs; j++)
+ {
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j];
+ args->quick_push (ce->value);
+ arg_loc.quick_push (ce->get_location ());
+ origtypes->quick_push (ce->original_type);
+ }
+ expr.value = c_build_function_call_vec (loc, arg_loc, fn->value,
+ args, origtypes);
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
case RID_BUILTIN_CALL_WITH_STATIC_CHAIN:
{
vec<c_expr_t, va_gc> *cexpr_list;
@@ -8563,6 +9126,7 @@ c_parser_postfix_expression (c_parser *parser)
expr.set_error ();
break;
}
+ out:
return c_parser_postfix_expression_after_primary
(parser, EXPR_LOC_OR_LOC (expr.value, loc), expr);
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index c6bdb86..711264c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11684,6 +11684,63 @@ future revisions.
@end deftypefn
+@deftypefn {Built-in Function} @var{type} __builtin_tgmath (@var{functions}, @var{arguments})
+
+The built-in function @code{__builtin_tgmath}, available only for C
+and Objective-C, calls a function determined according to the rules of
+@code{<tgmath.h>} macros. It is intended to be used in
+implementations of that header, so that expansions of macros from that
+header only expand each of their arguments once, to avoid problems
+when calls to such macros are nested inside the arguments of other
+calls to such macros; in addition, it results in better diagnostics
+for invalid calls to @code{<tgmath.h>} macros than implementations
+using other GNU C language features. For example, the @code{pow}
+type-generic macro might be defined as:
+
+@smallexample
+#define pow(a, b) __builtin_tgmath (powf, pow, powl, \
+ cpowf, cpow, cpowl, a, b)
+@end smallexample
+
+The arguments to @code{__builtin_tgmath} are at least two pointers to
+functions, followed by the arguments to the type-generic macro (which
+will be passed as arguments to the selected function). All the
+pointers to functions must be pointers to prototyped functions, none
+of which may have variable arguments, and all of which must have the
+same number of parameters; the number of parameters of the first
+function determines how many arguments to @code{__builtin_tgmath} are
+interpreted as function pointers, and how many as the arguments to the
+called function.
+
+The types of the specified functions must all be different, but
+related to each other in the same way as a set of functions that may
+be selected between by a macro in @code{<tgmath.h>}. This means that
+the functions are parameterized by a floating-point type @var{t},
+different for each such function. The function return types may all
+be the same type, or they may be @var{t} for each function, or they
+may be the real type corresponding to @var{t} for each function (if
+some of the types @var{t} are complex). Likewise, for each parameter
+position, the type of the parameter in that position may always be the
+same type, or may be @var{t} for each function (this case must apply
+for at least one parameter position), or may be the real type
+corresponding to @var{t} for each function.
+
+The standard rules for @code{<tgmath.h>} macros are used to find a
+common type @var{u} from the types of the arguments for parameters
+whose types vary between the functions; complex integer types (a GNU
+extension) are treated like @code{_Complex double} for this purpose.
+If the function return types vary, or are all the same integer type,
+the function called is the one for which @var{t} is @var{u}, and it is
+an error if there is no such function. If the function return types
+are all the same floating-point type, the type-generic macro is taken
+to be one of those from TS 18661 that rounds the result to a narrower
+type; if there is a function for which @var{t} is @var{u}, it is
+called, and otherwise the first function, if any, for which @var{t}
+has at least the range and precision of @var{u} is called, and it is
+an error if there is no such function.
+
+@end deftypefn
+
@deftypefn {Built-in Function} @var{type} __builtin_complex (@var{real}, @var{imag})
The built-in function @code{__builtin_complex} is provided for use in
diff --git a/gcc/ginclude/tgmath.h b/gcc/ginclude/tgmath.h
index be3f5be..97968ad 100644
--- a/gcc/ginclude/tgmath.h
+++ b/gcc/ginclude/tgmath.h
@@ -38,68 +38,24 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
__TGMATH_CPLX*, __TGMATH_REAL*, and __TGMATH_CPLX_ONLY. _CPLX
means the generic argument(s) may be real or complex, _REAL means
real only, _CPLX means complex only. If there is no suffix, we are
- defining a function of one generic argument. If the suffix is _n
- it is a function of n generic arguments. If the suffix is _m_n it
- is a function of n arguments, the first m of which are generic. We
- only define these macros for values of n and/or m that are needed. */
-
-/* The general rules for generic macros are given in 7.22 paragraphs 1 and 2.
- If any generic parameter is complex, we use a complex version. Otherwise
- we use a real version. If the real part of any generic parameter is long
- double, we use the long double version. Otherwise if the real part of any
- generic parameter is double or of integer type, we use the double version.
- Otherwise we use the float version. */
-
-#define __tg_cplx(expr) \
- __builtin_classify_type(expr) == 9
-
-#define __tg_ldbl(expr) \
- __builtin_types_compatible_p(__typeof__(expr), long double)
-
-#define __tg_dbl(expr) \
- (__builtin_types_compatible_p(__typeof__(expr), double) \
- || __builtin_classify_type(expr) == 1)
-
-#define __tg_choose(x,f,d,l) \
- __builtin_choose_expr(__tg_ldbl(x), l, \
- __builtin_choose_expr(__tg_dbl(x), d, \
- f))
-
-#define __tg_choose_2(x,y,f,d,l) \
- __builtin_choose_expr(__tg_ldbl(x) || __tg_ldbl(y), l, \
- __builtin_choose_expr(__tg_dbl(x) || __tg_dbl(y), d, \
- f))
-
-#define __tg_choose_3(x,y,z,f,d,l) \
- __builtin_choose_expr(__tg_ldbl(x) || __tg_ldbl(y) || __tg_ldbl(z), l, \
- __builtin_choose_expr(__tg_dbl(x) || __tg_dbl(y) \
- || __tg_dbl(z), d, \
- f))
-
-#define __TGMATH_CPLX(z,R,C) \
- __builtin_choose_expr (__tg_cplx(z), \
- __tg_choose (__real__(z), C##f(z), (C)(z), C##l(z)), \
- __tg_choose (z, R##f(z), (R)(z), R##l(z)))
-
-#define __TGMATH_CPLX_2(z1,z2,R,C) \
- __builtin_choose_expr (__tg_cplx(z1) || __tg_cplx(z2), \
- __tg_choose_2 (__real__(z1), __real__(z2), \
- C##f(z1,z2), (C)(z1,z2), C##l(z1,z2)), \
- __tg_choose_2 (z1, z2, \
- R##f(z1,z2), (R)(z1,z2), R##l(z1,z2)))
+ defining a function of one argument. If the suffix is _n
+ it is a function of n arguments. We only define these macros for
+ values of n that are needed. */
+
+#define __TGMATH_CPLX(z,R,C) \
+ __builtin_tgmath (R##f, R, R##l, C##f, C, C##l, (z))
+
+#define __TGMATH_CPLX_2(z1,z2,R,C) \
+ __builtin_tgmath (R##f, R, R##l, C##f, C, C##l, (z1), (z2))
#define __TGMATH_REAL(x,R) \
- __tg_choose (x, R##f(x), (R)(x), R##l(x))
+ __builtin_tgmath (R##f, R, R##l, (x))
#define __TGMATH_REAL_2(x,y,R) \
- __tg_choose_2 (x, y, R##f(x,y), (R)(x,y), R##l(x,y))
+ __builtin_tgmath (R##f, R, R##l, (x), (y))
#define __TGMATH_REAL_3(x,y,z,R) \
- __tg_choose_3 (x, y, z, R##f(x,y,z), (R)(x,y,z), R##l(x,y,z))
-#define __TGMATH_REAL_1_2(x,y,R) \
- __tg_choose (x, R##f(x,y), (R)(x,y), R##l(x,y))
-#define __TGMATH_REAL_2_3(x,y,z,R) \
- __tg_choose_2 (x, y, R##f(x,y,z), (R)(x,y,z), R##l(x,y,z))
+ __builtin_tgmath (R##f, R, R##l, (x), (y), (z))
#define __TGMATH_CPLX_ONLY(z,C) \
- __tg_choose (__real__(z), C##f(z), (C)(z), C##l(z))
+ __builtin_tgmath (C##f, C, C##l, (z))
/* Functions defined in both <math.h> and <complex.h> (7.22p4) */
#define acos(z) __TGMATH_CPLX(z, acos, cacos)
@@ -135,10 +91,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define fmax(x,y) __TGMATH_REAL_2(x, y, fmax)
#define fmin(x,y) __TGMATH_REAL_2(x, y, fmin)
#define fmod(x,y) __TGMATH_REAL_2(x, y, fmod)
-#define frexp(x,y) __TGMATH_REAL_1_2(x, y, frexp)
+#define frexp(x,y) __TGMATH_REAL_2(x, y, frexp)
#define hypot(x,y) __TGMATH_REAL_2(x, y, hypot)
#define ilogb(x) __TGMATH_REAL(x, ilogb)
-#define ldexp(x,y) __TGMATH_REAL_1_2(x, y, ldexp)
+#define ldexp(x,y) __TGMATH_REAL_2(x, y, ldexp)
#define lgamma(x) __TGMATH_REAL(x, lgamma)
#define llrint(x) __TGMATH_REAL(x, llrint)
#define llround(x) __TGMATH_REAL(x, llround)
@@ -150,13 +106,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define lround(x) __TGMATH_REAL(x, lround)
#define nearbyint(x) __TGMATH_REAL(x, nearbyint)
#define nextafter(x,y) __TGMATH_REAL_2(x, y, nextafter)
-#define nexttoward(x,y) __TGMATH_REAL_1_2(x, y, nexttoward)
+#define nexttoward(x,y) __TGMATH_REAL_2(x, y, nexttoward)
#define remainder(x,y) __TGMATH_REAL_2(x, y, remainder)
-#define remquo(x,y,z) __TGMATH_REAL_2_3(x, y, z, remquo)
+#define remquo(x,y,z) __TGMATH_REAL_3(x, y, z, remquo)
#define rint(x) __TGMATH_REAL(x, rint)
#define round(x) __TGMATH_REAL(x, round)
-#define scalbn(x,y) __TGMATH_REAL_1_2(x, y, scalbn)
-#define scalbln(x,y) __TGMATH_REAL_1_2(x, y, scalbln)
+#define scalbn(x,y) __TGMATH_REAL_2(x, y, scalbn)
+#define scalbln(x,y) __TGMATH_REAL_2(x, y, scalbln)
#define tgamma(x) __TGMATH_REAL(x, tgamma)
#define trunc(x) __TGMATH_REAL(x, trunc)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ec43496..1cd0070 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2017-11-15 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/81156
+ * gcc.dg/builtin-tgmath-1.c, gcc.dg/builtin-tgmath-2.c,
+ gcc.dg/builtin-tgmath-err-1.c, gcc.dg/builtin-tgmath-err-2.c,
+ gcc.dg/dfp/builtin-tgmath-dfp-err.c,
+ gcc.dg/dfp/builtin-tgmath-dfp.c: New tests.
+
2017-11-14 Michael Meissner <meissner@linux.vnet.ibm.com>
* gcc.target/powerpc/float128-hw4.c: New test.
diff --git a/gcc/testsuite/gcc.dg/builtin-tgmath-1.c b/gcc/testsuite/gcc.dg/builtin-tgmath-1.c
new file mode 100644
index 0000000..ff87ace
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-tgmath-1.c
@@ -0,0 +1,322 @@
+/* Test __builtin_tgmath: valid uses, standard floating-point types. */
+/* { dg-do run } */
+/* { dg-options "" } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CHECK_CALL(C, E, V) \
+ do \
+ { \
+ if ((C) != (E)) \
+ abort (); \
+ extern __typeof (C) V; \
+ } \
+ while (0)
+
+extern float var_f;
+extern double var_d;
+extern long double var_ld;
+extern _Complex float var_cf;
+extern _Complex double var_cd;
+extern _Complex long double var_cld;
+extern int var_i;
+
+typedef float float_type;
+typedef double double_type;
+
+/* Test simple case, real arguments and return type. */
+
+float_type t1f (float x) { return x + 1; }
+double t1d (double_type x) { return x + 2; }
+long double t1l (volatile long double x) { return x + 3; }
+
+#define t1v(x) __builtin_tgmath (t1f, t1d, t1l, x)
+#define t1vr(x) __builtin_tgmath (t1l, t1d, t1f, x)
+
+static void
+test_1 (void)
+{
+ float_type f = 1;
+ volatile float vf = 2;
+ double d = 3;
+ long double ld = 4;
+ int i = 5;
+ long long ll = 6;
+ CHECK_CALL (t1v (f), 2, var_f);
+ CHECK_CALL (t1v (vf), 3, var_f);
+ CHECK_CALL (t1v (d), 5, var_d);
+ CHECK_CALL (t1v (ld), 7, var_ld);
+ CHECK_CALL (t1v (i), 7, var_d);
+ CHECK_CALL (t1v (ll), 8, var_d);
+ CHECK_CALL (t1vr (f), 2, var_f);
+ CHECK_CALL (t1vr (vf), 3, var_f);
+ CHECK_CALL (t1vr (d), 5, var_d);
+ CHECK_CALL (t1vr (ld), 7, var_ld);
+ CHECK_CALL (t1vr (i), 7, var_d);
+ CHECK_CALL (t1vr (ll), 8, var_d);
+}
+
+/* Test first argument not type-generic. */
+
+float t2f (int a, float x) { return a * x + 1; }
+double t2d (int a, double x) { return a * x + 2; }
+long double t2l (int a, long double x) { return a * x + 3; }
+
+#define t2v(a, x) __builtin_tgmath (t2f, t2d, t2l, a, x)
+
+static void
+test_2 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ int i = 4;
+ unsigned long long ll = 5;
+ CHECK_CALL (t2v (1, f), 2, var_f);
+ CHECK_CALL (t2v (2, d), 6, var_d);
+ CHECK_CALL (t2v (3, ld), 12, var_ld);
+ CHECK_CALL (t2v (4, i), 18, var_d);
+ CHECK_CALL (t2v (5, ll), 27, var_d);
+}
+
+/* Test return type not type-generic. */
+
+int t3f (float x) { return x + 1; }
+int t3d (double x) { return x + 2; }
+int t3l (long double x) { return x + 3; }
+
+#define t3v(x) __builtin_tgmath (t3f, t3d, t3l, x)
+
+static void
+test_3 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ short s = 4;
+ CHECK_CALL (t3v (f), 2, var_i);
+ CHECK_CALL (t3v (d), 4, var_i);
+ CHECK_CALL (t3v (ld), 6, var_i);
+ CHECK_CALL (t3v (s), 6, var_i);
+}
+
+/* Test multiple type-generic arguments. */
+
+float t4f (float x, float y) { return 10 * x + y; }
+double t4d (double x, double y) { return 100 * x + y; }
+long double t4l (long double x, long double y) { return 1000 * x + y; }
+
+#define t4v(x, y) __builtin_tgmath (t4f, t4d, t4l, x, y)
+
+static void
+test_4 (void)
+{
+ float f1 = 1;
+ float f2 = 2;
+ double d1 = 3;
+ double d2 = 4;
+ long double ld = 5;
+ long int l = 6;
+ CHECK_CALL (t4v (f1, f2), 12, var_f);
+ CHECK_CALL (t4v (f2, f1), 21, var_f);
+ CHECK_CALL (t4v (f1, d1), 103, var_d);
+ CHECK_CALL (t4v (d2, f2), 402, var_d);
+ CHECK_CALL (t4v (f1, l), 106, var_d);
+ CHECK_CALL (t4v (ld, f1), 5001, var_ld);
+ CHECK_CALL (t4v (l, l), 606, var_d);
+ CHECK_CALL (t4v (l, ld), 6005, var_ld);
+}
+
+/* Test complex argument, real return type. */
+
+float t5f (_Complex float x) { return 1 + __real__ x + 3 * __imag__ x; }
+double t5d (_Complex double x) { return 2 + __real__ x + 4 * __imag__ x; }
+long double t5l (_Complex long double x) { return 3 + __real__ x + 5 * __imag__ x; }
+
+#define t5v(x) __builtin_tgmath (t5f, t5d, t5l, x)
+
+static void
+test_5 (void)
+{
+ float f = 1;
+ _Complex float cf = 2 + 3i;
+ double d = 4;
+ _Complex double cd = 5 + 6i;
+ long double ld = 7;
+ _Complex long double cld = 8 + 9i;
+ int i = 10;
+ _Complex int ci = 11 + 12i;
+ CHECK_CALL (t5v (f), 2, var_f);
+ CHECK_CALL (t5v (cf), 12, var_f);
+ CHECK_CALL (t5v (d), 6, var_d);
+ CHECK_CALL (t5v (cd), 31, var_d);
+ CHECK_CALL (t5v (ld), 10, var_ld);
+ CHECK_CALL (t5v (cld), 56, var_ld);
+ CHECK_CALL (t5v (i), 12, var_d);
+ CHECK_CALL (t5v (ci), 61, var_d);
+}
+
+/* Test complex argument, complex return type. */
+
+_Complex float t6f (_Complex float x) { return 1 + x; }
+_Complex double t6d (_Complex double x) { return 2 + x; }
+_Complex long double t6l (_Complex long double x) { return 3 + x; }
+
+#define t6v(x) __builtin_tgmath (t6f, t6d, t6l, x)
+
+static void
+test_6 (void)
+{
+ float f = 1;
+ _Complex float cf = 2 + 3i;
+ double d = 4;
+ _Complex double cd = 5 + 6i;
+ long double ld = 7;
+ _Complex long double cld = 8 + 9i;
+ int i = 10;
+ _Complex int ci = 11 + 12i;
+ CHECK_CALL (t6v (f), 2, var_cf);
+ CHECK_CALL (t6v (cf), 3 + 3i, var_cf);
+ CHECK_CALL (t6v (d), 6, var_cd);
+ CHECK_CALL (t6v (cd), 7 + 6i, var_cd);
+ CHECK_CALL (t6v (ld), 10, var_cld);
+ CHECK_CALL (t6v (cld), 11 + 9i, var_cld);
+ CHECK_CALL (t6v (i), 12, var_cd);
+ CHECK_CALL (t6v (ci), 13 + 12i, var_cd);
+}
+
+/* Test real and complex argument, real return type. */
+
+float t7f (float x) { return 1 + x; }
+float t7cf (_Complex float x) { return 2 + __real__ x; }
+double t7d (double x) { return 3 + x; }
+double t7cd (_Complex double x) { return 4 + __real__ x; }
+long double t7l (long double x) { return 5 + x; }
+long double t7cl (_Complex long double x) { return 6 + __real__ x; }
+
+#define t7v(x) __builtin_tgmath (t7f, t7d, t7l, t7cf, t7cd, t7cl, x)
+
+static void
+test_7 (void)
+{
+ float f = 1;
+ _Complex float cf = 2 + 3i;
+ double d = 4;
+ _Complex double cd = 5 + 6i;
+ long double ld = 7;
+ _Complex long double cld = 8 + 9i;
+ int i = 10;
+ _Complex int ci = 11 + 12i;
+ CHECK_CALL (t7v (f), 2, var_f);
+ CHECK_CALL (t7v (cf), 4, var_f);
+ CHECK_CALL (t7v (d), 7, var_d);
+ CHECK_CALL (t7v (cd), 9, var_d);
+ CHECK_CALL (t7v (ld), 12, var_ld);
+ CHECK_CALL (t7v (cld), 14, var_ld);
+ CHECK_CALL (t7v (i), 13, var_d);
+ CHECK_CALL (t7v (ci), 15, var_d);
+}
+
+/* Test real and complex argument, real and complex return type. */
+
+float t8f (float x) { return 1 + x; }
+_Complex float t8cf (_Complex float x) { return 2 + x; }
+double t8d (double x) { return 3 + x; }
+_Complex double t8cd (_Complex double x) { return 4 + x; }
+long double t8l (long double x) { return 5 + x; }
+_Complex long double t8cl (_Complex long double x) { return 6 + x; }
+
+#define t8v(x) __builtin_tgmath (t8f, t8d, t8l, t8cf, t8cd, t8cl, x)
+
+static void
+test_8 (void)
+{
+ float f = 1;
+ _Complex float cf = 2 + 3i;
+ double d = 4;
+ _Complex double cd = 5 + 6i;
+ long double ld = 7;
+ _Complex long double cld = 8 + 9i;
+ int i = 10;
+ _Complex int ci = 11 + 12i;
+ CHECK_CALL (t8v (f), 2, var_f);
+ CHECK_CALL (t8v (cf), 4 + 3i, var_cf);
+ CHECK_CALL (t8v (d), 7, var_d);
+ CHECK_CALL (t8v (cd), 9 + 6i, var_cd);
+ CHECK_CALL (t8v (ld), 12, var_ld);
+ CHECK_CALL (t8v (cld), 14 + 9i, var_cld);
+ CHECK_CALL (t8v (i), 13, var_d);
+ CHECK_CALL (t8v (ci), 15 + 12i, var_cd);
+}
+
+/* Test multiple type-generic arguments, real and complex. */
+
+float t9f (float x, float y) { return x + 10 * y; }
+_Complex float t9cf (_Complex float x, _Complex float y) { return x + 100 * y; }
+double t9d (double x, double y) { return x + 1000 * y; }
+_Complex double t9cd (_Complex double x, _Complex double y) { return x + 10000 * y; }
+long double t9l (long double x, long double y) { return x + 100000 * y; }
+_Complex long double t9cl (_Complex long double x, _Complex long double y) { return x + 1000000 * y; }
+
+#define t9v(x, y) __builtin_tgmath (t9f, t9d, t9l, t9cf, t9cd, t9cl, x, y)
+
+static void
+test_9 (void)
+{
+ float f = 1;
+ _Complex float cf = 2 + 3i;
+ double d = 4;
+ _Complex double cd = 5 + 6i;
+ long double ld = 7;
+ _Complex long double cld = 8 + 9i;
+ int i = 10;
+ _Complex int ci = 11 + 12i;
+ CHECK_CALL (t9v (f, f), 11, var_f);
+ CHECK_CALL (t9v (f, cf), 201 + 300i, var_cf);
+ CHECK_CALL (t9v (cf, f), 102 + 3i, var_cf);
+ CHECK_CALL (t9v (f, i), 10001, var_d);
+ CHECK_CALL (t9v (i, f), 1010, var_d);
+ CHECK_CALL (t9v (d, d), 4004, var_d);
+ CHECK_CALL (t9v (d, cd), 50004 + 60000i, var_cd);
+ CHECK_CALL (t9v (ld, i), 1000007, var_ld);
+ CHECK_CALL (t9v (cf, cld), 8000002 + 9000003i, var_cld);
+ CHECK_CALL (t9v (i, i), 10010, var_d);
+ CHECK_CALL (t9v (ci, i), 100011 + 12i, var_cd);
+}
+
+/* Test functions rounding result to narrower type. */
+
+float t10d (double x) { return 1 + x; }
+float t10l (long double x) { return 2 + x; }
+
+#define t10v(x) __builtin_tgmath (t10d, t10l, x)
+
+static void
+test_10 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ short s = 4;
+ CHECK_CALL (t10v (f), 2, var_f);
+ CHECK_CALL (t10v (d), 3, var_f);
+ CHECK_CALL (t10v (ld), 5, var_f);
+ CHECK_CALL (t10v (s), 5, var_f);
+}
+
+int
+main (void)
+{
+ test_1 ();
+ test_2 ();
+ test_3 ();
+ test_4 ();
+ test_5 ();
+ test_6 ();
+ test_7 ();
+ test_8 ();
+ test_9 ();
+ test_10 ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-tgmath-2.c b/gcc/testsuite/gcc.dg/builtin-tgmath-2.c
new file mode 100644
index 0000000..c4140cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-tgmath-2.c
@@ -0,0 +1,51 @@
+/* Test __builtin_tgmath: valid uses, _FloatN types. */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CHECK_CALL(C, E, V) \
+ do \
+ { \
+ if ((C) != (E)) \
+ abort (); \
+ extern __typeof (C) V; \
+ } \
+ while (0)
+
+extern float var_f;
+extern double var_d;
+extern long double var_ld;
+extern _Float32 var_f32;
+
+float t1f (float x) { return x + 1; }
+double t1d (double x) { return x + 2; }
+long double t1l (long double x) { return x + 3; }
+_Float32 t1f32 (_Float32 x) { return x + 4; }
+
+#define t1v(x) __builtin_tgmath (t1f, t1d, t1l, t1f32, x)
+
+static void
+test_1 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ _Float32 f32 = 4;
+ int i = 5;
+ CHECK_CALL (t1v (f), 2, var_f);
+ CHECK_CALL (t1v (d), 4, var_d);
+ CHECK_CALL (t1v (ld), 6, var_ld);
+ CHECK_CALL (t1v (f32), 8, var_f32);
+ CHECK_CALL (t1v (i), 7, var_d);
+}
+
+int
+main (void)
+{
+ test_1 ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-tgmath-err-1.c b/gcc/testsuite/gcc.dg/builtin-tgmath-err-1.c
new file mode 100644
index 0000000..9016ec7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-tgmath-err-1.c
@@ -0,0 +1,76 @@
+/* Test __builtin_tgmath: errors that indicate a bad definition of a
+ type-generic macro rather than bad arguments in a call to it. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void *p;
+double d;
+double unprototyped_d ();
+long double unprototyped_ld ();
+double variadic_d (double, ...);
+long double variadic_ld (long double, ...);
+double no_arguments_d (void);
+long double no_arguments_ld (void);
+double f_d (double);
+long double f_ld (long double);
+double many_args (double, double, double, double);
+int f_i_d (double);
+_Complex int f_ci_d (double);
+void * f_p_d (double);
+double f_d_i (int);
+double f_d_ci (_Complex int);
+double f_d_p (void *);
+long double f_ld_d (double);
+_Complex double f_cd_d (double);
+double f_d_f (float);
+double f_d_dd (double, double);
+long double f_ld_ldld (long double, long double);
+float f_f_fd (float, double);
+
+void
+test (void)
+{
+ /* Arguments individually invalid or no consistent number of
+ arguments followed by those arguments. */
+ __builtin_tgmath (); /* { dg-error "too few arguments" } */
+ __builtin_tgmath (f_d); /* { dg-error "too few arguments" } */
+ __builtin_tgmath (f_d, f_ld); /* { dg-error "too few arguments" } */
+ __builtin_tgmath (many_args, many_args, many_args); /* { dg-error "too few arguments" } */
+ __builtin_tgmath (many_args, d, d, d, d); /* { dg-error "too few arguments" } */
+ __builtin_tgmath (f_ld, many_args, d); /* { dg-error "has wrong number of arguments" } */
+ __builtin_tgmath (unprototyped_d, unprototyped_ld, d); /* { dg-error "is unprototyped" } */
+ __builtin_tgmath (f_d, unprototyped_ld, d); /* { dg-error "is unprototyped" } */
+ __builtin_tgmath (variadic_d, variadic_ld, d); /* { dg-error "variable arguments" } */
+ __builtin_tgmath (f_d, variadic_ld, d); /* { dg-error "variable arguments" } */
+ __builtin_tgmath (p, p, p); /* { dg-error "is not a function pointer" } */
+ __builtin_tgmath (f_d, p, p); /* { dg-error "is not a function pointer" } */
+ __builtin_tgmath (no_arguments_d, no_arguments_d, no_arguments_ld); /* { dg-error "has no arguments" } */
+ __builtin_tgmath (f_d, no_arguments_d, no_arguments_ld); /* { dg-error "has no arguments" } */
+
+ /* Invalid varying types of arguments. */
+ __builtin_tgmath (f_i_d, f_ld, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_ci_d, f_ld, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_p_d, f_ld, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_ld, f_i_d, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_ld, f_ci_d, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_ld, f_p_d, 0); /* { dg-error "invalid type-generic return type" } */
+ __builtin_tgmath (f_d_i, f_ld, 0); /* { dg-error "invalid type-generic type for argument" } */
+ __builtin_tgmath (f_d_ci, f_ld, 0); /* { dg-error "invalid type-generic type for argument" } */
+ __builtin_tgmath (f_d_p, f_ld, 0); /* { dg-error "invalid type-generic type for argument" } */
+ __builtin_tgmath (f_ld, f_d_i, 0); /* { dg-error "invalid type-generic type for argument" } */
+ __builtin_tgmath (f_ld, f_d_ci, 0); /* { dg-error "invalid type-generic type for argument" } */
+ __builtin_tgmath (f_ld, f_d_p, 0); /* { dg-error "invalid type-generic type for argument" } */
+
+ /* Arguments same type. */
+ __builtin_tgmath (f_d, f_d, 0); /* { dg-error "all have the same type" } */
+
+ /* Missing or invalid type-generic parameter. */
+ __builtin_tgmath (f_d, f_ld_d, 0); /* { dg-error "lack type-generic parameter" } */
+ __builtin_tgmath (f_d, f_ld, f_cd_d, 0); /* { dg-error "lack type-generic parameter" } */
+ __builtin_tgmath (f_d, f_ld, f_d, 0); /* { dg-error "duplicate type-generic parameter type" } */
+
+ /* Variation not consistent with the identified type-generic
+ parameter. */
+ __builtin_tgmath (f_d, f_ld, f_d_f, 0); /* { dg-error "bad return type for function argument" } */
+ __builtin_tgmath (f_d_dd, f_ld_ldld, f_f_fd, 0, 0); /* { dg-error "bad type for argument" } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-tgmath-err-2.c b/gcc/testsuite/gcc.dg/builtin-tgmath-err-2.c
new file mode 100644
index 0000000..df5655e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-tgmath-err-2.c
@@ -0,0 +1,19 @@
+/* Test __builtin_tgmath: errors that indicate bad arguments in a call
+ to a type-generic macro, non-DFP. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+float f_f (float);
+double f_d (double);
+long double f_ld (long double);
+void *p;
+long double ld;
+_Complex float cf;
+
+void
+test (void)
+{
+ __builtin_tgmath (f_f, f_d, f_ld, p); /* { dg-error "invalid type of argument" } */
+ __builtin_tgmath (f_f, f_d, ld); /* { dg-error "no matching function for type-generic call" } */
+ __builtin_tgmath (f_f, f_d, cf); /* { dg-error "no matching function for type-generic call" } */
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp-err.c b/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp-err.c
new file mode 100644
index 0000000..b94c760
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp-err.c
@@ -0,0 +1,33 @@
+/* Test __builtin_tgmath: errors that indicate bad arguments in a call
+ to a type-generic macro, DFP involved. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+float f_f (float);
+double f_d (double);
+long double f_ld (long double);
+_Complex float f_cf (_Complex float);
+_Complex double f_cd (_Complex double);
+_Complex long double f_cld (_Complex long double);
+_Decimal32 f_d32 (_Decimal32);
+_Decimal64 f_d64 (_Decimal64);
+_Decimal128 f_d128 (_Decimal128);
+float f_ff (float, float);
+_Complex float f_cfcf (_Complex float, _Complex float);
+_Decimal32 f_d32d32 (_Decimal32, _Decimal32);
+_Complex float cf;
+float f;
+_Decimal32 d32;
+
+void
+test (void)
+{
+ __builtin_tgmath (f_cf, f_cd, f_cld, d32); /* { dg-error "decimal floating-point argument 1 to complex-only type-generic function" } */
+ __builtin_tgmath (f_f, f_d, f_ld, d32); /* { dg-error "decimal floating-point argument 1 to binary-only type-generic function" } */
+ __builtin_tgmath (f_cfcf, f_d32d32, cf, d32); /* { dg-error "both complex and decimal floating-point arguments to type-generic function" } */
+ __builtin_tgmath (f_ff, f_d32d32, f, d32); /* { dg-error "both binary and decimal floating-point arguments to type-generic function" } */
+ __builtin_tgmath (f_d32, f_d64, f_d128, cf); /* { dg-error "complex argument 1 to decimal-only type-generic function" } */
+ __builtin_tgmath (f_d32, f_d64, f_d128, f); /* { dg-error "binary argument 1 to decimal-only type-generic function" } */
+ __builtin_tgmath (f_cfcf, f_d32d32, d32, cf); /* { dg-error "both complex and decimal floating-point arguments to type-generic function" } */
+ __builtin_tgmath (f_ff, f_d32d32, d32, f); /* { dg-error "both binary and decimal floating-point arguments to type-generic function" } */
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp.c b/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp.c
new file mode 100644
index 0000000..256a71e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/builtin-tgmath-dfp.c
@@ -0,0 +1,263 @@
+/* Test __builtin_tgmath: valid uses, decimal floating-point types. */
+/* { dg-do run } */
+/* { dg-options "" } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CHECK_CALL(C, E, V) \
+ do \
+ { \
+ if ((C) != (E)) \
+ abort (); \
+ extern __typeof (C) V; \
+ } \
+ while (0)
+
+extern float var_f;
+extern double var_d;
+extern long double var_ld;
+extern _Complex float var_cf;
+extern _Complex double var_cd;
+extern _Complex long double var_cld;
+extern _Decimal32 var_d32;
+extern _Decimal64 var_d64;
+extern _Decimal128 var_d128;
+extern int var_i;
+
+/* Test decimal-only function, single argument. */
+
+_Decimal32 t1d32 (_Decimal32 x) { return x + 1; }
+_Decimal64 t1d64 (_Decimal64 x) { return x + 2; }
+_Decimal128 t1d128 (_Decimal128 x) { return x + 3; }
+
+#define t1v(x) __builtin_tgmath (t1d32, t1d64, t1d128, x)
+
+static void
+test_1 (void)
+{
+ _Decimal32 d32 = 32;
+ _Decimal64 d64 = 64;
+ _Decimal128 d128 = 128;
+ int i = 256;
+ CHECK_CALL (t1v (d32), 33, var_d32);
+ CHECK_CALL (t1v (d64), 66, var_d64);
+ CHECK_CALL (t1v (d128), 131, var_d128);
+ CHECK_CALL (t1v (i), 258, var_d64);
+}
+
+/* Test decimal-only function, two arguments. */
+
+_Decimal32 t2d32 (_Decimal32 x, _Decimal32 y) { return 10 * x + y; }
+_Decimal64 t2d64 (_Decimal64 x, _Decimal64 y) { return 100 * x + y;; }
+_Decimal128 t2d128 (_Decimal128 x, _Decimal128 y) { return 1000 * x + y; }
+
+#define t2v(x, y) __builtin_tgmath (t2d32, t2d64, t2d128, x, y)
+
+static void
+test_2 (void)
+{
+ _Decimal32 d32 = 1;
+ _Decimal64 d64 = 2;
+ _Decimal128 d128 = 3;
+ int i = 4;
+ CHECK_CALL (t2v (d32, d32), 11, var_d32);
+ CHECK_CALL (t2v (d64, d64), 202, var_d64);
+ CHECK_CALL (t2v (d32, d64), 102, var_d64);
+ CHECK_CALL (t2v (d128, d64), 3002, var_d128);
+ CHECK_CALL (t2v (d128, i), 3004, var_d128);
+ CHECK_CALL (t2v (i, i), 404, var_d64);
+ CHECK_CALL (t2v (i, d32), 401, var_d64);
+}
+
+/* Test real-only function, single argument. */
+
+float t3f (float x) { return x + 1; }
+double t3d (double x) { return x + 2; }
+long double t3l (long double x) { return x + 3; }
+_Decimal32 t3d32 (_Decimal32 x) { return x + 4; }
+_Decimal64 t3d64 (_Decimal64 x) { return x + 5; }
+_Decimal128 t3d128 (_Decimal128 x) { return x + 6; }
+
+#define t3v(x) __builtin_tgmath (t3f, t3d, t3l, t3d32, t3d64, t3d128, x)
+
+static void
+test_3 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ int i = 4;
+ _Decimal32 d32 = 5;
+ _Decimal64 d64 = 6;
+ _Decimal128 d128 = 7;
+ CHECK_CALL (t3v (f), 2, var_f);
+ CHECK_CALL (t3v (d), 4, var_d);
+ CHECK_CALL (t3v (ld), 6, var_ld);
+ CHECK_CALL (t3v (i), 6, var_d);
+ CHECK_CALL (t3v (d32), 9, var_d32);
+ CHECK_CALL (t3v (d64), 11, var_d64);
+ CHECK_CALL (t3v (d128), 13, var_d128);
+}
+
+/* Test real-and-complex function, single argument. */
+
+float t4f (float x) { return x + 1; }
+double t4d (double x) { return x + 2; }
+long double t4l (long double x) { return x + 3; }
+_Complex float t4cf (_Complex float x) { return x + 4; }
+_Complex double t4cd (_Complex double x) { return x + 5; }
+_Complex long double t4cl (_Complex long double x) { return x + 6; }
+_Decimal32 t4d32 (_Decimal32 x) { return x + 7; }
+_Decimal64 t4d64 (_Decimal64 x) { return x + 8; }
+_Decimal128 t4d128 (_Decimal128 x) { return x + 9; }
+
+#define t4v(x) __builtin_tgmath (t4f, t4d, t4l, t4cf, t4cd, t4cl, t4d32, t4d64, t4d128, x)
+
+static void
+test_4 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ int i = 4;
+ _Complex float cf = 5;
+ _Complex double cd = 6;
+ _Complex long double cld = 7;
+ _Complex int ci = 8;
+ _Decimal32 d32 = 9;
+ _Decimal64 d64 = 10;
+ _Decimal128 d128 = 11;
+ CHECK_CALL (t4v (f), 2, var_f);
+ CHECK_CALL (t4v (d), 4, var_d);
+ CHECK_CALL (t4v (ld), 6, var_ld);
+ CHECK_CALL (t4v (i), 6, var_d);
+ CHECK_CALL (t4v (cf), 9, var_cf);
+ CHECK_CALL (t4v (cd), 11, var_cd);
+ CHECK_CALL (t4v (cld), 13, var_cld);
+ CHECK_CALL (t4v (ci), 13, var_cd);
+ CHECK_CALL (t4v (d32), 16, var_d32);
+ CHECK_CALL (t4v (d64), 18, var_d64);
+ CHECK_CALL (t4v (d128), 20, var_d128);
+}
+
+/* Test real-and-complex function, real return type, single argument. */
+
+float t5f (float x) { return x + 1; }
+double t5d (double x) { return x + 2; }
+long double t5l (long double x) { return x + 3; }
+float t5cf (_Complex float x) { return __real__ x + 4; }
+double t5cd (_Complex double x) { return __real__ x + 5; }
+long double t5cl (_Complex long double x) { return __real__ x + 6; }
+_Decimal32 t5d32 (_Decimal32 x) { return x + 7; }
+_Decimal64 t5d64 (_Decimal64 x) { return x + 8; }
+_Decimal128 t5d128 (_Decimal128 x) { return x + 9; }
+
+#define t5v(x) __builtin_tgmath (t5f, t5d, t5l, t5cf, t5cd, t5cl, t5d32, t5d64, t5d128, x)
+
+static void
+test_5 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ int i = 4;
+ _Complex float cf = 5;
+ _Complex double cd = 6;
+ _Complex long double cld = 7;
+ _Complex int ci = 8;
+ _Decimal32 d32 = 9;
+ _Decimal64 d64 = 10;
+ _Decimal128 d128 = 11;
+ CHECK_CALL (t5v (f), 2, var_f);
+ CHECK_CALL (t5v (d), 4, var_d);
+ CHECK_CALL (t5v (ld), 6, var_ld);
+ CHECK_CALL (t5v (i), 6, var_d);
+ CHECK_CALL (t5v (cf), 9, var_f);
+ CHECK_CALL (t5v (cd), 11, var_d);
+ CHECK_CALL (t5v (cld), 13, var_ld);
+ CHECK_CALL (t5v (ci), 13, var_d);
+ CHECK_CALL (t5v (d32), 16, var_d32);
+ CHECK_CALL (t5v (d64), 18, var_d64);
+ CHECK_CALL (t5v (d128), 20, var_d128);
+}
+
+/* Test real-and-complex function, two arguments. */
+
+float t6f (float x, float y) { return x * 10 + y; }
+double t6d (double x, double y) { return x * 100 + y; }
+long double t6l (long double x, long double y) { return x * 1000 + y; }
+_Complex float t6cf (_Complex float x, _Complex float y) { return x * 10000 + y; }
+_Complex double t6cd (_Complex double x, _Complex double y) { return x * 100000 + y; }
+_Complex long double t6cl (_Complex long double x, _Complex long double y) { return x * 1000000 + y; }
+_Decimal32 t6d32 (_Decimal32 x, _Decimal32 y) { return x * 50 + y; }
+_Decimal64 t6d64 (_Decimal64 x, _Decimal64 y) { return x * 500 + y; }
+_Decimal128 t6d128 (_Decimal128 x, _Decimal128 y) { return x * 5000 + y; }
+
+#define t6v(x, y) __builtin_tgmath (t6f, t6d, t6l, t6cf, t6cd, t6cl, t6d32, t6d64, t6d128, x, y)
+
+static void
+test_6 (void)
+{
+ float f = 1;
+ double d = 2;
+ long double ld = 3;
+ int i = 4;
+ _Complex float cf = 5;
+ _Complex double cd = 6;
+ _Complex long double cld = 7;
+ _Complex int ci = 8;
+ _Decimal32 d32 = 9;
+ _Decimal64 d64 = 10;
+ _Decimal128 d128 = 11;
+ CHECK_CALL (t6v (f, f), 11, var_f);
+ CHECK_CALL (t6v (d, f), 201, var_d);
+ CHECK_CALL (t6v (f, d), 102, var_d);
+ CHECK_CALL (t6v (f, i), 104, var_d);
+ CHECK_CALL (t6v (ld, f), 3001, var_ld);
+ CHECK_CALL (t6v (i, ld), 4003, var_ld);
+ CHECK_CALL (t6v (i, i), 404, var_d);
+ CHECK_CALL (t6v (cf, f), 50001, var_cf);
+ CHECK_CALL (t6v (cf, cf), 50005, var_cf);
+ CHECK_CALL (t6v (cd, cf), 600005, var_cd);
+ CHECK_CALL (t6v (d, cld), 2000007, var_cld);
+ CHECK_CALL (t6v (ci, ci), 800008, var_cd);
+ CHECK_CALL (t6v (ci, f), 800001, var_cd);
+ CHECK_CALL (t6v (d32, d32), 459, var_d32);
+ CHECK_CALL (t6v (d64, i), 5004, var_d64);
+ CHECK_CALL (t6v (i, d32), 2009, var_d64);
+ CHECK_CALL (t6v (d128, d32), 55009, var_d128);
+}
+
+/* Test decimal-only function rounding result to narrower type. */
+
+_Decimal32 t7d64 (_Decimal64 x) { return 1 + x; }
+_Decimal32 t7d128 (_Decimal128 x) { return 2 + x; }
+
+#define t7v(x) __builtin_tgmath (t7d64, t7d128, x)
+
+static void
+test_7 (void)
+{
+ _Decimal32 d32 = 1;
+ _Decimal64 d64 = 2;
+ _Decimal128 d128 = 3;
+ short s = 4;
+ CHECK_CALL (t7v (d32), 2, var_d32);
+ CHECK_CALL (t7v (d64), 3, var_d32);
+ CHECK_CALL (t7v (d128), 5, var_d32);
+ CHECK_CALL (t7v (s), 5, var_d32);
+}
+
+int
+main (void)
+{
+ test_1 ();
+ test_2 ();
+ test_3 ();
+ test_4 ();
+ test_5 ();
+ test_6 ();
+ test_7 ();
+ exit (0);
+}