static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
-static int resort_field_decl_cmp (const void *, const void *);
/* Reserved words. The third field is a mask: keywords are disabled
if they match the mask.
{ "__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 },
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, D_CXXONLY },
{ "while", RID_WHILE, 0 },
+ { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY },
+ { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY },
/* C++ transactional memory. */
{ "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
return error_mark_node;
}
- if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))))
- != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask)))))
+ if (GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))))
+ != GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (TREE_TYPE (mask)))))
{
if (complain)
error_at (loc, "__builtin_shuffle argument vector(s) inner type "
can return SAFE_CONVERSION (zero) in that case. Function can produce
signedness warnings if PRODUCE_WARNS is true.
+ RESULT, when non-null is the result of the conversion. When constant
+ it is included in the text of diagnostics.
+
Function allows conversions from complex constants to non-complex types,
provided that imaginary part is zero and real part can be safely converted
to TYPE. */
enum conversion_safety
-unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
+unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
+ bool produce_warns)
{
enum conversion_safety give_warning = SAFE_CONVERSION; /* is 0 or false */
tree expr_type = TREE_TYPE (expr);
- loc = expansion_point_location_if_in_system_header (loc);
+
+ bool cstresult = (result
+ && TREE_CODE_CLASS (TREE_CODE (result)) == tcc_constant);
+
+ loc = expansion_point_location_if_in_system_header (loc);
if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
{
&& tree_int_cst_sgn (expr) < 0)
{
if (produce_warns)
- warning_at (loc, OPT_Wsign_conversion, "negative integer"
- " implicitly converted to unsigned type");
+ {
+ if (cstresult)
+ warning_at (loc, OPT_Wsign_conversion,
+ "unsigned conversion from %qT to %qT "
+ "changes value from %qE to %qE",
+ expr_type, type, expr, result);
+ else
+ warning_at (loc, OPT_Wsign_conversion,
+ "unsigned conversion from %qT to %qT "
+ "changes the value of %qE",
+ expr_type, type, expr);
+ }
}
else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
{
- if (produce_warns)
- warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
- " constant value to negative integer");
+ if (cstresult)
+ warning_at (loc, OPT_Wsign_conversion,
+ "signed conversion from %qT to %qT changes "
+ "value from %qE to %qE",
+ expr_type, type, expr, result);
+ else
+ warning_at (loc, OPT_Wsign_conversion,
+ "signed conversion from %qT to %qT changes "
+ "the value of %qE",
+ expr_type, type, expr);
}
else
give_warning = UNSAFE_OTHER;
with different type of EXPR, but it is still safe, because when EXPR
is a constant, it's type is not used in text of generated warnings
(otherwise they could sound misleading). */
- return unsafe_conversion_p (loc, type, TREE_REALPART (expr),
+ return unsafe_conversion_p (loc, type, TREE_REALPART (expr), result,
produce_warns);
/* Conversion from complex constant with non-zero imaginary part. */
else
Possible solution: add a separate function for checking
constants and combine result of two calls appropriately. */
enum conversion_safety re_safety =
- unsafe_conversion_p (loc, type, TREE_REALPART (expr), false);
+ unsafe_conversion_p (loc, type, TREE_REALPART (expr),
+ result, false);
enum conversion_safety im_safety =
- unsafe_conversion_p (loc, type, imag_part, false);
+ unsafe_conversion_p (loc, type, imag_part, result, false);
/* Merge the results into appropriate single warning. */
if (bits <= TYPE_PRECISION (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
- return 0;
+ return NULL_TREE;
}
/* Return a fixed-point type that has at least IBIT ibits and FBIT fbits
c_common_fixed_point_type_for_size (unsigned int ibit, unsigned int fbit,
int unsignedp, int satp)
{
- machine_mode mode;
+ enum mode_class mclass;
if (ibit == 0)
- mode = unsignedp ? UQQmode : QQmode;
+ mclass = unsignedp ? MODE_UFRACT : MODE_FRACT;
else
- mode = unsignedp ? UHAmode : HAmode;
+ mclass = unsignedp ? MODE_UACCUM : MODE_ACCUM;
- for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
- if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit)
- break;
+ opt_scalar_mode opt_mode;
+ scalar_mode mode;
+ FOR_EACH_MODE_IN_CLASS (opt_mode, mclass)
+ {
+ mode = opt_mode.require ();
+ if (GET_MODE_IBIT (mode) >= ibit && GET_MODE_FBIT (mode) >= fbit)
+ break;
+ }
- if (mode == VOIDmode || !targetm.scalar_mode_supported_p (mode))
+ if (!opt_mode.exists (&mode) || !targetm.scalar_mode_supported_p (mode))
{
sorry ("GCC cannot support operators with integer types and "
"fixed-point types that have too many integral and "
"fractional bits together");
- return 0;
+ return NULL_TREE;
}
return c_common_type_for_mode (mode, satp);
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- if (mode == TYPE_MODE (widest_integer_literal_type_node))
- return unsignedp ? widest_unsigned_literal_type_node
- : widest_integer_literal_type_node;
-
if (mode == QImode)
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
if (mode == TYPE_MODE (void_type_node))
return void_type_node;
- if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
- return (unsignedp
- ? make_unsigned_type (GET_MODE_PRECISION (mode))
- : make_signed_type (GET_MODE_PRECISION (mode)));
-
- if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
- return (unsignedp
- ? make_unsigned_type (GET_MODE_PRECISION (mode))
- : make_signed_type (GET_MODE_PRECISION (mode)));
+ if (mode == TYPE_MODE (build_pointer_type (char_type_node))
+ || mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+ {
+ unsigned int precision
+ = GET_MODE_PRECISION (as_a <scalar_int_mode> (mode));
+ return (unsignedp
+ ? make_unsigned_type (precision)
+ : make_signed_type (precision));
+ }
if (COMPLEX_MODE_P (mode))
{
&& !!unsignedp == !!TYPE_UNSIGNED (TREE_VALUE (t)))
return TREE_VALUE (t);
- return 0;
+ return NULL_TREE;
}
tree
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- if (type1 == widest_integer_literal_type_node || type1 == widest_unsigned_literal_type_node)
- return unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node;
#if HOST_BITS_PER_WIDE_INT >= 64
if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node)
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- if (TYPE_OK (widest_integer_literal_type_node))
- return (unsignedp ? widest_unsigned_literal_type_node
- : widest_integer_literal_type_node);
-
#if HOST_BITS_PER_WIDE_INT >= 64
if (TYPE_OK (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
DECL_ARTIFICIAL (decl) = 1;
if (!TYPE_NAME (type))
TYPE_NAME (type) = decl;
- pushdecl (decl);
+ lang_hooks.decls.pushdecl (decl);
registered_builtin_types = tree_cons (0, type, registered_builtin_types);
}
default:
gcc_unreachable ();
}
- error_at_rich_loc (richloc,
- "invalid operands to binary %s (have %qT and %qT)",
- opname, type0, type1);
+ error_at (richloc,
+ "invalid operands to binary %s (have %qT and %qT)",
+ opname, type0, type1);
}
\f
/* Given an expression as a tree, return its original type. Do this
LOC is the location of the comparison.
- If this function returns nonzero, it means that the comparison has
+ If this function returns non-NULL_TREE, it means that the comparison has
a constant value. What this function returns is an expression for
that value. */
else if (real1 && real2
&& (DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop0)))
|| DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (primop1)))))
- return 0;
+ return NULL_TREE;
else if (real1 && real2
&& (TYPE_PRECISION (TREE_TYPE (primop0))
if (!real1 && !real2 && integer_zerop (primop1)
&& TYPE_UNSIGNED (*restype_ptr))
{
- tree value = 0;
+ tree value = NULL_TREE;
/* All unsigned values are >= 0, so we warn. However,
if OP0 is a constant that is >= 0, the signedness of
the comparison isn't an issue, so suppress the
break;
}
- if (value != 0)
+ if (value != NULL_TREE)
{
/* Don't forget to evaluate PRIMOP0 if it has side effects. */
if (TREE_SIDE_EFFECTS (primop0))
*restype_ptr = truthvalue_type_node;
- return 0;
+ return NULL_TREE;
}
\f
/* Return a tree for the sum or difference (RESULTCODE says which)
can result in a sum or difference with different type args. */
ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)),
subcode, ptrop,
- convert (int_type, TREE_OPERAND (intop, 1)), 1);
+ convert (int_type, TREE_OPERAND (intop, 1)),
+ true);
intop = convert (int_type, TREE_OPERAND (intop, 0));
}
convert (TREE_TYPE (intop), size_exp));
intop = convert (sizetype, t);
if (TREE_OVERFLOW_P (intop) && !TREE_OVERFLOW (t))
- intop = wide_int_to_tree (TREE_TYPE (intop), intop);
+ intop = wide_int_to_tree (TREE_TYPE (intop), wi::to_wide (intop));
}
/* Create the sum or difference. */
return expr;
}
-/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but
- for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
- around the SAVE_EXPR if needed so that c_fully_fold does not need
- to look inside SAVE_EXPRs. */
-
-tree
-c_save_expr (tree expr)
-{
- bool maybe_const = true;
- if (c_dialect_cxx ())
- return save_expr (expr);
- expr = c_fully_fold (expr, false, &maybe_const);
- expr = save_expr (expr);
- if (!maybe_const)
- expr = c_wrap_maybe_const (expr, true);
- return expr;
-}
-
/* Return whether EXPR is a declaration whose address can never be
NULL. */
TREE_OPERAND (expr, 0)),
c_common_truthvalue_conversion (location,
TREE_OPERAND (expr, 1)),
- 0);
+ false);
goto ret;
case NEGATE_EXPR:
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
- tree t = (in_late_binary_op ? save_expr (expr) : c_save_expr (expr));
+ tree t = save_expr (expr);
expr = (build_binary_op
(EXPR_LOCATION (expr),
(TREE_SIDE_EFFECTS (expr)
c_common_truthvalue_conversion
(location,
build_unary_op (location, IMAGPART_EXPR, t, false)),
- 0));
+ false));
goto ret;
}
tree fixed_zero_node = build_fixed (TREE_TYPE (expr),
FCONST0 (TYPE_MODE
(TREE_TYPE (expr))));
- return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, 1);
+ return build_binary_op (location, NE_EXPR, expr, fixed_zero_node, true);
}
else
- return build_binary_op (location, NE_EXPR, expr, integer_zero_node, 1);
+ return build_binary_op (location, NE_EXPR, expr, integer_zero_node, true);
ret:
protected_set_expr_location (expr, location);
}
}
-struct c_type_hasher : ggc_ptr_hash<tree_node>
-{
- static hashval_t hash (tree);
- static bool equal (tree, tree);
-};
-
-/* Hash function for the problem of multiple type definitions in
- different files. This must hash all types that will compare
- equal via comptypes to the same value. In practice it hashes
- on some of the simple stuff and leaves the details to comptypes. */
-
-hashval_t
-c_type_hasher::hash (tree t)
-{
- int n_elements;
- int shift, size;
- tree t2;
- switch (TREE_CODE (t))
- {
- /* For pointers, hash on pointee type plus some swizzling. */
- case POINTER_TYPE:
- return hash (TREE_TYPE (t)) ^ 0x3003003;
- /* Hash on number of elements and total size. */
- case ENUMERAL_TYPE:
- shift = 3;
- t2 = TYPE_VALUES (t);
- break;
- case RECORD_TYPE:
- shift = 0;
- t2 = TYPE_FIELDS (t);
- break;
- case QUAL_UNION_TYPE:
- shift = 1;
- t2 = TYPE_FIELDS (t);
- break;
- case UNION_TYPE:
- shift = 2;
- t2 = TYPE_FIELDS (t);
- break;
- default:
- gcc_unreachable ();
- }
- /* FIXME: We want to use a DECL_CHAIN iteration method here, but
- TYPE_VALUES of ENUMERAL_TYPEs is stored as a TREE_LIST. */
- n_elements = list_length (t2);
- /* We might have a VLA here. */
- if (TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST)
- size = 0;
- else
- size = TREE_INT_CST_LOW (TYPE_SIZE (t));
- return ((size << 24) | (n_elements << shift));
-}
-
-bool
-c_type_hasher::equal (tree t1, tree t2)
-{
- return lang_hooks.types_compatible_p (t1, t2);
-}
-
-static GTY(()) hash_table<c_type_hasher> *type_hash_table;
-
/* Return the typed-based alias set for T, which may be an expression
or a type. Return -1 if we don't do anything special. */
return get_alias_set (t1);
}
- /* Handle the case of multiple type nodes referring to "the same" type,
- which occurs with IMA. These share an alias set. FIXME: Currently only
- C90 is handled. (In C99 type compatibility is not transitive, which
- complicates things mightily. The alias set splay trees can theoretically
- represent this, but insertion is tricky when you consider all the
- different orders things might arrive in.) */
-
- if (c_language != clk_c || flag_isoc99)
- return -1;
-
- /* Save time if there's only one input file. */
- if (num_in_fnames == 1)
- return -1;
-
- /* Pointers need special handling if they point to any type that
- needs special handling (below). */
- if (TREE_CODE (t) == POINTER_TYPE)
- {
- tree t2;
- /* Find bottom type under any nested POINTERs. */
- for (t2 = TREE_TYPE (t);
- TREE_CODE (t2) == POINTER_TYPE;
- t2 = TREE_TYPE (t2))
- ;
- if (!RECORD_OR_UNION_TYPE_P (t2)
- && TREE_CODE (t2) != ENUMERAL_TYPE)
- return -1;
- if (TYPE_SIZE (t2) == 0)
- return -1;
- }
- /* These are the only cases that need special handling. */
- if (!RECORD_OR_UNION_TYPE_P (t)
- && TREE_CODE (t) != ENUMERAL_TYPE
- && TREE_CODE (t) != POINTER_TYPE)
- return -1;
- /* Undefined? */
- if (TYPE_SIZE (t) == 0)
- return -1;
-
- /* Look up t in hash table. Only one of the compatible types within each
- alias set is recorded in the table. */
- if (!type_hash_table)
- type_hash_table = hash_table<c_type_hasher>::create_ggc (1021);
- tree *slot = type_hash_table->find_slot (t, INSERT);
- if (*slot != NULL)
- {
- TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot);
- return TYPE_ALIAS_SET ((tree)*slot);
- }
- else
- /* Our caller will assign and record (in t) a new alias set; all we need
- to do is remember t in the hash table. */
- *slot = t;
-
return -1;
}
\f
#endif
/* Create the widest literal types. */
- widest_integer_literal_type_node
- = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
- lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
- TYPE_DECL, NULL_TREE,
- widest_integer_literal_type_node));
-
- widest_unsigned_literal_type_node
- = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
- lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
- TYPE_DECL, NULL_TREE,
- widest_unsigned_literal_type_node));
+ if (targetm.scalar_mode_supported_p (TImode))
+ {
+ widest_integer_literal_type_node = intTI_type_node;
+ widest_unsigned_literal_type_node = unsigned_intTI_type_node;
+ }
+ else
+ {
+ widest_integer_literal_type_node = intDI_type_node;
+ widest_unsigned_literal_type_node = unsigned_intDI_type_node;
+ }
signed_size_type_node = c_common_signed_type (size_type_node);
if (c_dialect_cxx ())
{
/* For C++, make fileptr_type_node a distinct void * type until
- FILE type is defined. */
- fileptr_type_node = build_variant_type_copy (ptr_type_node);
- /* Likewise for const struct tm*. */
- const_tm_ptr_type_node = build_variant_type_copy (const_ptr_type_node);
+ FILE type is defined. Likewise for const struct tm*. */
+ for (unsigned i = 0;
+ i < sizeof (builtin_structptr_types)
+ / sizeof (builtin_structptr_type);
+ ++i)
+ builtin_structptr_types[i].node =
+ build_variant_type_copy (builtin_structptr_types[i].base);
+
}
record_builtin_type (RID_VOID, NULL, void_type_node);
return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node);
case BOOLEAN_TYPE:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
/* Return 1 if PARMS specifies a fixed number of parameters
and none of their types is affected by default promotions. */
-int
+bool
self_promoting_args_p (const_tree parms)
{
const_tree t;
if (type == error_mark_node)
continue;
- if (TREE_CHAIN (t) == 0 && type != void_type_node)
- return 0;
+ if (TREE_CHAIN (t) == NULL_TREE && type != void_type_node)
+ return false;
- if (type == 0)
- return 0;
+ if (type == NULL_TREE)
+ return false;
if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return 0;
+ return false;
if (c_promoting_integer_type_p (type))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* Recursively remove any '*' or '&' operator from TYPE. */
/* And apply them. */
decode_options (&global_options, &global_options_set,
decoded_options, decoded_options_count,
- input_location, global_dc);
+ input_location, global_dc, NULL);
targetm.override_options_after_change();
diagnostics. Return true if -Wnonnull warning has been diagnosed. */
bool
check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
- int nargs, tree *argarray)
+ int nargs, tree *argarray, vec<location_t> *arglocs)
{
bool warned_p = false;
/* Check for errors in format strings. */
if (warn_format || warn_suggest_attribute_format)
- check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray);
+ check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray, arglocs);
if (warn_format)
check_function_sentinel (fntype, nargs, argarray);
format_num = tree_to_uhwi (format_num_expr);
for (inner_arg = first_call_expr_arg (param, &iter), i = 1;
- inner_arg != 0;
+ inner_arg != NULL_TREE;
inner_arg = next_call_expr_arg (&iter), i++)
if (i == format_num)
{
switch (DECL_FUNCTION_CODE (fndecl))
{
+ case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
+ if (!tree_fits_uhwi_p (args[2]))
+ {
+ error_at (ARG_LOCATION (2),
+ "third argument to function %qE must be a constant integer",
+ fndecl);
+ return false;
+ }
+ /* fall through */
+
case BUILT_IN_ALLOCA_WITH_ALIGN:
{
/* Get the requested alignment (in bits) if it's a constant
}
}
-/* Function to help qsort sort FIELD_DECLs by name order. */
-
-int
-field_decl_cmp (const void *x_p, const void *y_p)
-{
- const tree *const x = (const tree *const) x_p;
- const tree *const y = (const tree *const) y_p;
-
- if (DECL_NAME (*x) == DECL_NAME (*y))
- /* A nontype is "greater" than a type. */
- return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL);
- if (DECL_NAME (*x) == NULL_TREE)
- return -1;
- if (DECL_NAME (*y) == NULL_TREE)
- return 1;
- if (DECL_NAME (*x) < DECL_NAME (*y))
- return -1;
- return 1;
-}
-
-static struct {
- gt_pointer_operator new_value;
- void *cookie;
-} resort_data;
-
-/* This routine compares two fields like field_decl_cmp but using the
-pointer operator in resort_data. */
-
-static int
-resort_field_decl_cmp (const void *x_p, const void *y_p)
-{
- const tree *const x = (const tree *const) x_p;
- const tree *const y = (const tree *const) y_p;
-
- if (DECL_NAME (*x) == DECL_NAME (*y))
- /* A nontype is "greater" than a type. */
- return (TREE_CODE (*y) == TYPE_DECL) - (TREE_CODE (*x) == TYPE_DECL);
- if (DECL_NAME (*x) == NULL_TREE)
- return -1;
- if (DECL_NAME (*y) == NULL_TREE)
- return 1;
- {
- tree d1 = DECL_NAME (*x);
- tree d2 = DECL_NAME (*y);
- resort_data.new_value (&d1, resort_data.cookie);
- resort_data.new_value (&d2, resort_data.cookie);
- if (d1 < d2)
- return -1;
- }
- return 1;
-}
-
-/* Resort DECL_SORTED_FIELDS because pointers have been reordered. */
-
-void
-resort_sorted_fields (void *obj,
- void * ARG_UNUSED (orig_obj),
- gt_pointer_operator new_value,
- void *cookie)
-{
- struct sorted_fields_type *sf = (struct sorted_fields_type *) obj;
- resort_data.new_value = new_value;
- resort_data.cookie = cookie;
- qsort (&sf->elts[0], sf->len, sizeof (tree),
- resort_field_decl_cmp);
-}
-
/* Subroutine of c_parse_error.
Return the result of concatenating LHS and RHS. RHS is really
a string literal, its first character is indicated by RHS_START and
static char *
catenate_strings (const char *lhs, const char *rhs_start, int rhs_size)
{
- const int lhs_size = strlen (lhs);
+ const size_t lhs_size = strlen (lhs);
char *result = XNEWVEC (char, lhs_size + rhs_size);
- strncpy (result, lhs, lhs_size);
- strncpy (result + lhs_size, rhs_start, rhs_size);
+ memcpy (result, lhs, lhs_size);
+ memcpy (result + lhs_size, rhs_start, rhs_size);
return result;
}
-/* Issue the error given by GMSGID, indicating that it occurred before
- TOKEN, which had the associated VALUE. */
+/* Issue the error given by GMSGID at RICHLOC, indicating that it occurred
+ before TOKEN, which had the associated VALUE. */
void
c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
- tree value, unsigned char token_flags)
+ tree value, unsigned char token_flags,
+ rich_location *richloc)
{
#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2))
else
message = catenate_messages (gmsgid, " before %s'\\x%x'");
- error (message, prefix, val);
+ error_at (richloc, message, prefix, val);
free (message);
message = NULL;
}
else if (token_type == CPP_NAME)
{
message = catenate_messages (gmsgid, " before %qE");
- error (message, value);
+ error_at (richloc, message, value);
free (message);
message = NULL;
}
else if (token_type < N_TTYPES)
{
message = catenate_messages (gmsgid, " before %qs token");
- error (message, cpp_type2name (token_type, token_flags));
+ error_at (richloc, message, cpp_type2name (token_type, token_flags));
free (message);
message = NULL;
}
else
- error (gmsgid);
+ error_at (richloc, gmsgid);
if (message)
{
- error (message);
+ error_at (richloc, message);
free (message);
}
#undef catenate_messages
richloc, dlevel);
diagnostic_override_option_index (&diagnostic,
c_option_controlling_cpp_error (reason));
- ret = report_diagnostic (&diagnostic);
+ ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
if (level == CPP_DL_WARNING_SYSHDR)
global_dc->dc_warn_system_headers = save_warn_system_headers;
return ret;
{
tree maxindex, type, main_type, elt, unqual_elt;
int failure = 0, quals;
- hashval_t hashcode = 0;
bool overflow_p = false;
maxindex = size_zero_node;
TYPE_DOMAIN (main_type)
= build_range_type (TREE_TYPE (maxindex),
build_int_cst (TREE_TYPE (maxindex), 0), maxindex);
+ TYPE_TYPELESS_STORAGE (main_type) = TYPE_TYPELESS_STORAGE (type);
layout_type (main_type);
/* Make sure we have the canonical MAIN_TYPE. */
- hashcode = iterative_hash_object (TYPE_HASH (unqual_elt), hashcode);
- hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (main_type)),
- hashcode);
+ hashval_t hashcode = type_hash_canon_hash (main_type);
main_type = type_hash_canon (hashcode, main_type);
/* Fix the canonical type. */
!= TYPE_DOMAIN (main_type)))
TYPE_CANONICAL (main_type)
= build_array_type (TYPE_CANONICAL (TREE_TYPE (main_type)),
- TYPE_CANONICAL (TYPE_DOMAIN (main_type)));
+ TYPE_CANONICAL (TYPE_DOMAIN (main_type)),
+ TYPE_TYPELESS_STORAGE (main_type));
else
TYPE_CANONICAL (main_type) = main_type;
}
argtype = type = TREE_TYPE ((*params)[0]);
- if (TREE_CODE (type) == ARRAY_TYPE)
+ if (TREE_CODE (type) == ARRAY_TYPE && c_dialect_cxx ())
{
/* Force array-to-pointer decay for C++. */
- gcc_assert (c_dialect_cxx());
(*params)[0] = default_conversion ((*params)[0]);
type = TREE_TYPE ((*params)[0]);
}
if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
goto incompatible;
+ if (!COMPLETE_TYPE_P (type))
+ goto incompatible;
+
if (fetch && TREE_CODE (type) == BOOLEAN_TYPE)
goto incompatible;
/* Get type of first parameter, and determine its size. */
type_0 = TREE_TYPE ((*params)[0]);
- if (TREE_CODE (type_0) == ARRAY_TYPE)
+ if (TREE_CODE (type_0) == ARRAY_TYPE && c_dialect_cxx ())
{
/* Force array-to-pointer decay for C++. */
- gcc_assert (c_dialect_cxx());
(*params)[0] = default_conversion ((*params)[0]);
type_0 = TREE_TYPE ((*params)[0]);
}
/* __atomic_compare_exchange has a bool in the 4th position, skip it. */
if (n_param == 6 && x == 3)
continue;
+ if (TREE_CODE (type) == ARRAY_TYPE && c_dialect_cxx ())
+ {
+ /* Force array-to-pointer decay for C++. */
+ (*params)[x] = default_conversion ((*params)[x]);
+ type = TREE_TYPE ((*params)[x]);
+ }
if (!POINTER_TYPE_P (type))
{
error_at (loc, "argument %d of %qE must be a pointer type", x + 1,
tree p = (*params)[x];
if (TREE_CODE (p) == INTEGER_CST)
{
- int i = tree_to_uhwi (p);
- if (i < 0 || (memmodel_base (i) >= MEMMODEL_LAST))
- {
- warning_at (loc, OPT_Winvalid_memory_model,
- "invalid memory model argument %d of %qE", x + 1,
- function);
- }
+ /* memmodel_base masks the low 16 bits, thus ignore any bits above
+ it by using TREE_INT_CST_LOW instead of tree_to_*hwi. Those high
+ bits will be checked later during expansion in target specific
+ way. */
+ if (memmodel_base (TREE_INT_CST_LOW (p)) >= MEMMODEL_LAST)
+ warning_at (loc, OPT_Winvalid_memory_model,
+ "invalid memory model argument %d of %qE", x + 1,
+ function);
}
else
if (!INTEGRAL_TYPE_P (TREE_TYPE (p)))
if (TREE_CODE (type0) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
{
- if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0, false))
+ if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0,
+ NULL_TREE, false))
{
if (complain)
error_at (loc, "conversion of scalar %qT to vector %qT "
if (TREE_CODE (type0) == INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
{
- if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0, false))
+ if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0,
+ NULL_TREE, false))
{
if (complain)
error_at (loc, "conversion of scalar %qT to vector %qT "
|| TREE_CODE (type0) == INTEGER_TYPE)
&& SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
{
- if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0, false))
+ if (unsafe_conversion_p (loc, TREE_TYPE (type1), op0,
+ NULL_TREE, false))
{
if (complain)
error_at (loc, "conversion of scalar %qT to vector %qT "
return c_ts18661_flt_eval_method ();
}
+/* An enum for get_missing_token_insertion_kind for describing the best
+ place to insert a missing token, if there is one. */
+
+enum missing_token_insertion_kind
+{
+ MTIK_IMPOSSIBLE,
+ MTIK_INSERT_BEFORE_NEXT,
+ MTIK_INSERT_AFTER_PREV
+};
+
+/* Given a missing token of TYPE, determine if it is reasonable to
+ emit a fix-it hint suggesting the insertion of the token, and,
+ if so, where the token should be inserted relative to other tokens.
+
+ It only makes sense to do this for values of TYPE that are symbols.
+
+ Some symbols should go before the next token, e.g. in:
+ if flag)
+ we want to insert the missing '(' immediately before "flag",
+ giving:
+ if (flag)
+ rather than:
+ if( flag)
+ These use MTIK_INSERT_BEFORE_NEXT.
+
+ Other symbols should go after the previous token, e.g. in:
+ if (flag
+ do_something ();
+ we want to insert the missing ')' immediately after the "flag",
+ giving:
+ if (flag)
+ do_something ();
+ rather than:
+ if (flag
+ )do_something ();
+ These use MTIK_INSERT_AFTER_PREV. */
+
+static enum missing_token_insertion_kind
+get_missing_token_insertion_kind (enum cpp_ttype type)
+{
+ switch (type)
+ {
+ /* Insert missing "opening" brackets immediately
+ before the next token. */
+ case CPP_OPEN_SQUARE:
+ case CPP_OPEN_PAREN:
+ return MTIK_INSERT_BEFORE_NEXT;
+
+ /* Insert other missing symbols immediately after
+ the previous token. */
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ case CPP_SEMICOLON:
+ case CPP_COMMA:
+ case CPP_COLON:
+ return MTIK_INSERT_AFTER_PREV;
+
+ /* Other kinds of token don't get fix-it hints. */
+ default:
+ return MTIK_IMPOSSIBLE;
+ }
+}
+
+/* Given RICHLOC, a location for a diagnostic describing a missing token
+ of kind TOKEN_TYPE, potentially add a fix-it hint suggesting the
+ insertion of the token.
+
+ The location of the attempted fix-it hint depends on TOKEN_TYPE:
+ it will either be:
+ (a) immediately after PREV_TOKEN_LOC, or
+
+ (b) immediately before the primary location within RICHLOC (taken to
+ be that of the token following where the token was expected).
+
+ If we manage to add a fix-it hint, then the location of the
+ fix-it hint is likely to be more useful as the primary location
+ of the diagnostic than that of the following token, so we swap
+ these locations.
+
+ For example, given this bogus code:
+ 123456789012345678901234567890
+ 1 | int missing_semicolon (void)
+ 2 | {
+ 3 | return 42
+ 4 | }
+
+ we will emit:
+
+ "expected ';' before '}'"
+
+ RICHLOC's primary location is at the closing brace, so before "swapping"
+ we would emit the error at line 4 column 1:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< fix-it hint emitted for this line
+ | ; |
+ 4 | } |< "expected ';' before '}'" emitted at this line
+ | ^ |
+
+ It's more useful for the location of the diagnostic to be at the
+ fix-it hint, so we swap the locations, so the primary location
+ is at the fix-it hint, with the old primary location inserted
+ as a secondary location, giving this, with the error at line 3
+ column 12:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< "expected ';' before '}'" emitted at this line,
+ | ^ | with fix-it hint
+ 4 | ; |
+ | } |< secondary range emitted here
+ | ~ |. */
+
+void
+maybe_suggest_missing_token_insertion (rich_location *richloc,
+ enum cpp_ttype token_type,
+ location_t prev_token_loc)
+{
+ gcc_assert (richloc);
+
+ enum missing_token_insertion_kind mtik
+ = get_missing_token_insertion_kind (token_type);
+
+ switch (mtik)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+
+ case MTIK_IMPOSSIBLE:
+ return;
+
+ case MTIK_INSERT_BEFORE_NEXT:
+ /* Attempt to add the fix-it hint before the primary location
+ of RICHLOC. */
+ richloc->add_fixit_insert_before (cpp_type2name (token_type, 0));
+ break;
+
+ case MTIK_INSERT_AFTER_PREV:
+ /* Attempt to add the fix-it hint after PREV_TOKEN_LOC. */
+ richloc->add_fixit_insert_after (prev_token_loc,
+ cpp_type2name (token_type, 0));
+ break;
+ }
+
+ /* If we were successful, use the fix-it hint's location as the
+ primary location within RICHLOC, adding the old primary location
+ back as a secondary location. */
+ if (!richloc->seen_impossible_fixit_p ())
+ {
+ fixit_hint *hint = richloc->get_last_fixit_hint ();
+ location_t hint_loc = hint->get_start_loc ();
+ location_t old_loc = richloc->get_loc ();
+
+ richloc->set_range (line_table, 0, hint_loc, true);
+ richloc->add_range (old_loc, false);
+ }
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the tests within c-family. */
+
+void
+c_family_tests (void)
+{
+ c_format_c_tests ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
+/* Attempt to locate a suitable location within FILE for a
+ #include directive to be inserted before. FILE should
+ be a string from libcpp (pointer equality is used).
+ LOC is the location of the relevant diagnostic.
+
+ Attempt to return the location within FILE immediately
+ after the last #include within that file, or the start of
+ that file if it has no #include directives.
+
+ Return UNKNOWN_LOCATION if no suitable location is found,
+ or if an error occurs. */
+
+static location_t
+try_to_locate_new_include_insertion_point (const char *file, location_t loc)
+{
+ /* Locate the last ordinary map within FILE that ended with a #include. */
+ const line_map_ordinary *last_include_ord_map = NULL;
+
+ /* ...and the next ordinary map within FILE after that one. */
+ const line_map_ordinary *last_ord_map_after_include = NULL;
+
+ /* ...and the first ordinary map within FILE. */
+ const line_map_ordinary *first_ord_map_in_file = NULL;
+
+ /* Get ordinary map containing LOC (or its expansion). */
+ const line_map_ordinary *ord_map_for_loc = NULL;
+ loc = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
+ &ord_map_for_loc);
+ gcc_assert (ord_map_for_loc);
+
+ for (unsigned int i = 0; i < LINEMAPS_ORDINARY_USED (line_table); i++)
+ {
+ const line_map_ordinary *ord_map
+ = LINEMAPS_ORDINARY_MAP_AT (line_table, i);
+
+ const line_map_ordinary *from = INCLUDED_FROM (line_table, ord_map);
+ if (from)
+ if (from->to_file == file)
+ {
+ last_include_ord_map = from;
+ last_ord_map_after_include = NULL;
+ }
+
+ if (ord_map->to_file == file)
+ {
+ if (!first_ord_map_in_file)
+ first_ord_map_in_file = ord_map;
+ if (last_include_ord_map && !last_ord_map_after_include)
+ last_ord_map_after_include = ord_map;
+ }
+
+ /* Stop searching when reaching the ord_map containing LOC,
+ as it makes no sense to provide fix-it hints that appear
+ after the diagnostic in question. */
+ if (ord_map == ord_map_for_loc)
+ break;
+ }
+
+ /* Determine where to insert the #include. */
+ const line_map_ordinary *ord_map_for_insertion;
+
+ /* We want the next ordmap in the file after the last one that's a
+ #include, but failing that, the start of the file. */
+ if (last_ord_map_after_include)
+ ord_map_for_insertion = last_ord_map_after_include;
+ else
+ ord_map_for_insertion = first_ord_map_in_file;
+
+ if (!ord_map_for_insertion)
+ return UNKNOWN_LOCATION;
+
+ /* The "start_location" is column 0, meaning "the whole line".
+ rich_location and edit_context can't cope with this, so use
+ column 1 instead. */
+ location_t col_0 = ord_map_for_insertion->start_location;
+ return linemap_position_for_loc_and_offset (line_table, col_0, 1);
+}
+
+/* A map from filenames to sets of headers added to them, for
+ ensuring idempotency within maybe_add_include_fixit. */
+
+/* The values within the map. We need string comparison as there's
+ no guarantee that two different diagnostics that are recommending
+ adding e.g. "<stdio.h>" are using the same buffer. */
+
+typedef hash_set <const char *, nofree_string_hash> per_file_includes_t;
+
+/* The map itself. We don't need string comparison for the filename keys,
+ as they come from libcpp. */
+
+typedef hash_map <const char *, per_file_includes_t *> added_includes_t;
+static added_includes_t *added_includes;
+
+/* Attempt to add a fix-it hint to RICHLOC, adding "#include HEADER\n"
+ in a suitable location within the file of RICHLOC's primary
+ location.
+
+ This function is idempotent: a header will be added at most once to
+ any given file. */
+
+void
+maybe_add_include_fixit (rich_location *richloc, const char *header)
+{
+ location_t loc = richloc->get_loc ();
+ const char *file = LOCATION_FILE (loc);
+ if (!file)
+ return;
+
+ /* Idempotency: don't add the same header more than once to a given file. */
+ if (!added_includes)
+ added_includes = new added_includes_t ();
+ per_file_includes_t *&set = added_includes->get_or_insert (file);
+ if (set)
+ if (set->contains (header))
+ /* ...then we've already added HEADER to that file. */
+ return;
+ if (!set)
+ set = new per_file_includes_t ();
+ set->add (header);
+
+ /* Attempt to locate a suitable place for the new directive. */
+ location_t include_insert_loc
+ = try_to_locate_new_include_insertion_point (file, loc);
+ if (include_insert_loc == UNKNOWN_LOCATION)
+ return;
+
+ char *text = xasprintf ("#include %s\n", header);
+ richloc->add_fixit_insert_before (include_insert_loc, text);
+ free (text);
+}
+
#include "gt-c-family-c-common.h"