static int function_types_compatible_p (const_tree, const_tree);
static int type_lists_compatible_p (const_tree, const_tree);
static tree lookup_field (tree, tree);
-static int convert_arguments (int, tree *, tree, tree, tree, tree);
+static int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree,
+ tree);
static tree pointer_diff (tree, tree);
-static tree convert_for_assignment (tree, tree, enum impl_conv, bool,
+static tree convert_for_assignment (tree, tree, tree, enum impl_conv, bool,
tree, tree, int);
static tree valid_compound_expr_initializer (tree, tree);
static void push_string (const char *);
static int spelling_length (void);
static char *print_spelling (char *);
static void warning_init (int, const char *);
-static tree digest_init (tree, tree, bool, bool, int);
-static void output_init_element (tree, bool, tree, tree, int, bool);
+static tree digest_init (tree, tree, tree, bool, bool, int);
+static void output_init_element (tree, tree, bool, tree, tree, int, bool);
static void output_pending_init_elements (int);
static int set_designator (int);
static void push_range_stack (tree);
-static void add_pending_init (tree, tree, bool);
+static void add_pending_init (tree, tree, tree, bool);
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
static void readonly_error (tree, enum lvalue_use);
+static void readonly_warning (tree, enum lvalue_use);
static int lvalue_or_else (const_tree, enum lvalue_use);
-static int lvalue_p (const_tree);
static void record_maybe_used_decl (tree);
static int comptypes_internal (const_tree, const_tree);
\f
return ret;
}
+/* Having checked whether EXPR may appear in an unevaluated part of an
+ integer constant expression and found that it may, remove any
+ C_MAYBE_CONST_EXPR noting this fact and return the resulting
+ expression. */
+
+static inline tree
+remove_c_maybe_const_expr (tree expr)
+{
+ if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
+ return C_MAYBE_CONST_EXPR_EXPR (expr);
+ else
+ return expr;
+}
+
\f/* This is a cache to hold if two types are compatible or not. */
struct tagged_tu_seen_cache {
\f
/* Build an external reference to identifier ID. FUN indicates
whether this will be used for a function call. LOC is the source
- location of the identifier. */
+ location of the identifier. This sets *TYPE to the type of the
+ identifier, which is not the same as the type of the returned value
+ for CONST_DECLs defined as enum constants. If the type of the
+ identifier is not available, *TYPE is set to NULL. */
tree
-build_external_ref (tree id, int fun, location_t loc)
+build_external_ref (tree id, int fun, location_t loc, tree *type)
{
tree ref;
tree decl = lookup_name (id);
whatever lookup_name() found. */
decl = objc_lookup_ivar (decl, id);
+ *type = NULL;
if (decl && decl != error_mark_node)
- ref = decl;
+ {
+ ref = decl;
+ *type = TREE_TYPE (ref);
+ }
else if (fun)
/* Implicit function declaration. */
ref = implicitly_declare (id);
&& (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref))
&& ! TREE_PUBLIC (ref)
&& DECL_CONTEXT (ref) != current_function_decl)
- pedwarn (loc, 0, "%qD is static but used in inline function %qD "
- "which is not static", ref, current_function_decl);
+ record_inline_static (loc, current_function_decl, ref,
+ csi_internal);
return ref;
}
{
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
pop_maybe_used (false);
}
else
&expr_const_operands);
ret.value = c_sizeof (TREE_TYPE (folded_expr));
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (c_vla_type_p (TREE_TYPE (folded_expr)))
{
/* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */
type = groktypename (t, &type_expr, &type_expr_const);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
- if (type_expr && c_vla_type_p (type))
- {
+ ret.original_type = NULL;
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && c_vla_type_p (type))
+ {
+ /* If the type is a [*] array, it is a VLA but is represented as
+ having a size of zero. In such a case we must ensure that
+ the result of sizeof does not get folded to a constant by
+ c_fully_fold, because if the size is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this sizeof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
type_expr, ret.value);
C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
tree
build_function_call (tree function, tree params)
{
+ VEC(tree,gc) *vec;
+ tree ret;
+
+ vec = VEC_alloc (tree, gc, list_length (params));
+ for (; params; params = TREE_CHAIN (params))
+ VEC_quick_push (tree, vec, TREE_VALUE (params));
+ ret = build_function_call_vec (function, vec, NULL);
+ VEC_free (tree, gc, vec);
+ return ret;
+}
+
+/* Build a function call to function FUNCTION with parameters PARAMS.
+ ORIGTYPES, if not NULL, is a vector of types; each element is
+ either NULL or the original type of the corresponding element in
+ PARAMS. The original type may differ from TREE_TYPE of the
+ parameter for enums. FUNCTION's data type may be a function type
+ or pointer-to-function. This function changes the elements of
+ PARAMS. */
+
+tree
+build_function_call_vec (tree function, VEC(tree,gc) *params,
+ VEC(tree,gc) *origtypes)
+{
tree fntype, fundecl = 0;
tree name = NULL_TREE, result;
tree tem;
/* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
expressions, like those used for ObjC messenger dispatches. */
- function = objc_rewrite_function_call (function, params);
+ if (!VEC_empty (tree, params))
+ function = objc_rewrite_function_call (function,
+ VEC_index (tree, params, 0));
function = c_fully_fold (function, false, NULL);
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
- nargs = list_length (params);
- argarray = (tree *) alloca (nargs * sizeof (tree));
- nargs = convert_arguments (nargs, argarray, TYPE_ARG_TYPES (fntype),
- params, function, fundecl);
+ nargs = convert_arguments (TYPE_ARG_TYPES (fntype), params, origtypes,
+ function, fundecl);
if (nargs < 0)
return error_mark_node;
/* Before the abort, allow the function arguments to exit or
call longjmp. */
for (i = 0; i < nargs; i++)
- trap = build2 (COMPOUND_EXPR, void_type_node, argarray[i], trap);
+ trap = build2 (COMPOUND_EXPR, void_type_node,
+ VEC_index (tree, params, i), trap);
if (VOID_TYPE_P (return_type))
- return trap;
+ {
+ if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED)
+ pedwarn (input_location, 0,
+ "function with qualified void return type called");
+ return trap;
+ }
else
{
tree rhs;
else
rhs = fold_convert (return_type, integer_zero_node);
- return build2 (COMPOUND_EXPR, return_type, trap, rhs);
+ return require_complete_type (build2 (COMPOUND_EXPR, return_type,
+ trap, rhs));
}
}
+ argarray = VEC_address (tree, params);
+
/* Check that arguments to builtin functions match the expectations. */
if (fundecl
&& DECL_BUILT_IN (fundecl)
function, nargs, argarray);
if (VOID_TYPE_P (TREE_TYPE (result)))
- return result;
+ {
+ if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED)
+ pedwarn (input_location, 0,
+ "function with qualified void return type called");
+ return result;
+ }
return require_complete_type (result);
}
\f
-/* Convert the argument expressions in the list VALUES
- to the types in the list TYPELIST. The resulting arguments are
- stored in the array ARGARRAY which has size NARGS.
+/* Convert the argument expressions in the vector VALUES
+ to the types in the list TYPELIST.
If TYPELIST is exhausted, or when an element has NULL as its type,
perform the default conversions.
- PARMLIST is the chain of parm decls for the function being called.
- It may be 0, if that info is not available.
- It is used only for generating error messages.
+ ORIGTYPES is the original types of the expressions in VALUES. This
+ holds the type of enum values which have been converted to integral
+ types. It may be NULL.
FUNCTION is a tree for the called function. It is used only for
error messages, where it is formatted with %qE.
This is also where warnings about wrong number of args are generated.
- VALUES is a chain of TREE_LIST nodes with the elements of the list
- in the TREE_VALUE slots of those nodes.
-
Returns the actual number of arguments processed (which may be less
- than NARGS in some error situations), or -1 on failure. */
+ than the length of VALUES in some error situations), or -1 on
+ failure. */
static int
-convert_arguments (int nargs, tree *argarray,
- tree typelist, tree values, tree function, tree fundecl)
+convert_arguments (tree typelist, VEC(tree,gc) *values,
+ VEC(tree,gc) *origtypes, tree function, tree fundecl)
{
- tree typetail, valtail;
- int parmnum;
+ tree typetail, val;
+ unsigned int parmnum;
const bool type_generic = fundecl
&& lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl)));
+ bool type_generic_remove_excess_precision = false;
tree selector;
/* Change pointer to function to the function itself for
/* Handle an ObjC selector specially for diagnostics. */
selector = objc_message_selector ();
+ /* For type-generic built-in functions, determine whether excess
+ precision should be removed (classification) or not
+ (comparison). */
+ if (type_generic
+ && DECL_BUILT_IN (fundecl)
+ && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL)
+ {
+ switch (DECL_FUNCTION_CODE (fundecl))
+ {
+ case BUILT_IN_ISFINITE:
+ case BUILT_IN_ISINF:
+ case BUILT_IN_ISINF_SIGN:
+ case BUILT_IN_ISNAN:
+ case BUILT_IN_ISNORMAL:
+ case BUILT_IN_FPCLASSIFY:
+ type_generic_remove_excess_precision = true;
+ break;
+
+ default:
+ type_generic_remove_excess_precision = false;
+ break;
+ }
+ }
+
/* Scan the given expressions and types, producing individual
- converted arguments and storing them in ARGARRAY. */
+ converted arguments. */
- for (valtail = values, typetail = typelist, parmnum = 0;
- valtail;
- valtail = TREE_CHAIN (valtail), parmnum++)
+ for (typetail = typelist, parmnum = 0;
+ VEC_iterate (tree, values, parmnum, val);
+ ++parmnum)
{
tree type = typetail ? TREE_VALUE (typetail) : 0;
- tree val = TREE_VALUE (valtail);
+ tree valtype = TREE_TYPE (val);
tree rname = function;
int argnum = parmnum + 1;
const char *invalid_func_diag;
+ bool excess_precision = false;
bool npc;
+ tree parmval;
if (type == void_type_node)
{
}
npc = null_pointer_constant_p (val);
+
+ /* If there is excess precision and a prototype, convert once to
+ the required type rather than converting via the semantic
+ type. Likewise without a prototype a float value represented
+ as long double should be converted once to double. But for
+ type-generic classification functions excess precision must
+ be removed here. */
+ if (TREE_CODE (val) == EXCESS_PRECISION_EXPR
+ && (type || !type_generic || !type_generic_remove_excess_precision))
+ {
+ val = TREE_OPERAND (val, 0);
+ excess_precision = true;
+ }
val = c_fully_fold (val, false, NULL);
STRIP_TYPE_NOPS (val);
if (type != 0)
{
/* Formal parm type is specified by a function prototype. */
- tree parmval;
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
{
}
else
{
+ tree origtype;
+
/* Optionally warn about conversions that
differ from the default conversions. */
if (warn_traditional_conversion || warn_traditional)
unsigned int formal_prec = TYPE_PRECISION (type);
if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
warning (0, "passing argument %d of %qE as integer "
"rather than floating due to prototype",
argnum, rname);
if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ && TREE_CODE (valtype) == COMPLEX_TYPE)
warning (0, "passing argument %d of %qE as integer "
"rather than complex due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
warning (0, "passing argument %d of %qE as complex "
"rather than floating due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
warning (0, "passing argument %d of %qE as floating "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
warning (0, "passing argument %d of %qE as complex "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ && TREE_CODE (valtype) == COMPLEX_TYPE)
warning (0, "passing argument %d of %qE as floating "
"rather than complex due to prototype",
argnum, rname);
conversions between complex types, but that's too messy
to do now. */
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
{
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
for decimal float types. Warn of conversions with
binary float types and of precision narrowing due to
prototype. */
- else if (type != TREE_TYPE (val)
+ else if (type != valtype
&& (type == dfloat32_type_node
|| type == dfloat64_type_node
|| type == dfloat128_type_node
- || TREE_TYPE (val) == dfloat32_type_node
- || TREE_TYPE (val) == dfloat64_type_node
- || TREE_TYPE (val) == dfloat128_type_node)
+ || valtype == dfloat32_type_node
+ || valtype == dfloat64_type_node
+ || valtype == dfloat128_type_node)
&& (formal_prec
- <= TYPE_PRECISION (TREE_TYPE (val))
+ <= TYPE_PRECISION (valtype)
|| (type == dfloat128_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat64_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat32_type_node)))
|| (type == dfloat64_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat32_type_node))))
warning (0, "passing argument %d of %qE as %qT "
"rather than %qT due to prototype",
- argnum, rname, type, TREE_TYPE (val));
+ argnum, rname, type, valtype);
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
-Wtraditional-conversion, not with -Wtraditional. */
else if (warn_traditional_conversion && INTEGRAL_TYPE_P (type)
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
{
tree would_have_been = default_conversion (val);
tree type1 = TREE_TYPE (would_have_been);
if (TREE_CODE (type) == ENUMERAL_TYPE
&& (TYPE_MAIN_VARIANT (type)
- == TYPE_MAIN_VARIANT (TREE_TYPE (val))))
+ == TYPE_MAIN_VARIANT (valtype)))
/* No warning if function asks for enum
and the actual arg is that enum type. */
;
unsigned type, it doesn't matter whether we
pass it as signed or unsigned; the value
certainly is the same either way. */
- else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type)
- && TYPE_UNSIGNED (TREE_TYPE (val)))
+ else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type)
+ && TYPE_UNSIGNED (valtype))
;
else if (TYPE_UNSIGNED (type))
warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
}
}
- parmval = convert_for_assignment (type, val, ic_argpass, npc,
+ /* Possibly restore an EXCESS_PRECISION_EXPR for the
+ sake of better warnings from convert_and_check. */
+ if (excess_precision)
+ val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
+ origtype = (origtypes == NULL
+ ? NULL_TREE
+ : VEC_index (tree, origtypes, parmnum));
+ parmval = convert_for_assignment (type, val, origtype,
+ ic_argpass, npc,
fundecl, function,
parmnum + 1);
&& (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
}
- argarray[parmnum] = parmval;
}
- else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (val))
+ else if (TREE_CODE (valtype) == REAL_TYPE
+ && (TYPE_PRECISION (valtype)
< TYPE_PRECISION (double_type_node))
- && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
+ && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
{
if (type_generic)
- argarray[parmnum] = val;
+ parmval = val;
else
/* Convert `float' to `double'. */
- argarray[parmnum] = convert (double_type_node, val);
+ parmval = convert (double_type_node, val);
}
+ else if (excess_precision && !type_generic)
+ /* A "double" argument with excess precision being passed
+ without a prototype or in variable arguments. */
+ parmval = convert (valtype, val);
else if ((invalid_func_diag =
targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
{
}
else
/* Convert `short' and `char' to full-size `int'. */
- argarray[parmnum] = default_conversion (val);
+ parmval = default_conversion (val);
+
+ VEC_replace (tree, values, parmnum, parmval);
if (typetail)
typetail = TREE_CHAIN (typetail);
}
- gcc_assert (parmnum == nargs);
+ gcc_assert (parmnum == VEC_length (tree, values));
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
result.value = build_unary_op (loc, code, arg.value, 0);
result.original_code = code;
-
+ result.original_type = NULL;
+
if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
overflow_warning (result.value);
enum tree_code code1 = arg1.original_code;
enum tree_code code2 = arg2.original_code;
+ tree type1 = (arg1.original_type
+ ? arg1.original_type
+ : TREE_TYPE (arg1.value));
+ tree type2 = (arg2.original_type
+ ? arg2.original_type
+ : TREE_TYPE (arg2.value));
result.value = build_binary_op (location, code,
arg1.value, arg2.value, 1);
result.original_code = code;
+ result.original_type = NULL;
if (TREE_CODE (result.value) == ERROR_MARK)
return result;
if (warn_parentheses)
warn_about_parentheses (code, code1, arg1.value, code2, arg2.value);
- if (TREE_CODE_CLASS (code1) != tcc_comparison)
- warn_logical_operator (code, arg1.value, arg2.value);
+ if (warn_logical_op)
+ warn_logical_operator (input_location, code,
+ code1, arg1.value, code2, arg2.value);
/* Warn about comparisons against string literals, with the exception
of testing for equality or inequality of a string literal with NULL. */
&& !TREE_OVERFLOW_P (arg2.value))
overflow_warning (result.value);
+ /* Warn about comparisons of different enum types. */
+ if (warn_enum_compare
+ && TREE_CODE_CLASS (code) == tcc_comparison
+ && TREE_CODE (type1) == ENUMERAL_TYPE
+ && TREE_CODE (type2) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
+ warning_at (location, OPT_Wenum_compare,
+ "comparison between %qT and %qT",
+ type1, type2);
+
return result;
}
\f
enum tree_code typecode;
tree val;
tree ret = error_mark_node;
+ tree eptype = NULL_TREE;
int noconvert = flag;
const char *invalid_op_diag;
bool int_operands;
int_operands = EXPR_INT_CONST_OPERANDS (xarg);
+ if (int_operands)
+ arg = remove_c_maybe_const_expr (arg);
if (code != ADDR_EXPR)
arg = require_complete_type (arg);
return error_mark_node;
}
+ if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (arg);
+ arg = TREE_OPERAND (arg, 0);
+ }
+
switch (code)
{
case CONVERT_EXPR:
}
arg = c_objc_common_truthvalue_conversion (location, arg);
ret = invert_truthvalue (arg);
+ /* If the TRUTH_NOT_EXPR has been folded, reset the location. */
+ if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret))
+ location = EXPR_LOCATION (ret);
goto return_build_unary_op;
case REALPART_EXPR:
ret = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
ret = arg;
+ if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
+ eptype = TREE_TYPE (eptype);
goto return_build_unary_op;
case IMAGPART_EXPR:
ret = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
ret = omit_one_operand (TREE_TYPE (arg), integer_zero_node, arg);
+ if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
+ eptype = TREE_TYPE (eptype);
goto return_build_unary_op;
case PREINCREMENT_EXPR:
}
/* Report a read-only lvalue. */
- if (TREE_READONLY (arg))
+ if (TYPE_READONLY (argtype))
{
readonly_error (arg,
((code == PREINCREMENT_EXPR
? lv_increment : lv_decrement));
return error_mark_node;
}
+ else if (TREE_READONLY (arg))
+ readonly_warning (arg,
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment : lv_decrement));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
case ADDR_EXPR:
/* Note that this operation never does default_conversion. */
+ /* The operand of unary '&' must be an lvalue (which excludes
+ expressions of type void), or, in C99, the result of a [] or
+ unary '*' operator. */
+ if (VOID_TYPE_P (TREE_TYPE (arg))
+ && TYPE_QUALS (TREE_TYPE (arg)) == TYPE_UNQUALIFIED
+ && (TREE_CODE (arg) != INDIRECT_REF
+ || !flag_isoc99))
+ pedwarn (location, 0, "taking address of expression of type %<void%>");
+
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
{
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
else if (TREE_CODE (ret) != INTEGER_CST && int_operands)
ret = note_integer_operands (ret);
+ if (eptype)
+ ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
protected_set_expr_location (ret, location);
return ret;
}
Lvalues can be assigned, unless their type has TYPE_READONLY.
Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
-static int
+bool
lvalue_p (const_tree ref)
{
const enum tree_code code = TREE_CODE (ref);
arg);
}
+/* Give a warning for storing in something that is read-only in GCC
+ terms but not const in ISO C terms. */
+
+static void
+readonly_warning (tree arg, enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ warning (0, "assignment of read-only location %qE", arg);
+ break;
+ case lv_increment:
+ warning (0, "increment of read-only location %qE", arg);
+ break;
+ case lv_decrement:
+ warning (0, "decrement of read-only location %qE", arg);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return;
+}
+
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. USE says
enum tree_code code1;
enum tree_code code2;
tree result_type = NULL;
+ tree ep_result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
bool int_const, op1_int_operands, op2_int_operands, int_operands;
+ bool ifexp_int_operands;
tree ret;
bool objc_ok;
+ op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+ if (op1_int_operands)
+ op1 = remove_c_maybe_const_expr (op1);
+ op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
+ if (op2_int_operands)
+ op2 = remove_c_maybe_const_expr (op2);
+ ifexp_int_operands = EXPR_INT_CONST_OPERANDS (ifexp);
+ if (ifexp_int_operands)
+ ifexp = remove_c_maybe_const_expr (ifexp);
+
/* Promote both alternatives. */
if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
objc_ok = objc_compare_types (type1, type2, -3, NULL_TREE);
+ if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR
+ || TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE)
+ && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
+ || code2 == COMPLEX_TYPE))
+ {
+ ep_result_type = c_common_type (type1, type2);
+ if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 0);
+ type1 = TREE_TYPE (op1);
+ gcc_assert (TREE_CODE (type1) == code1);
+ }
+ if (TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
+ {
+ op2 = TREE_OPERAND (op2, 0);
+ type2 = TREE_TYPE (op2);
+ gcc_assert (TREE_CODE (type2) == code2);
+ }
+ }
+
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
- op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
if (ifexp_bcp && ifexp == truthvalue_true_node)
{
op2_int_operands = true;
op1_int_operands = true;
op2 = c_fully_fold (op2, require_constant_value, NULL);
}
- int_const = int_operands = (EXPR_INT_CONST_OPERANDS (ifexp)
+ int_const = int_operands = (ifexp_int_operands
&& op1_int_operands
&& op2_int_operands);
if (int_operands)
if (int_operands)
ret = note_integer_operands (ret);
}
+ if (ep_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
return ret;
}
tree
build_compound_expr (tree expr1, tree expr2)
{
+ bool expr1_int_operands, expr2_int_operands;
+ tree eptype = NULL_TREE;
tree ret;
+ expr1_int_operands = EXPR_INT_CONST_OPERANDS (expr1);
+ if (expr1_int_operands)
+ expr1 = remove_c_maybe_const_expr (expr1);
+ expr2_int_operands = EXPR_INT_CONST_OPERANDS (expr2);
+ if (expr2_int_operands)
+ expr2 = remove_c_maybe_const_expr (expr2);
+
+ if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR)
+ expr1 = TREE_OPERAND (expr1, 0);
+ if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (expr2);
+ expr2 = TREE_OPERAND (expr2, 0);
+ }
+
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
if (flag_isoc99
- && EXPR_INT_CONST_OPERANDS (expr1)
- && EXPR_INT_CONST_OPERANDS (expr2))
+ && expr1_int_operands
+ && expr2_int_operands)
ret = note_integer_operands (ret);
+ if (eptype)
+ ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
+
return ret;
}
tree
build_c_cast (tree type, tree expr)
{
- tree value = expr;
+ tree value;
+
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ value = expr;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
"ISO C forbids casts to union type");
t = digest_init (type,
build_constructor_single (type, field, value),
- false, true, 0);
+ NULL_TREE, false, true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
return t;
}
}
\f
/* Build an assignment expression of lvalue LHS from value RHS.
+ If LHS_ORIGTYPE is not NULL, it is the original type of LHS, which
+ may differ from TREE_TYPE (LHS) for an enum bitfield.
MODIFYCODE is the code for a binary operator that we use
to combine the old value of LHS with RHS to get the new value.
Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
+ If RHS_ORIGTYPE is not NULL_TREE, it is the original type of RHS,
+ which may differ from TREE_TYPE (RHS) for an enum value.
LOCATION is the location of the MODIFYCODE operator. */
tree
-build_modify_expr (location_t location,
- tree lhs, enum tree_code modifycode, tree rhs)
+build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
+ enum tree_code modifycode, tree rhs, tree rhs_origtype)
{
tree result;
tree newrhs;
+ tree rhs_semantic_type = NULL_TREE;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
bool npc;
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
+ if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+ {
+ rhs_semantic_type = TREE_TYPE (rhs);
+ rhs = TREE_OPERAND (rhs, 0);
+ }
+
newrhs = rhs;
if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
{
tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs),
- modifycode, rhs);
+ lhs_origtype, modifycode, rhs,
+ rhs_origtype);
if (inner == error_mark_node)
return error_mark_node;
result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
lhs = stabilize_reference (lhs);
newrhs = build_binary_op (location,
modifycode, lhs, rhs, 1);
+
+ /* The original type of the right hand side is no longer
+ meaningful. */
+ rhs_origtype = NULL_TREE;
}
/* Give an error for storing in something that is 'const'. */
- if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
+ if (TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
readonly_error (lhs, lv_assign);
return error_mark_node;
}
+ else if (TREE_READONLY (lhs))
+ readonly_warning (lhs, lv_assign);
/* If storing into a structure or union member,
it has probably been given type `int'.
TREE_TYPE (lhs) = lhstype;
}
- /* Convert new value to destination type. Fold it first for the
- sake of conversion warnings. */
+ /* Issue -Wc++-compat warnings about an assignment to an enum type
+ when LHS does not have its original type. This happens for,
+ e.g., an enum bitfield in a struct. */
+ if (warn_cxx_compat
+ && lhs_origtype != NULL_TREE
+ && lhs_origtype != lhstype
+ && TREE_CODE (lhs_origtype) == ENUMERAL_TYPE)
+ {
+ tree checktype = (rhs_origtype != NULL_TREE
+ ? rhs_origtype
+ : TREE_TYPE (rhs));
+ if (checktype != error_mark_node
+ && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype))
+ warning_at (location, OPT_Wc___compat,
+ "enum conversion in assignment is invalid in C++");
+ }
+
+ /* Convert new value to destination type. Fold it first, then
+ restore any excess precision information, for the sake of
+ conversion warnings. */
npc = null_pointer_constant_p (newrhs);
newrhs = c_fully_fold (newrhs, false, NULL);
- newrhs = convert_for_assignment (lhstype, newrhs, ic_assign, npc,
- NULL_TREE, NULL_TREE, 0);
+ if (rhs_semantic_type)
+ newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+ newrhs = convert_for_assignment (lhstype, newrhs, rhs_origtype, ic_assign,
+ npc, NULL_TREE, NULL_TREE, 0);
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
if (olhstype == TREE_TYPE (result))
return result;
- result = convert_for_assignment (olhstype, result, ic_assign, false,
- NULL_TREE, NULL_TREE, 0);
+ result = convert_for_assignment (olhstype, result, rhs_origtype, ic_assign,
+ false, NULL_TREE, NULL_TREE, 0);
protected_set_expr_location (result, location);
return result;
}
\f
-/* Convert value RHS to type TYPE as preparation for an assignment
- to an lvalue of type TYPE. NULL_POINTER_CONSTANT says whether RHS
- was a null pointer constant before any folding.
+/* Convert value RHS to type TYPE as preparation for an assignment to
+ an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the
+ original type of RHS; this differs from TREE_TYPE (RHS) for enum
+ types. NULL_POINTER_CONSTANT says whether RHS was a null pointer
+ constant before any folding.
The real work of conversion is done by `convert'.
The purpose of this function is to generate error messages
for assignments that are not allowed in C.
PARMNUM is the number of the argument, for printing in error messages. */
static tree
-convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
- bool null_pointer_constant,
+convert_for_assignment (tree type, tree rhs, tree origtype,
+ enum impl_conv errtype, bool null_pointer_constant,
tree fundecl, tree function, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
+ tree orig_rhs = rhs;
tree rhstype;
enum tree_code coder;
tree rname = NULL_TREE;
} \
} while (0)
+ if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
+
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
objc_ok = objc_compare_types (type, rhstype, parmno, rname);
}
+ if (warn_cxx_compat)
+ {
+ tree checktype = origtype != NULL_TREE ? origtype : rhstype;
+ if (checktype != error_mark_node
+ && TREE_CODE (type) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type))
+ {
+ WARN_FOR_ASSIGNMENT (input_location, OPT_Wc___compat,
+ G_("enum conversion when passing argument "
+ "%d of %qE is invalid in C++"),
+ G_("enum conversion in assignment is "
+ "invalid in C++"),
+ G_("enum conversion in initialization is "
+ "invalid in C++"),
+ G_("enum conversion in return is "
+ "invalid in C++"));
+ }
+ }
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
return rhs;
bool save = in_late_binary_op;
if (codel == BOOLEAN_TYPE)
in_late_binary_op = true;
- ret = convert_and_check (type, rhs);
+ ret = convert_and_check (type, orig_rhs);
if (codel == BOOLEAN_TYPE)
in_late_binary_op = save;
return ret;
/* Perform appropriate conversions on the initial value of a variable,
store it in the declaration DECL,
and print any error messages that are appropriate.
+ If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
If the init is invalid, store an ERROR_MARK. */
void
-store_init_value (tree decl, tree init)
+store_init_value (tree decl, tree init, tree origtype)
{
tree value, type;
bool npc = false;
if (init)
npc = null_pointer_constant_p (init);
- value = digest_init (type, init, npc, true, TREE_STATIC (decl));
+ value = digest_init (type, init, origtype, npc, true, TREE_STATIC (decl));
/* Store the expression if valid; else report error. */
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
+ If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
+
NULL_POINTER_CONSTANT is true if INIT is a null pointer constant.
If INIT is a string constant, STRICT_STRING is true if it is
elements are seen. */
static tree
-digest_init (tree type, tree init, bool null_pointer_constant,
+digest_init (tree type, tree init, tree origtype, bool null_pointer_constant,
bool strict_string, int require_constant)
{
enum tree_code code = TREE_CODE (type);
tree inside_init = init;
+ tree semantic_type = NULL_TREE;
bool maybe_const = true;
if (type == error_mark_node
STRIP_TYPE_NOPS (inside_init);
+ if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (inside_init);
+ inside_init = TREE_OPERAND (inside_init, 0);
+ }
inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
inside_init = decl_constant_value_for_optimization (inside_init);
tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)));
expr.value = inside_init;
expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
+ expr.original_type = NULL;
maybe_warn_string_init (type, expr);
+ if (TYPE_DOMAIN (type) && !TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ pedwarn_init (input_location, OPT_pedantic,
+ "initialization of a flexible array member");
+
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
TYPE_MAIN_VARIANT (type)))
return inside_init;
/* Added to enable additional -Wmissing-format-attribute warnings. */
if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
- inside_init = convert_for_assignment (type, inside_init, ic_init,
- null_pointer_constant,
+ inside_init = convert_for_assignment (type, inside_init, origtype,
+ ic_init, null_pointer_constant,
NULL_TREE, NULL_TREE, 0);
return inside_init;
}
&& (TREE_CODE (init) == STRING_CST
|| TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
inside_init = init = array_to_pointer_conversion (init);
+ if (semantic_type)
+ inside_init = build1 (EXCESS_PRECISION_EXPR, semantic_type,
+ inside_init);
inside_init
- = convert_for_assignment (type, inside_init, ic_init,
+ = convert_for_assignment (type, inside_init, origtype, ic_init,
null_pointer_constant,
NULL_TREE, NULL_TREE, 0);
int balance;
tree purpose;
tree value;
+ tree origtype;
};
/* Tree of pending elements at this constructor level.
if (type == 0)
type = TREE_TYPE (constructor_decl);
- if (targetm.vector_opaque_p (type))
+ if (TREE_CODE (type) == VECTOR_TYPE
+ && TYPE_VECTOR_OPAQUE (type))
error ("opaque vector types cannot be initialized");
p->type = constructor_type;
p->depth = constructor_depth;
p->replacement_value.value = 0;
p->replacement_value.original_code = ERROR_MARK;
+ p->replacement_value.original_type = NULL;
p->implicit = 0;
p->range_stack = 0;
p->outer = 0;
p->depth = constructor_depth;
p->replacement_value.value = 0;
p->replacement_value.original_code = ERROR_MARK;
+ p->replacement_value.original_type = NULL;
p->implicit = implicit;
p->outer = 0;
p->incremental = constructor_incremental;
struct c_expr ret;
ret.value = 0;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (implicit == 0)
{
}
if (TREE_CODE (first) != INTEGER_CST)
+ {
+ first = c_fully_fold (first, false, NULL);
+ if (TREE_CODE (first) == INTEGER_CST)
+ pedwarn_init (input_location, OPT_pedantic,
+ "array index in initializer is not "
+ "an integer constant expression");
+ }
+
+ if (last && TREE_CODE (last) != INTEGER_CST)
+ {
+ last = c_fully_fold (last, false, NULL);
+ if (TREE_CODE (last) == INTEGER_CST)
+ pedwarn_init (input_location, OPT_pedantic,
+ "array index in initializer is not "
+ "an integer constant expression");
+ }
+
+ if (TREE_CODE (first) != INTEGER_CST)
error_init ("nonconstant array index in initializer");
else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
error_init ("nonconstant array index in initializer");
\f
/* Add a new initializer to the tree of pending initializers. PURPOSE
identifies the initializer, either array index or field in a structure.
- VALUE is the value of that index or field.
+ VALUE is the value of that index or field. If ORIGTYPE is not
+ NULL_TREE, it is the original type of VALUE.
IMPLICIT is true if value comes from pop_init_level (1),
the new initializer has been merged with the existing one
existing initializer. */
static void
-add_pending_init (tree purpose, tree value, bool implicit)
+add_pending_init (tree purpose, tree value, tree origtype, bool implicit)
{
struct init_node *p, **q, *r;
warning_init (OPT_Woverride_init, "initialized field overwritten");
}
p->value = value;
+ p->origtype = origtype;
return;
}
}
warning_init (OPT_Woverride_init, "initialized field overwritten");
}
p->value = value;
+ p->origtype = origtype;
return;
}
}
r = GGC_NEW (struct init_node);
r->purpose = purpose;
r->value = value;
+ r->origtype = origtype;
*q = r;
r->parent = p;
return;
FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
- add_pending_init (index, value, false);
+ add_pending_init (index, value, NULL_TREE, false);
constructor_elements = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
}
value = build_int_cst_wide (type, val[1], val[0]);
- add_pending_init (purpose, value, false);
+ add_pending_init (purpose, value, NULL_TREE, false);
}
constructor_incremental = 0;
/* "Output" the next constructor element.
At top level, really output it to assembler code now.
Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
+ If ORIGTYPE is not NULL_TREE, it is the original type of VALUE.
TYPE is the data type that the containing data type wants here.
FIELD is the field (a FIELD_DECL) or the index that this element fills.
If VALUE is a string constant, STRICT_STRING is true if it is
existing initializer. */
static void
-output_init_element (tree value, bool strict_string, tree type, tree field,
- int pending, bool implicit)
+output_init_element (tree value, tree origtype, bool strict_string, tree type,
+ tree field, int pending, bool implicit)
{
+ tree semantic_type = NULL_TREE;
constructor_elt *celt;
bool maybe_const = true;
bool npc;
}
npc = null_pointer_constant_p (value);
+ if (TREE_CODE (value) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (value);
+ value = TREE_OPERAND (value, 0);
+ }
value = c_fully_fold (value, require_constant_value, &maybe_const);
if (value == error_mark_node)
pedwarn_init (input_location, 0,
"initializer element is not a constant expression");
+ /* Issue -Wc++-compat warnings about initializing a bitfield with
+ enum type. */
+ if (warn_cxx_compat
+ && field != NULL_TREE
+ && TREE_CODE (field) == FIELD_DECL
+ && DECL_BIT_FIELD_TYPE (field) != NULL_TREE
+ && (TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field))
+ != TYPE_MAIN_VARIANT (type))
+ && TREE_CODE (DECL_BIT_FIELD_TYPE (field)) == ENUMERAL_TYPE)
+ {
+ tree checktype = origtype != NULL_TREE ? origtype : TREE_TYPE (value);
+ if (checktype != error_mark_node
+ && (TYPE_MAIN_VARIANT (checktype)
+ != TYPE_MAIN_VARIANT (DECL_BIT_FIELD_TYPE (field))))
+ warning_init (OPT_Wc___compat,
+ "enum conversion in initialization is invalid in C++");
+ }
+
/* If this field is empty (and not at the end of structure),
don't do anything other than checking the initializer. */
if (field
|| TREE_CHAIN (field)))))
return;
- value = digest_init (type, value, npc, strict_string,
+ if (semantic_type)
+ value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value);
+ value = digest_init (type, value, origtype, npc, strict_string,
require_constant_value);
if (value == error_mark_node)
{
&& tree_int_cst_lt (field, constructor_unfilled_index))
set_nonincremental_init ();
- add_pending_init (field, value, implicit);
+ add_pending_init (field, value, origtype, implicit);
return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
}
}
- add_pending_init (field, value, implicit);
+ add_pending_init (field, value, origtype, implicit);
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
{
if (tree_int_cst_equal (elt->purpose,
constructor_unfilled_index))
- output_init_element (elt->value, true,
+ output_init_element (elt->value, elt->origtype, true,
TREE_TYPE (constructor_type),
constructor_unfilled_index, 0, false);
else if (tree_int_cst_lt (constructor_unfilled_index,
if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
{
constructor_unfilled_fields = elt->purpose;
- output_init_element (elt->value, true, TREE_TYPE (elt->purpose),
+ output_init_element (elt->value, elt->origtype, true,
+ TREE_TYPE (elt->purpose),
elt->purpose, 0, false);
}
else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
process_init_element (pop_init_level (1), true);
- else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+ else if ((TREE_CODE (constructor_type) == ARRAY_TYPE
+ || TREE_CODE (constructor_type) == VECTOR_TYPE)
&& (constructor_max_index == 0
|| tree_int_cst_lt (constructor_max_index,
constructor_index)))
if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
|| !require_constant_value
|| flag_isoc99)
- value.value = c_save_expr (value.value);
+ {
+ tree semantic_type = NULL_TREE;
+ if (TREE_CODE (value.value) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (value.value);
+ value.value = TREE_OPERAND (value.value, 0);
+ }
+ value.value = c_save_expr (value.value);
+ if (semantic_type)
+ value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type,
+ value.value);
+ }
}
while (1)
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
- || fieldcode == UNION_TYPE))
+ || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
push_init_level (1);
continue;
if (value.value)
{
push_member_name (constructor_fields);
- output_init_element (value.value, strict_string,
- fieldtype, constructor_fields, 1, implicit);
+ output_init_element (value.value, value.original_type,
+ strict_string, fieldtype,
+ constructor_fields, 1, implicit);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
- || fieldcode == UNION_TYPE))
+ || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
push_init_level (1);
continue;
if (value.value)
{
push_member_name (constructor_fields);
- output_init_element (value.value, strict_string,
- fieldtype, constructor_fields, 1, implicit);
+ output_init_element (value.value, value.original_type,
+ strict_string, fieldtype,
+ constructor_fields, 1, implicit);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
&& value.value != error_mark_node
&& TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
- || eltcode == UNION_TYPE))
+ || eltcode == UNION_TYPE || eltcode == VECTOR_TYPE))
{
push_init_level (1);
continue;
if (value.value)
{
push_array_bounds (tree_low_cst (constructor_index, 1));
- output_init_element (value.value, strict_string,
- elttype, constructor_index, 1, implicit);
+ output_init_element (value.value, value.original_type,
+ strict_string, elttype,
+ constructor_index, 1, implicit);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
/* Now output the actual element. */
if (value.value)
- output_init_element (value.value, strict_string,
- elttype, constructor_index, 1, implicit);
+ {
+ if (TREE_CODE (value.value) == VECTOR_CST)
+ elttype = TYPE_MAIN_VARIANT (constructor_type);
+ output_init_element (value.value, value.original_type,
+ strict_string, elttype,
+ constructor_index, 1, implicit);
+ }
constructor_index
= size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
else
{
if (value.value)
- output_init_element (value.value, strict_string,
- constructor_type, NULL_TREE, 1, implicit);
+ output_init_element (value.value, value.original_type,
+ strict_string, constructor_type,
+ NULL_TREE, 1, implicit);
constructor_fields = 0;
}
}
/* Generate a C `return' statement. RETVAL is the expression for what
- to return, or a null pointer for `return;' with no value. */
+ to return, or a null pointer for `return;' with no value. If
+ ORIGTYPE is not NULL_TREE, it is the original type of RETVAL. */
tree
-c_finish_return (tree retval)
+c_finish_return (tree retval, tree origtype)
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt;
bool no_warning = false;
if (retval)
{
+ tree semantic_type = NULL_TREE;
npc = null_pointer_constant_p (retval);
+ if (TREE_CODE (retval) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (retval);
+ retval = TREE_OPERAND (retval, 0);
+ }
retval = c_fully_fold (retval, false, NULL);
+ if (semantic_type)
+ retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval);
}
if (!retval)
}
else
{
- tree t = convert_for_assignment (valtype, retval, ic_return, npc,
- NULL_TREE, NULL_TREE, 0);
+ tree t = convert_for_assignment (valtype, retval, origtype, ic_return,
+ npc, NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
tree inner;
{
tree label = NULL_TREE;
+ if (low_value && TREE_CODE (low_value) != INTEGER_CST)
+ {
+ low_value = c_fully_fold (low_value, false, NULL);
+ if (TREE_CODE (low_value) == INTEGER_CST)
+ pedwarn (input_location, OPT_pedantic,
+ "case label is not an integer constant expression");
+ }
+
+ if (high_value && TREE_CODE (high_value) != INTEGER_CST)
+ {
+ high_value = c_fully_fold (high_value, false, NULL);
+ if (TREE_CODE (high_value) == INTEGER_CST)
+ pedwarn (input_location, OPT_pedantic,
+ "case label is not an integer constant expression");
+ }
+
if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
&& !c_switch_stack->blocked_vm)
{
build_binary_op (location_t location, enum tree_code code,
tree orig_op0, tree orig_op1, int convert_p)
{
- tree type0, type1;
+ tree type0, type1, orig_type0, orig_type1;
+ tree eptype;
enum tree_code code0, code1;
tree op0, op1;
tree ret = error_mark_node;
const char *invalid_op_diag;
+ bool op0_int_operands, op1_int_operands;
bool int_const, int_const_or_overflow, int_operands;
/* Expression code to give to the expression when it is built.
In the simplest cases this is the common type of the arguments. */
tree result_type = NULL;
+ /* When the computation is in excess precision, the type of the
+ final EXCESS_PRECISION_EXPR. */
+ tree real_result_type = NULL;
+
/* Nonzero means operands have already been type-converted
in whatever way is necessary.
Zero means they need to be converted to RESULT_TYPE. */
/* True means types are compatible as far as ObjC is concerned. */
bool objc_ok;
+ /* True means this is an arithmetic operation that may need excess
+ precision. */
+ bool may_need_excess_precision;
+
if (location == UNKNOWN_LOCATION)
location = input_location;
- int_operands = (EXPR_INT_CONST_OPERANDS (orig_op0)
- && EXPR_INT_CONST_OPERANDS (orig_op1));
+ op0 = orig_op0;
+ op1 = orig_op1;
+
+ op0_int_operands = EXPR_INT_CONST_OPERANDS (orig_op0);
+ if (op0_int_operands)
+ op0 = remove_c_maybe_const_expr (op0);
+ op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+ if (op1_int_operands)
+ op1 = remove_c_maybe_const_expr (op1);
+ int_operands = (op0_int_operands && op1_int_operands);
if (int_operands)
{
int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST
if (convert_p)
{
- op0 = default_conversion (orig_op0);
- op1 = default_conversion (orig_op1);
- }
- else
- {
- op0 = orig_op0;
- op1 = orig_op1;
+ op0 = default_conversion (op0);
+ op1 = default_conversion (op1);
}
- type0 = TREE_TYPE (op0);
- type1 = TREE_TYPE (op1);
+ orig_type0 = type0 = TREE_TYPE (op0);
+ orig_type1 = type1 = TREE_TYPE (op1);
/* The expression codes of the data types of the arguments tell us
whether the arguments are integers, floating, pointers, etc. */
return error_mark_node;
}
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ may_need_excess_precision = true;
+ break;
+ default:
+ may_need_excess_precision = false;
+ break;
+ }
+ if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
+ {
+ op0 = TREE_OPERAND (op0, 0);
+ type0 = TREE_TYPE (op0);
+ }
+ else if (may_need_excess_precision
+ && (eptype = excess_precision_type (type0)) != NULL_TREE)
+ {
+ type0 = eptype;
+ op0 = convert (eptype, op0);
+ }
+ if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 0);
+ type1 = TREE_TYPE (op1);
+ }
+ else if (may_need_excess_precision
+ && (eptype = excess_precision_type (type1)) != NULL_TREE)
+ {
+ type1 = eptype;
+ op1 = convert (eptype, op1);
+ }
+
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
switch (code)
/* Handle the pointer + int case. */
if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
+ ret = pointer_int_sum (PLUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
+ ret = pointer_int_sum (PLUS_EXPR, op1, op0);
goto return_build_binary_op;
}
else
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
+ ret = pointer_int_sum (MINUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else
}
if (build_type == NULL_TREE)
- build_type = result_type;
+ {
+ build_type = result_type;
+ if (type0 != orig_type0 || type1 != orig_type1)
+ {
+ gcc_assert (may_need_excess_precision && common);
+ real_result_type = c_common_type (orig_type0, orig_type1);
+ }
+ }
/* Treat expressions in initializers specially as they can't trap. */
if (int_const_or_overflow)
else if (TREE_CODE (ret) != INTEGER_CST && int_operands
&& !in_late_binary_op)
ret = note_integer_operands (ret);
+ if (real_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, real_result_type, ret);
protected_set_expr_location (ret, location);
return ret;
}
int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr));
int_operands = EXPR_INT_CONST_OPERANDS (expr);
+ if (int_operands)
+ expr = remove_c_maybe_const_expr (expr);
/* ??? Should we also give an error for void and vectors rather than
leaving those to give errors later? */