#include "tm.h"
#include "intl.h"
#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "trans-mem.h"
#include "flags.h"
#include "c-pragma.h"
#include "ggc.h"
#include "diagnostic.h"
#include "tree-iterator.h"
#include "hashtab.h"
-#include "tree-mudflap.h"
#include "opts.h"
#include "cgraph.h"
#include "target-def.h"
+#include "gimple.h"
+#include "gimplify.h"
#include "wide-int-print.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
int, bool *);
static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree,
int, bool *);
+static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
+ bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_bnd_variable_size_attribute (tree *, tree, tree, int, bool *);
+static tree handle_bnd_legacy (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, int, tree *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
{
{ "_Alignas", RID_ALIGNAS, D_CONLY },
{ "_Alignof", RID_ALIGNOF, D_CONLY },
+ { "_Atomic", RID_ATOMIC, D_CONLY },
{ "_Bool", RID_BOOL, D_CONLY },
{ "_Complex", RID_COMPLEX, 0 },
+ { "_Cilk_spawn", RID_CILK_SPAWN, 0 },
+ { "_Cilk_sync", RID_CILK_SYNC, 0 },
{ "_Imaginary", RID_IMAGINARY, D_CONLY },
{ "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT },
{ "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT },
{ "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
{ "_Noreturn", RID_NORETURN, D_CONLY },
{ "_Generic", RID_GENERIC, D_CONLY },
+ { "_Thread_local", RID_THREAD, D_CONLY },
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 },
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__asm__", RID_ASM, 0 },
{ "__attribute", RID_ATTRIBUTE, 0 },
{ "__attribute__", RID_ATTRIBUTE, 0 },
+ { "__auto_type", RID_AUTO_TYPE, D_CONLY },
{ "__bases", RID_BASES, D_CXXONLY },
{ "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
{ "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
{ "no_sanitize_address", 0, 0, true, false, false,
handle_no_sanitize_address_attribute,
false },
+ { "no_sanitize_undefined", 0, 0, true, false, false,
+ handle_no_sanitize_undefined_attribute,
+ false },
{ "warning", 1, 1, true, false, false,
handle_error_attribute, false },
{ "error", 1, 1, true, false, false,
handle_fnspec_attribute, false },
{ "warn_unused", 0, 0, false, false, false,
handle_warn_unused_attribute, false },
+ { "returns_nonnull", 0, 0, false, true, true,
+ handle_returns_nonnull_attribute, false },
+ { "omp declare simd", 0, -1, true, false, false,
+ handle_omp_declare_simd_attribute, false },
+ { "omp declare target", 0, 0, true, false, false,
+ handle_omp_declare_target_attribute, false },
+ { "bnd_variable_size", 0, 0, true, false, false,
+ handle_bnd_variable_size_attribute, false },
+ { "bnd_legacy", 0, 0, true, false, false,
+ handle_bnd_legacy, false },
{ NULL, 0, 0, false, false, false, NULL, false }
};
for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved))
{
tree decl = TREE_PURPOSE (saved);
- unsigned ix = tree_to_hwi (TREE_VALUE (saved));
+ unsigned ix = TREE_INT_CST_LOW (TREE_VALUE (saved));
*fname_vars[ix].decl = decl;
}
"%q+D takes only zero or two arguments", decl);
}
+/* vector_targets_convertible_p is used for vector pointer types. The
+ callers perform various checks that the qualifiers are satisfactory,
+ while OTOH vector_targets_convertible_p ignores the number of elements
+ in the vectors. That's fine with vector pointers as we can consider,
+ say, a vector of 8 elements as two consecutive vectors of 4 elements,
+ and that does not require and conversion of the pointer values.
+ In contrast, vector_types_convertible_p and
+ vector_types_compatible_elements_p are used for vector value types. */
/* True if pointers to distinct types T1 and T2 can be converted to
each other without an explicit cast. Only returns true for opaque
vector types. */
return false;
}
+/* vector_types_convertible_p is used for vector value types.
+ It could in principle call vector_targets_convertible_p as a subroutine,
+ but then the check for vector type would be duplicated with its callers,
+ and also the purpose of vector_targets_convertible_p would become
+ muddled.
+ Where vector_types_convertible_p returns true, a conversion might still be
+ needed to make the types match.
+ In contrast, vector_targets_convertible_p is used for vector pointer
+ values, and vector_types_compatible_elements_p is used specifically
+ in the context for binary operators, as a check if use is possible without
+ conversion. */
/* True if vector types T1 and T2 can be converted to each other
without an explicit cast. If EMIT_LAX_NOTE is true, and T1 and T2
can only be converted with -flax-vector-conversions yet that is not
arg0 = c_common_get_narrower (op0, &unsigned0);
arg1 = c_common_get_narrower (op1, &unsigned1);
-
+
/* UNS is 1 if the operation to be done is an unsigned one. */
uns = TYPE_UNSIGNED (result_type);
}
/* Checks if expression EXPR of real/integer type cannot be converted
- to the real/integer type TYPE. Function returns true when:
+ to the real/integer type TYPE. Function returns non-zero when:
* EXPR is a constant which cannot be exactly converted to TYPE
* EXPR is not a constant and size of EXPR's type > than size of TYPE,
for EXPR type and TYPE being both integers or both real.
* EXPR is not a constant of integer type which cannot be
exactly converted to real type.
Function allows conversions between types of different signedness and
- does not return true in that case. Function can produce signedness
- warnings if PRODUCE_WARNS is true. */
-bool
+ can return SAFE_CONVERSION (zero) in that case. Function can produce
+ signedness warnings if PRODUCE_WARNS is true. */
+enum conversion_safety
unsafe_conversion_p (tree type, tree expr, bool produce_warns)
{
- bool give_warning = false;
+ enum conversion_safety give_warning = SAFE_CONVERSION; /* is 0 or false */
tree expr_type = TREE_TYPE (expr);
location_t loc = EXPR_LOC_OR_HERE (expr);
&& TREE_CODE (type) == INTEGER_TYPE)
{
if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
/* Warn for an integer constant that does not fit into integer type. */
else if (TREE_CODE (expr_type) == INTEGER_TYPE
" constant value to negative integer");
}
else
- give_warning = true;
+ give_warning = UNSAFE_OTHER;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
{
REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
/* Warn for a real constant that does not fit into a smaller
real type. */
{
REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
}
}
/* Warn for real types converted to integer types. */
if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
- give_warning = true;
+ give_warning = UNSAFE_REAL;
else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
&& int_fits_type_p (op1, c_common_signed_type (type))
&& int_fits_type_p (op1,
c_common_unsigned_type (type))))
- return false;
+ return SAFE_CONVERSION;
/* If constant is unsigned and fits in the target
type, then the result will also fit. */
else if ((TREE_CODE (op0) == INTEGER_CST
|| (TREE_CODE (op1) == INTEGER_CST
&& unsigned1
&& int_fits_type_p (op1, type)))
- return false;
+ return SAFE_CONVERSION;
}
}
/* Warn for integer types converted to smaller integer types. */
if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
- give_warning = true;
+ give_warning = UNSAFE_OTHER;
/* When they are the same width but different signedness,
then the value may change. */
if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
|| !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
- give_warning = true;
+ give_warning = UNSAFE_OTHER;
}
/* Warn for real types converted to smaller real types. */
else if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == REAL_TYPE
&& TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
return give_warning;
{
tree expr_type = TREE_TYPE (expr);
location_t loc = EXPR_LOC_OR_HERE (expr);
+ enum conversion_safety conversion_kind;
- if (!warn_conversion && !warn_sign_conversion)
+ if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
return;
switch (TREE_CODE (expr))
case REAL_CST:
case INTEGER_CST:
- if (unsafe_conversion_p (type, expr, true))
+ conversion_kind = unsafe_conversion_p (type, expr, true);
+ if (conversion_kind == UNSAFE_REAL)
+ warning_at (loc, OPT_Wfloat_conversion,
+ "conversion to %qT alters %qT constant value",
+ type, expr_type);
+ else if (conversion_kind)
warning_at (loc, OPT_Wconversion,
"conversion to %qT alters %qT constant value",
type, expr_type);
}
default: /* 'expr' is not a constant. */
- if (unsafe_conversion_p (type, expr, true))
+ conversion_kind = unsafe_conversion_p (type, expr, true);
+ if (conversion_kind == UNSAFE_REAL)
+ warning_at (loc, OPT_Wfloat_conversion,
+ "conversion to %qT from %qT may alter its value",
+ type, expr_type);
+ else if (conversion_kind)
warning_at (loc, OPT_Wconversion,
"conversion to %qT from %qT may alter its value",
type, expr_type);
if (mode == DImode)
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
-
+
#if HOST_BITS_PER_WIDE_INT >= 64
if (mode == TYPE_MODE (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
/* If one of the operands must be floated, we cannot optimize. */
real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
-
+
/* If first arg is constant, swap the args (changing operation
so value is preserved), for canonicalization. Don't do this if
the second arg is 0. */
/* Convert primop1 to target type, but do not introduce
additional overflow. We know primop1 is an int_cst. */
primop1 = force_fit_type (*restype_ptr,
- wide_int (primop1).force_to_size (TYPE_PRECISION (*restype_ptr),
- TYPE_SIGN (TREE_TYPE (primop1))),
+ wide_int::from
+ (primop1,
+ TYPE_PRECISION (*restype_ptr),
+ TYPE_SIGN (TREE_TYPE (primop1))),
0, TREE_OVERFLOW (primop1));
}
if (type != *restype_ptr)
maxval = convert (*restype_ptr, maxval);
}
- if (unsignedp && unsignedp0)
- {
- min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
- max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
- min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
- max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
- }
- else
- {
- min_gt = INT_CST_LT (primop1, minval);
- max_gt = INT_CST_LT (primop1, maxval);
- min_lt = INT_CST_LT (minval, primop1);
- max_lt = INT_CST_LT (maxval, primop1);
- }
+ min_gt = INT_CST_LT (primop1, minval);
+ max_gt = INT_CST_LT (primop1, maxval);
+ min_lt = INT_CST_LT (minval, primop1);
+ max_lt = INT_CST_LT (maxval, primop1);
val = 0;
/* This used to be a switch, but Genix compiler can't handle that. */
case ERROR_MARK:
return expr;
-
+
case INTEGER_CST:
return integer_zerop (expr) ? truthvalue_false_node
: truthvalue_true_node;
if (TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST)
size = 0;
else
- size = tree_to_hwi (TYPE_SIZE (t));
+ size = TREE_INT_CST_LOW (TYPE_SIZE (t));
return ((size << 24) | (n_elements << shift));
}
/* 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. */
-
+
alias_set_type
c_common_get_alias_set (tree t)
{
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
ARG6, ARG7) \
def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) \
+ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8);
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
def_fn_type (ENUM, RETURN, 1, 0);
#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
build_common_builtin_nodes ();
- if (flag_mudflap)
- mudflap_init ();
+ if (flag_enable_cilkplus)
+ cilk_init_builtins ();
}
/* Like get_identifier, but avoid warnings about null arguments when
}
/* This node must not be shared. */
- void_zero_node = make_int_cst (1);
+ void_zero_node = make_int_cst (1, 1);
TREE_TYPE (void_zero_node) = void_type_node;
void_list_node = build_void_list_node ();
(build_decl (UNKNOWN_LOCATION,
TYPE_DECL, get_identifier (pname),
ptype));
-
+
}
}
/* Create the built-in __null node. It is important that this is
not shared. */
- null_node = make_int_cst (1);
+ null_node = make_int_cst (1, 1);
TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
/* Since builtin_types isn't gc'ed, don't export these nodes. */
{
char buf[WIDE_INT_PRINT_BUFFER_SIZE];
- if (tree_fits_hwi_p (key, TYPE_SIGN (type)))
- print_dec (key, buf, TYPE_SIGN (type));
+ if (tree_fits_uhwi_p (key))
+ print_dec (key, buf, UNSIGNED);
+ else if (tree_fits_shwi_p (key))
+ print_dec (key, buf, SIGNED);
else
print_hex (key, buf);
return NULL_TREE;
}
+/* Handle a "no_sanitize_undefined" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "noinline" attribute; arguments as in
struct attribute_spec.handler. */
tree ident = TREE_VALUE (args);
*no_add_attrs = true;
-
+
if (TREE_CODE (ident) != IDENTIFIER_NODE)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
for (; args; args = TREE_CHAIN (args))
{
tree position = TREE_VALUE (args);
- wide_int p;
if (TREE_CODE (position) != INTEGER_CST
- || (p = wide_int (position)).ltu_p (1)
- || p.gtu_p (arg_count) )
+ || wi::ltu_p (position, 1)
+ || wi::gtu_p (position, arg_count))
{
warning (OPT_Wattributes,
"alloc_size parameter outside range");
return NULL_TREE;
}
+/* Handle a "bnd_variable_size" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_bnd_variable_size_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FIELD_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "bnd_legacy" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_bnd_legacy (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "warn_unused" attribute; arguments as in
struct attribute_spec.handler. */
return NULL_TREE;
}
+/* Handle an "omp declare simd" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
+{
+ return NULL_TREE;
+}
+
+/* Handle an "omp declare target" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *)
+{
+ return NULL_TREE;
+}
+
/* Handle a "returns_twice" attribute; arguments as in
struct attribute_spec.handler. */
if (TREE_VALUE (attr))
{
tree p = TREE_VALUE (TREE_VALUE (attr));
- pos = tree_to_hwi (p);
+ pos = TREE_INT_CST_LOW (p);
}
/* The sentinel must be one of the varargs, i.e.
/* Verify the arg number is a small constant. */
if (cst_fits_uhwi_p (arg_num_expr))
{
- *valp = tree_to_hwi (arg_num_expr);
+ *valp = TREE_INT_CST_LOW (arg_num_expr);
return true;
}
else
if (TREE_CODE (value) == INTEGER_CST)
{
char buffer[20];
- sprintf (buffer, "-O%ld", (long) tree_to_hwi (value));
+ sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
vec_safe_push (optimize_args, ggc_strdup (buffer));
}
/* Parse options, and update the vector. */
parse_optimize_options (args, true);
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
- = build_optimization_node ();
+ = build_optimization_node (&global_options);
/* Restore current options. */
cl_optimization_restore (&global_options, &cur_opts);
return NULL_TREE;
}
+
+/* Handle a "returns_nonnull" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_nonnull_attribute (tree *node, tree, tree, int,
+ bool *no_add_attrs)
+{
+ // Even without a prototype we still have a return type we can check.
+ if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE)
+ {
+ error ("returns_nonnull attribute on a function not returning a pointer");
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
\f
/* Check for valid arguments being passed to a function with FNTYPE.
There are NARGS arguments in the array ARGARRAY. */
to be valid. */
format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
- gcc_assert (tree_fits_uhwi_p (format_num_expr));
-
format_num = tree_to_uhwi (format_num_expr);
for (inner_arg = first_call_expr_arg (param, &iter), i = 1;
|| token_type == CPP_CHAR16
|| token_type == CPP_CHAR32)
{
- unsigned int val = tree_to_hwi (value);
+ unsigned int val = TREE_INT_CST_LOW (value);
const char *prefix;
switch (token_type)
{CPP_W_INVALID_PCH, OPT_Winvalid_pch},
{CPP_W_WARNING_DIRECTIVE, OPT_Wcpp},
{CPP_W_LITERAL_SUFFIX, OPT_Wliteral_suffix},
+ {CPP_W_DATE_TIME, OPT_Wdate_time},
{CPP_W_NONE, 0}
};
how ARG was being used. */
void
-readonly_error (tree arg, enum lvalue_use use)
+readonly_error (location_t loc, tree arg, enum lvalue_use use)
{
gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
|| use == lv_asm);
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- error (READONLY_MSG (G_("assignment of member "
- "%qD in read-only object"),
- G_("increment of member "
- "%qD in read-only object"),
- G_("decrement of member "
- "%qD in read-only object"),
- G_("member %qD in read-only object "
- "used as %<asm%> output")),
- TREE_OPERAND (arg, 1));
+ error_at (loc, READONLY_MSG (G_("assignment of member "
+ "%qD in read-only object"),
+ G_("increment of member "
+ "%qD in read-only object"),
+ G_("decrement of member "
+ "%qD in read-only object"),
+ G_("member %qD in read-only object "
+ "used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
else
- error (READONLY_MSG (G_("assignment of read-only member %qD"),
- G_("increment of read-only member %qD"),
- G_("decrement of read-only member %qD"),
- G_("read-only member %qD used as %<asm%> output")),
- TREE_OPERAND (arg, 1));
+ error_at (loc, READONLY_MSG (G_("assignment of read-only member %qD"),
+ G_("increment of read-only member %qD"),
+ G_("decrement of read-only member %qD"),
+ G_("read-only member %qD used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
}
else if (TREE_CODE (arg) == VAR_DECL)
- error (READONLY_MSG (G_("assignment of read-only variable %qD"),
- G_("increment of read-only variable %qD"),
- G_("decrement of read-only variable %qD"),
- G_("read-only variable %qD used as %<asm%> output")),
- arg);
+ error_at (loc, READONLY_MSG (G_("assignment of read-only variable %qD"),
+ G_("increment of read-only variable %qD"),
+ G_("decrement of read-only variable %qD"),
+ G_("read-only variable %qD used as %<asm%> output")),
+ arg);
else if (TREE_CODE (arg) == PARM_DECL)
- error (READONLY_MSG (G_("assignment of read-only parameter %qD"),
- G_("increment of read-only parameter %qD"),
- G_("decrement of read-only parameter %qD"),
- G_("read-only parameter %qD use as %<asm%> output")),
- arg);
+ error_at (loc, READONLY_MSG (G_("assignment of read-only parameter %qD"),
+ G_("increment of read-only parameter %qD"),
+ G_("decrement of read-only parameter %qD"),
+ G_("read-only parameter %qD use as %<asm%> output")),
+ arg);
else if (TREE_CODE (arg) == RESULT_DECL)
{
gcc_assert (c_dialect_cxx ());
- error (READONLY_MSG (G_("assignment of "
- "read-only named return value %qD"),
- G_("increment of "
- "read-only named return value %qD"),
- G_("decrement of "
- "read-only named return value %qD"),
- G_("read-only named return value %qD "
- "used as %<asm%>output")),
- arg);
+ error_at (loc, READONLY_MSG (G_("assignment of "
+ "read-only named return value %qD"),
+ G_("increment of "
+ "read-only named return value %qD"),
+ G_("decrement of "
+ "read-only named return value %qD"),
+ G_("read-only named return value %qD "
+ "used as %<asm%>output")),
+ arg);
}
else if (TREE_CODE (arg) == FUNCTION_DECL)
- error (READONLY_MSG (G_("assignment of function %qD"),
- G_("increment of function %qD"),
- G_("decrement of function %qD"),
- G_("function %qD used as %<asm%> output")),
- arg);
+ error_at (loc, READONLY_MSG (G_("assignment of function %qD"),
+ G_("increment of function %qD"),
+ G_("decrement of function %qD"),
+ G_("function %qD used as %<asm%> output")),
+ arg);
else
- error (READONLY_MSG (G_("assignment of read-only location %qE"),
- G_("increment of read-only location %qE"),
- G_("decrement of read-only location %qE"),
- G_("read-only location %qE used as %<asm%> output")),
- arg);
+ error_at (loc, READONLY_MSG (G_("assignment of read-only location %qE"),
+ G_("increment of read-only location %qE"),
+ G_("decrement of read-only location %qE"),
+ G_("read-only location %qE used as %<asm%> output")),
+ arg);
}
/* Print an error message for an invalid lvalue. USE says
"invalid type argument of %<->%> (have %qT)",
type);
break;
+ case RO_ARROW_STAR:
+ error_at (loc,
+ "invalid type argument of %<->*%> (have %qT)",
+ type);
+ break;
case RO_IMPLICIT_CONVERSION:
error_at (loc,
"invalid type argument of implicit conversion (have %qT)",
{
error ("size of array is too large");
/* If we proceed with the array type as it is, we'll eventually
- crash in tree_to_uhwi(). */
+ crash in tree_to_[su]hwi(). */
type = error_mark_node;
}
call to check_function_arguments what ever type the user used. */
function_args_iter_next (&iter);
ptype = TREE_TYPE (TREE_TYPE ((*params)[0]));
+ ptype = TYPE_MAIN_VARIANT (ptype);
/* For the rest of the values, we need to cast these to FTYPE, so that we
don't get warnings for passing pointer types, etc. */
}
+/* Return whether atomic operations for naturally aligned N-byte
+ arguments are supported, whether inline or through libatomic. */
+static bool
+atomic_size_supported_p (int n)
+{
+ switch (n)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return true;
+
+ case 16:
+ return targetm.scalar_mode_supported_p (TImode);
+
+ default:
+ return false;
+ }
+}
+
/* This will process an __atomic_exchange function call, determine whether it
needs to be mapped to the _N variation, or turned into a library call.
LOC is the location of the builtin call.
}
/* If not a lock-free size, change to the library generic format. */
- if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16)
+ if (!atomic_size_supported_p (n))
{
*new_return = add_atomic_size_parameter (n, loc, function, params);
return true;
}
/* If not a lock-free size, change to the library generic format. */
- if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16)
+ if (!atomic_size_supported_p (n))
{
/* The library generic format does not have the weak parameter, so
remove it from the param list. Since a parameter has been removed,
bool fn(T* mem, T* desired, T* return, weak, success, failure)
into
bool fn ((In *)mem, (In *)expected, (In) *desired, weak, succ, fail) */
-
+
p0 = (*params)[0];
p1 = (*params)[1];
p2 = (*params)[2];
}
/* If not a lock-free size, change to the library generic format. */
- if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16)
+ if (!atomic_size_supported_p (n))
{
*new_return = add_atomic_size_parameter (n, loc, function, params);
return true;
}
/* If not a lock-free size, change to the library generic format. */
- if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16)
+ if (!atomic_size_supported_p (n))
{
*new_return = add_atomic_size_parameter (n, loc, function, params);
return true;
}
}
-/* Ignoring their sign, return true if two scalar types are the same. */
+/* vector_types_compatible_elements_p is used in type checks of vectors
+ values used as operands of binary operators. Where it returns true, and
+ the other checks of the caller succeed (being vector types in he first
+ place, and matching number of elements), we can just treat the types
+ as essentially the same.
+ Contrast with vector_targets_convertible_p, which is used for vector
+ pointer types, and vector_types_convertible_p, which will allow
+ language-specific matches under the control of flag_lax_vector_conversions,
+ and might still require a conversion. */
+/* True if vector types T1 and T2 can be inputs to the same binary
+ operator without conversion.
+ We don't check the overall vector size here because some of our callers
+ want to give different error messages when the vectors are compatible
+ except for the element count. */
+
bool
-same_scalar_type_ignoring_signedness (tree t1, tree t2)
+vector_types_compatible_elements_p (tree t1, tree t2)
{
+ bool opaque = TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2);
+ t1 = TREE_TYPE (t1);
+ t2 = TREE_TYPE (t2);
+
enum tree_code c1 = TREE_CODE (t1), c2 = TREE_CODE (t2);
gcc_assert ((c1 == INTEGER_TYPE || c1 == REAL_TYPE || c1 == FIXED_POINT_TYPE)
&& (c2 == INTEGER_TYPE || c2 == REAL_TYPE
|| c2 == FIXED_POINT_TYPE));
+ t1 = c_common_signed_type (t1);
+ t2 = c_common_signed_type (t2);
/* Equality works here because c_common_signed_type uses
TYPE_MAIN_VARIANT. */
- return c_common_signed_type (t1)
- == c_common_signed_type (t2);
+ if (t1 == t2)
+ return true;
+ if (opaque && c1 == c2
+ && (c1 == INTEGER_TYPE || c1 == REAL_TYPE)
+ && TYPE_PRECISION (t1) == TYPE_PRECISION (t2))
+ return true;
+ return false;
}
/* Check for missing format attributes on function pointers. LTYPE is
early on, later parts of the compiler can always do the reverse
translation and get back the corresponding typedef name. For
example, given:
-
+
typedef struct S MY_TYPE;
MY_TYPE object;
{
switch (keyword)
{
+ case RID_AUTO_TYPE:
case RID_INT:
case RID_CHAR:
case RID_FLOAT:
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
+ case RID_ATOMIC:
return true;
default:
return false;
if (TREE_CODE (index) == INTEGER_CST)
if (!tree_fits_uhwi_p (index)
- || ((unsigned HOST_WIDE_INT) tree_to_uhwi (index)
- >= TYPE_VECTOR_SUBPARTS (type)))
+ || tree_to_uhwi (index) >= TYPE_VECTOR_SUBPARTS (type))
warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
c_common_mark_addressable_vec (*vecp);