aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r--gcc/c/c-parser.c564
1 files changed, 564 insertions, 0 deletions
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);
}