/* Build expressions with type checking for C compiler.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
diagnostic messages in convert_for_assignment. */
enum impl_conv {
ic_argpass,
- ic_argpass_nonproto,
ic_assign,
ic_init,
ic_return
};
+/* Whether we are building a boolean conversion inside
+ convert_for_assignment, or some other late binary operation. If
+ build_binary_op is called (from code shared with C++) in this case,
+ then the operands have already been folded and the result will not
+ be folded again, so C_MAYBE_CONST_EXPR should not be generated. */
+bool in_late_binary_op;
+
/* The level of nesting inside "__alignof__". */
int in_alignof;
static int comp_target_types (tree, tree);
static int function_types_compatible_p (const_tree, const_tree);
static int type_lists_compatible_p (const_tree, const_tree);
-static tree decl_constant_value_for_broken_optimization (tree);
static tree lookup_field (tree, tree);
static int convert_arguments (int, tree *, tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
-static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
- int);
+static tree convert_for_assignment (tree, tree, enum impl_conv, bool,
+ tree, tree, int);
static tree valid_compound_expr_initializer (tree, tree);
static void push_string (const char *);
static void push_member_name (tree);
static int spelling_length (void);
static char *print_spelling (char *);
static void warning_init (int, const char *);
-static tree digest_init (tree, tree, bool, int);
-static void output_init_element (tree, bool, tree, tree, int);
+static tree digest_init (tree, tree, bool, bool, int);
+static void output_init_element (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);
+static void add_pending_init (tree, tree, bool);
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
&& VOID_TYPE_P (TREE_TYPE (type))
&& TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
}
+
+/* EXPR may appear in an unevaluated part of an integer constant
+ expression, but not in an evaluated part. Wrap it in a
+ C_MAYBE_CONST_EXPR, or mark it with TREE_OVERFLOW if it is just an
+ INTEGER_CST and we cannot create a C_MAYBE_CONST_EXPR. */
+
+static tree
+note_integer_operands (tree expr)
+{
+ tree ret;
+ if (TREE_CODE (expr) == INTEGER_CST && in_late_binary_op)
+ {
+ ret = copy_node (expr);
+ TREE_OVERFLOW (ret) = 1;
+ }
+ else
+ {
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr);
+ C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1;
+ }
+ 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 {
tree d2 = TYPE_DOMAIN (t2);
bool d1_variable, d2_variable;
bool d1_zero, d2_zero;
+ bool t1_complete, t2_complete;
/* We should not have any type quals on arrays at all. */
gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
+ t1_complete = COMPLETE_TYPE_P (t1);
+ t2_complete = COMPLETE_TYPE_P (t2);
+
d1_zero = d1 == 0 || !TYPE_MAX_VALUE (d1);
d2_zero = d2 == 0 || !TYPE_MAX_VALUE (d2);
|| !d1_variable))
? t1
: t2));
+ /* Ensure a composite type involving a zero-length array type
+ is a zero-length type not an incomplete type. */
+ if (d1_zero && d2_zero
+ && (t1_complete || t2_complete)
+ && !COMPLETE_TYPE_P (t1))
+ {
+ TYPE_SIZE (t1) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (t1) = size_zero_node;
+ }
t1 = c_build_qualified_type (t1, quals);
return build_type_attribute_variant (t1, attributes);
}
return decl;
}
-/* Return either DECL or its known constant value (if it has one), but
- return DECL if pedantic or DECL has mode BLKmode. This is for
- bug-compatibility with the old behavior of decl_constant_value
- (before GCC 3.0); every use of this function is a bug and it should
- be removed before GCC 3.1. It is not appropriate to use pedantic
- in a way that affects optimization, and BLKmode is probably not the
- right test for avoiding misoptimizations either. */
-
-static tree
-decl_constant_value_for_broken_optimization (tree decl)
-{
- tree ret;
-
- if (pedantic || DECL_MODE (decl) == BLKmode)
- return decl;
-
- ret = decl_constant_value (decl);
- /* Avoid unwanted tree sharing between the initializer and current
- function's body where the tree can be modified e.g. by the
- gimplifier. */
- if (ret != decl && TREE_STATIC (decl))
- ret = unshare_expr (ret);
- return ret;
-}
-
/* Convert the array expression EXP to a pointer. */
static tree
array_to_pointer_conversion (tree exp)
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
- adr = build_unary_op (ADDR_EXPR, exp, 1);
+ adr = build_unary_op (EXPR_LOCATION (exp), ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
- return build_unary_op (ADDR_EXPR, exp, 0);
+ return build_unary_op (EXPR_LOCATION (exp), ADDR_EXPR, exp, 0);
}
/* Perform the default conversion of arrays and functions to pointers.
Return the result of converting EXP. For any other expression, just
- return EXP after removing NOPs. */
+ return EXP. */
struct c_expr
default_function_array_conversion (struct c_expr exp)
exp.value = function_to_pointer_conversion (exp.value);
break;
default:
- STRIP_TYPE_NOPS (exp.value);
- if (TREE_NO_WARNING (orig_exp))
- TREE_NO_WARNING (exp.value) = 1;
break;
}
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
- /* Replace a nonvolatile const static variable with its value unless
- it is an array, in which case we must be sure that taking the
- address of the array produces consistent results. */
- else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
- {
- exp = decl_constant_value_for_broken_optimization (exp);
- type = TREE_TYPE (exp);
- }
-
/* Strip no-op conversions. */
orig_exp = exp;
STRIP_TYPE_NOPS (exp);
enum tree_code code = TREE_CODE (type);
tree field = NULL;
tree ref;
+ bool datum_lvalue = lvalue_p (datum);
if (!objc_is_public (datum, component))
return error_mark_node;
tree subdatum = TREE_VALUE (field);
int quals;
tree subtype;
+ bool use_datum_quals;
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
+ /* If this is an rvalue, it does not have qualifiers in C
+ standard terms and we must avoid propagating such
+ qualifiers down to a non-lvalue array that is then
+ converted to a pointer. */
+ use_datum_quals = (datum_lvalue
+ || TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE);
+
quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
- quals |= TYPE_QUALS (TREE_TYPE (datum));
+ if (use_datum_quals)
+ quals |= TYPE_QUALS (TREE_TYPE (datum));
subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
NULL_TREE);
- if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
+ if (TREE_READONLY (subdatum)
+ || (use_datum_quals && TREE_READONLY (datum)))
TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
+ if (TREE_THIS_VOLATILE (subdatum)
+ || (use_datum_quals && TREE_THIS_VOLATILE (datum)))
TREE_THIS_VOLATILE (ref) = 1;
if (TREE_DEPRECATED (subdatum))
LOC is the location to use for the generated tree. */
tree
-build_indirect_ref (tree ptr, const char *errorstring, location_t loc)
+build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
{
tree pointer = default_conversion (ptr);
tree type = TREE_TYPE (pointer);
if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
{
- error ("dereferencing pointer to incomplete type");
+ error_at (loc, "dereferencing pointer to incomplete type");
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning (0, "dereferencing %<void *%> pointer");
+ warning_at (loc, 0, "dereferencing %<void *%> pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error ("invalid type argument of %qs (have %qT)", errorstring, type);
+ error_at (loc,
+ "invalid type argument of %qs (have %qT)", errorstring, type);
return error_mark_node;
}
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
- ret = require_complete_type (fold (rval));
+ ret = require_complete_type (rval);
protected_set_expr_location (ret, loc);
return ret;
}
gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
return build_indirect_ref
- (build_binary_op (loc, PLUS_EXPR, ar, index, 0),
- "array indexing", loc);
+ (loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0),
+ "array indexing");
}
}
\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);
{
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
pop_maybe_used (false);
}
else
{
- ret.value = c_sizeof (TREE_TYPE (expr.value));
+ bool expr_const_operands = true;
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_sizeof (TREE_TYPE (folded_expr));
ret.original_code = ERROR_MARK;
- if (c_vla_type_p (TREE_TYPE (expr.value)))
+ 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). */
- ret.value = build2 (COMPOUND_EXPR, TREE_TYPE (ret.value), expr.value, ret.value);
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
}
- pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)));
}
return ret;
}
{
tree type;
struct c_expr ret;
- type = groktypename (t);
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ if (type_expr && c_vla_type_p (type))
+ {
+ 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;
+ }
pop_maybe_used (type != error_mark_node
? C_TYPE_VARIABLE_SIZE (type) : false);
return ret;
expressions, like those used for ObjC messenger dispatches. */
function = objc_rewrite_function_call (function, params);
+ function = c_fully_fold (function, false, NULL);
+
fntype = TREE_TYPE (function);
if (TREE_CODE (fntype) == ERROR_MARK)
/* fntype now gets the type of function pointed to. */
fntype = TREE_TYPE (fntype);
+ /* 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);
+ if (nargs < 0)
+ return error_mark_node;
+
/* Check that the function is called through a compatible prototype.
If it is not, replace the call by a trap, wrapped up in a compound
expression if necessary. This has the nice side-effect to prevent
tree return_type = TREE_TYPE (fntype);
tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
NULL_TREE);
+ int i;
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
/* We can, however, treat "undefined" any way we please.
Call abort to encourage the user to fix the program. */
inform (input_location, "if this code is reached, the program will abort");
+ /* 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);
if (VOID_TYPE_P (return_type))
return trap;
if (AGGREGATE_TYPE_P (return_type))
rhs = build_compound_literal (return_type,
- build_constructor (return_type, 0));
+ build_constructor (return_type, 0),
+ false);
else
rhs = fold_convert (return_type, integer_zero_node);
}
}
- /* 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);
- if (nargs < 0)
- return error_mark_node;
-
/* Check that arguments to builtin functions match the expectations. */
if (fundecl
&& DECL_BUILT_IN (fundecl)
check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
TYPE_ARG_TYPES (fntype));
- if (require_constant_value)
+ if (name != NULL_TREE
+ && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
{
- result = fold_build_call_array_initializer (TREE_TYPE (fntype),
- function, nargs, argarray);
- if (TREE_CONSTANT (result)
- && (name == NULL_TREE
- || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
- pedwarn_init (input_location, 0, "initializer element is not constant");
+ if (require_constant_value)
+ result = fold_build_call_array_initializer (TREE_TYPE (fntype),
+ function, nargs, argarray);
+ else
+ result = fold_build_call_array (TREE_TYPE (fntype),
+ function, nargs, argarray);
+ if (TREE_CODE (result) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
+ STRIP_TYPE_NOPS (result);
}
else
- result = fold_build_call_array (TREE_TYPE (fntype),
- function, nargs, argarray);
+ result = build_call_array (TREE_TYPE (fntype),
+ function, nargs, argarray);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
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. */
{
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;
if (type == void_type_node)
{
argnum -= 2;
}
+ 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);
val = require_complete_type (val);
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,
+ /* 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);
+ parmval = convert_for_assignment (type, val, ic_argpass, npc,
fundecl, function,
parmnum + 1);
}
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;
/* Convert `float' to `double'. */
argarray[parmnum] = 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. */
+ argarray[parmnum] = convert (valtype, val);
else if ((invalid_func_diag =
targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
{
{
struct c_expr result;
- result.original_code = ERROR_MARK;
- result.value = build_unary_op (code, arg.value, 0);
- protected_set_expr_location (result.value, loc);
+ 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;
/* Check for cases such as x+y<<z which users are likely
to misinterpret. */
if (warn_parentheses)
- warn_about_parentheses (code, code1, code2);
+ 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);
&& !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
the default promotions (such as from short to int).
For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
allows non-lvalues; this is only used to handle conversion of non-lvalue
- arrays to pointers in C99. */
+ arrays to pointers in C99.
+
+ LOCATION is the location of the operator. */
tree
-build_unary_op (enum tree_code code, tree xarg, int flag)
+build_unary_op (location_t location,
+ enum tree_code code, tree xarg, int flag)
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg;
tree argtype = 0;
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);
if ((invalid_op_diag
= targetm.invalid_unary_op (code, TREE_TYPE (xarg))))
{
- error (invalid_op_diag);
+ error_at (location, invalid_op_diag);
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:
|| typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE))
{
- error ("wrong type argument to unary plus");
+ error_at (location, "wrong type argument to unary plus");
return error_mark_node;
}
else if (!noconvert)
|| typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE))
{
- error ("wrong type argument to unary minus");
+ error_at (location, "wrong type argument to unary minus");
return error_mark_node;
}
else if (!noconvert)
else if (typecode == COMPLEX_TYPE)
{
code = CONJ_EXPR;
- pedwarn (input_location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C does not support %<~%> for complex conjugation");
if (!noconvert)
arg = default_conversion (arg);
}
else
{
- error ("wrong type argument to bit-complement");
+ error_at (location, "wrong type argument to bit-complement");
return error_mark_node;
}
break;
case ABS_EXPR:
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
{
- error ("wrong type argument to abs");
+ error_at (location, "wrong type argument to abs");
return error_mark_node;
}
else if (!noconvert)
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
|| typecode == COMPLEX_TYPE))
{
- error ("wrong type argument to conjugation");
+ error_at (location, "wrong type argument to conjugation");
return error_mark_node;
}
else if (!noconvert)
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
&& typecode != COMPLEX_TYPE)
{
- error ("wrong type argument to unary exclamation mark");
+ error_at (location,
+ "wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = c_objc_common_truthvalue_conversion (input_location, arg);
- return invert_truthvalue (arg);
+ arg = c_objc_common_truthvalue_conversion (location, arg);
+ ret = invert_truthvalue (arg);
+ goto return_build_unary_op;
case REALPART_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
- return TREE_REALPART (arg);
+ ret = TREE_REALPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+ ret = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
- return arg;
+ ret = arg;
+ if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
+ eptype = TREE_TYPE (eptype);
+ goto return_build_unary_op;
case IMAGPART_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
- return TREE_IMAGPART (arg);
+ ret = TREE_IMAGPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+ ret = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
- return convert (TREE_TYPE (arg), integer_zero_node);
+ 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:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+ {
+ tree inner = build_unary_op (location, code,
+ C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+ if (inner == error_mark_node)
+ return error_mark_node;
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (arg), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+ C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1;
+ goto return_build_unary_op;
+ }
+
+ /* Complain about anything that is not a true lvalue. */
+ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment
+ : lv_decrement)))
+ return error_mark_node;
+
+ /* Ensure the argument is fully folded inside any SAVE_EXPR. */
+ arg = c_fully_fold (arg, false, NULL);
+
/* Increment or decrement the real part of the value,
and don't change the imaginary part. */
if (typecode == COMPLEX_TYPE)
{
tree real, imag;
- pedwarn (input_location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C does not support %<++%> and %<--%> on complex types");
arg = stabilize_reference (arg);
- real = build_unary_op (REALPART_EXPR, arg, 1);
- imag = build_unary_op (IMAGPART_EXPR, arg, 1);
- real = build_unary_op (code, real, 1);
+ real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
+ imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
+ real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
if (real == error_mark_node || imag == error_mark_node)
return error_mark_node;
- return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
- real, imag);
+ ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
+ real, imag);
+ goto return_build_unary_op;
}
/* Report invalid types. */
&& typecode != INTEGER_TYPE && typecode != REAL_TYPE)
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- error ("wrong type argument to increment");
+ error_at (location, "wrong type argument to increment");
else
- error ("wrong type argument to decrement");
+ error_at (location, "wrong type argument to decrement");
return error_mark_node;
}
{
tree inc;
- tree result_type = TREE_TYPE (arg);
- arg = get_unwidened (arg, 0);
argtype = TREE_TYPE (arg);
/* Compute the increment. */
{
/* If pointer target is an undefined struct,
we just cannot know how to do the arithmetic. */
- if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (result_type)))
+ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype)))
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- error ("increment of pointer to unknown structure");
+ error_at (location,
+ "increment of pointer to unknown structure");
else
- error ("decrement of pointer to unknown structure");
+ error_at (location,
+ "decrement of pointer to unknown structure");
}
- else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
+ else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE)
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"wrong type argument to increment");
else
- pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"wrong type argument to decrement");
}
- inc = c_size_in_bytes (TREE_TYPE (result_type));
+ inc = c_size_in_bytes (TREE_TYPE (argtype));
inc = fold_convert (sizetype, inc);
}
- else if (FRACT_MODE_P (TYPE_MODE (result_type)))
+ else if (FRACT_MODE_P (TYPE_MODE (argtype)))
{
/* For signed fract types, we invert ++ to -- or
-- to ++, and change inc from 1 to -1, because
inc = convert (argtype, inc);
}
- /* Complain about anything else that is not a true lvalue. */
- if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? lv_increment
- : lv_decrement)))
- return error_mark_node;
-
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
{
else
val = build2 (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
- val = convert (result_type, val);
if (TREE_CODE (val) != code)
TREE_NO_WARNING (val) = 1;
- return val;
+ ret = val;
+ goto return_build_unary_op;
}
case ADDR_EXPR:
/* Don't let this be an lvalue. */
if (lvalue_p (TREE_OPERAND (arg, 0)))
return non_lvalue (TREE_OPERAND (arg, 0));
- return TREE_OPERAND (arg, 0);
+ ret = TREE_OPERAND (arg, 0);
+ goto return_build_unary_op;
}
/* For &x[y], return x+y */
tree op0 = TREE_OPERAND (arg, 0);
if (!c_mark_addressable (op0))
return error_mark_node;
- return build_binary_op (EXPR_LOCATION (xarg), PLUS_EXPR,
+ return build_binary_op (location, PLUS_EXPR,
(TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
? array_to_pointer_conversion (op0)
: op0),
&& !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
+ /* Move address operations inside C_MAYBE_CONST_EXPR to simplify
+ folding later. */
+ if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+ {
+ tree inner = build_unary_op (location, code,
+ C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (arg), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+ C_MAYBE_CONST_EXPR_NON_CONST (ret)
+ = C_MAYBE_CONST_EXPR_NON_CONST (arg);
+ goto return_build_unary_op;
+ }
+
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
argtype = TREE_TYPE (arg);
tree op0 = fold_convert (sizetype, fold_offsetof (arg, val)), op1;
op1 = fold_convert (argtype, TREE_OPERAND (val, 0));
- return fold_build2 (POINTER_PLUS_EXPR, argtype, op1, op0);
+ ret = fold_build2 (POINTER_PLUS_EXPR, argtype, op1, op0);
+ goto return_build_unary_op;
}
val = build1 (ADDR_EXPR, argtype, arg);
- return val;
+ ret = val;
+ goto return_build_unary_op;
default:
gcc_unreachable ();
if (argtype == 0)
argtype = TREE_TYPE (arg);
- return require_constant_value ? fold_build1_initializer (code, argtype, arg)
- : fold_build1 (code, argtype, arg);
+ if (TREE_CODE (arg) == INTEGER_CST)
+ ret = (require_constant_value
+ ? fold_build1_initializer (code, argtype, arg)
+ : fold_build1 (code, argtype, arg));
+ else
+ ret = build1 (code, argtype, arg);
+ return_build_unary_op:
+ gcc_assert (ret != error_mark_node);
+ if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret)
+ && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg)))
+ 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;
}
/* Return nonzero if REF is an lvalue valid for this language.
case COMPONENT_REF:
return lvalue_p (TREE_OPERAND (ref, 0));
+ case C_MAYBE_CONST_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 1));
+
case COMPOUND_LITERAL_EXPR:
case STRING_CST:
return 1;
}
}
\f
-/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
+/* Build and return a conditional expression IFEXP ? OP1 : OP2. If
+ IFEXP_BCP then the condition is a call to __builtin_constant_p, and
+ if folded to an integer constant then the unselected half may
+ contain arbitrary operations not normally permitted in constant
+ expressions. */
tree
-build_conditional_expr (tree ifexp, tree op1, tree op2)
+build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
{
tree type1;
tree type2;
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. */
return error_mark_node;
}
+ 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))
and later code won't know it used to be different.
Do this check on the original types, so that explicit casts
will be considered, but default promotions won't. */
- if (warn_sign_compare && !skip_evaluation)
+ if (!skip_evaluation)
{
int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1));
int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2));
all the values of the unsigned type. */
if (!TYPE_UNSIGNED (result_type))
/* OK */;
- /* Do not warn if the signed quantity is an unsuffixed
- integer literal (or some static constant expression
- involving such literals) and it is non-negative. */
- else if ((unsigned_op2
- && tree_expr_nonnegative_warnv_p (op1, &ovf))
- || (unsigned_op1
- && tree_expr_nonnegative_warnv_p (op2, &ovf)))
- /* OK */;
else
- warning (OPT_Wsign_compare, "signed and unsigned type in conditional expression");
+ {
+ bool op1_maybe_const = true;
+ bool op2_maybe_const = true;
+
+ /* Do not warn if the signed quantity is an
+ unsuffixed integer literal (or some static
+ constant expression involving such literals) and
+ it is non-negative. This warning requires the
+ operands to be folded for best results, so do
+ that folding in this case even without
+ warn_sign_compare to avoid warning options
+ possibly affecting code generation. */
+ op1 = c_fully_fold (op1, require_constant_value,
+ &op1_maybe_const);
+ op2 = c_fully_fold (op2, require_constant_value,
+ &op2_maybe_const);
+
+ if (warn_sign_compare)
+ {
+ if ((unsigned_op2
+ && tree_expr_nonnegative_warnv_p (op1, &ovf))
+ || (unsigned_op1
+ && tree_expr_nonnegative_warnv_p (op2, &ovf)))
+ /* OK */;
+ else
+ warning (OPT_Wsign_compare, "signed and unsigned type in conditional expression");
+ }
+ if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
+ {
+ op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
+ NULL, op1);
+ C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
+ }
+ if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
+ {
+ op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2),
+ NULL, op2);
+ C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const;
+ }
+ }
}
}
}
}
else
{
- pedwarn (input_location, 0,
- "pointer type mismatch in conditional expression");
+ if (!objc_ok)
+ pedwarn (input_location, 0,
+ "pointer type mismatch in conditional expression");
result_type = build_pointer_type (void_type_node);
}
}
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ if (ifexp_bcp && ifexp == truthvalue_true_node)
+ {
+ op2_int_operands = true;
+ op1 = c_fully_fold (op1, require_constant_value, NULL);
+ }
+ if (ifexp_bcp && ifexp == truthvalue_false_node)
+ {
+ op1_int_operands = true;
+ op2 = c_fully_fold (op2, require_constant_value, NULL);
+ }
+ int_const = int_operands = (ifexp_int_operands
+ && op1_int_operands
+ && op2_int_operands);
+ if (int_operands)
+ {
+ int_const = ((ifexp == truthvalue_true_node
+ && TREE_CODE (orig_op1) == INTEGER_CST
+ && !TREE_OVERFLOW (orig_op1))
+ || (ifexp == truthvalue_false_node
+ && TREE_CODE (orig_op2) == INTEGER_CST
+ && !TREE_OVERFLOW (orig_op2)));
+ }
+ if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST))
+ ret = fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ else
+ {
+ ret = build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ if (int_operands)
+ ret = note_integer_operands (ret);
+ }
+ if (ep_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
+
+ return ret;
}
\f
/* Return a compound expression that performs two expressions and
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
if (expr2 == error_mark_node)
return error_mark_node;
- return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+
+ if (flag_isoc99
+ && expr1_int_operands
+ && expr2_int_operands)
+ ret = note_integer_operands (ret);
+
+ if (eptype)
+ ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
+
+ return ret;
}
/* Build an expression representing a cast to type TYPE of expression EXPR. */
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),
- true, 0);
+ false, true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
return t;
}
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
- if (TREE_CODE (value) == INTEGER_CST)
+ if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype))
{
if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue))
{
if (value == expr)
value = non_lvalue (value);
+ /* Don't allow the results of casting to floating-point or complex
+ types be confused with actual constants, or casts involving
+ integer and pointer types other than direct integer-to-integer
+ and integer-to-pointer be confused with integer constant
+ expressions and null pointer constants. */
+ if (TREE_CODE (value) == REAL_CST
+ || TREE_CODE (value) == COMPLEX_CST
+ || (TREE_CODE (value) == INTEGER_CST
+ && !((TREE_CODE (expr) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+ || TREE_CODE (expr) == REAL_CST
+ || TREE_CODE (expr) == COMPLEX_CST)))
+ value = build1 (NOP_EXPR, type, value);
+
return value;
}
c_cast_expr (struct c_type_name *type_name, tree expr)
{
tree type;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ tree ret;
int saved_wsp = warn_strict_prototypes;
/* This avoids warnings about unprototyped casts on
integers. E.g. "#define SIG_DFL (void(*)())0". */
if (TREE_CODE (expr) == INTEGER_CST)
warn_strict_prototypes = 0;
- type = groktypename (type_name);
+ type = groktypename (type_name, &type_expr, &type_expr_const);
warn_strict_prototypes = saved_wsp;
- return build_c_cast (type, expr);
+ ret = build_c_cast (type, expr);
+ if (type_expr)
+ {
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const;
+ }
+ return ret;
}
\f
/* Build an assignment expression of lvalue LHS from value RHS.
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. */
+ Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
+
+ LOCATION is the location of the MODIFYCODE operator. */
tree
-build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+build_modify_expr (location_t location,
+ tree lhs, enum tree_code modifycode, tree rhs)
{
tree result;
tree newrhs;
+ tree rhs_semantic_type = NULL_TREE;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
+ bool npc;
/* Types that aren't fully specified cannot be used in assignments. */
lhs = require_complete_type (lhs);
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
- STRIP_TYPE_NOPS (rhs);
+ 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);
+ if (inner == error_mark_node)
+ return error_mark_node;
+ result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (lhs), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs));
+ C_MAYBE_CONST_EXPR_NON_CONST (result) = 1;
+ protected_set_expr_location (result, location);
+ return result;
+ }
+
/* If a binary op has been requested, combine the old LHS value with the RHS
producing the value we should actually store into the LHS. */
if (modifycode != NOP_EXPR)
{
+ lhs = c_fully_fold (lhs, false, NULL);
lhs = stabilize_reference (lhs);
- newrhs = build_binary_op (EXPR_LOCATION (lhs),
+ newrhs = build_binary_op (location,
modifycode, lhs, rhs, 1);
}
TREE_TYPE (lhs) = lhstype;
}
- /* Convert new value to destination type. */
+ /* Convert new value to destination type. Fold it first, then
+ restore any excess precision information, for the sake of
+ conversion warnings. */
- newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
+ npc = null_pointer_constant_p (newrhs);
+ newrhs = c_fully_fold (newrhs, false, NULL);
+ if (rhs_semantic_type)
+ newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+ newrhs = convert_for_assignment (lhstype, newrhs, ic_assign, npc,
NULL_TREE, NULL_TREE, 0);
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
{
result = objc_generate_write_barrier (lhs, modifycode, newrhs);
if (result)
- return result;
+ {
+ protected_set_expr_location (result, location);
+ return result;
+ }
}
/* Scan operands. */
result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
+ protected_set_expr_location (result, location);
/* If we got the LHS in a different type for storing in,
convert the result back to the nominal type of LHS
if (olhstype == TREE_TYPE (result))
return result;
- return convert_for_assignment (olhstype, result, ic_assign,
- NULL_TREE, NULL_TREE, 0);
+
+ result = convert_for_assignment (olhstype, result, 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.
+ to an lvalue of type TYPE. 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.
static tree
convert_for_assignment (tree type, tree rhs, 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;
bool objc_ok = false;
- if (errtype == ic_argpass || errtype == ic_argpass_nonproto)
+ if (errtype == ic_argpass)
{
tree selector;
/* Change pointer to function to the function itself for
{ \
case ic_argpass: \
if (pedwarn (LOCATION, OPT, AR, parmnum, rname)) \
- inform (fundecl ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
"expected %qT but argument is of type %qT", \
type, rhstype); \
break; \
- case ic_argpass_nonproto: \
- warning (OPT, AR, parmnum, rname); \
- break; \
case ic_assign: \
pedwarn (LOCATION, OPT, AS); \
break; \
} \
} while (0)
- STRIP_TYPE_NOPS (rhs);
-
- if (optimize && TREE_CODE (rhs) == VAR_DECL
- && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
- rhs = decl_constant_value_for_broken_optimization (rhs);
+ if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
|| coder == FIXED_POINT_TYPE
|| coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
|| coder == BOOLEAN_TYPE))
- return convert_and_check (type, rhs);
+ {
+ tree ret;
+ bool save = in_late_binary_op;
+ if (codel == BOOLEAN_TYPE)
+ in_late_binary_op = true;
+ ret = convert_and_check (type, orig_rhs);
+ if (codel == BOOLEAN_TYPE)
+ in_late_binary_op = save;
+ return ret;
+ }
/* Aggregates in different TUs might need conversion. */
if ((codel == RECORD_TYPE || codel == UNION_TYPE)
/* Conversion to a transparent union from its member types.
This applies only to function arguments. */
if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
- && (errtype == ic_argpass || errtype == ic_argpass_nonproto))
+ && errtype == ic_argpass)
{
tree memb, marginal_memb = NULL_TREE;
}
/* Can convert integer zero to any pointer type. */
- if (null_pointer_constant_p (rhs))
+ if (null_pointer_constant)
{
rhs = null_pointer_node;
break;
switch (errtype)
{
case ic_argpass:
- case ic_argpass_nonproto:
warning (OPT_Wmissing_format_attribute,
"argument %d of %qE might be "
"a candidate for a format attribute",
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
||
(VOID_TYPE_P (ttr)
- && !null_pointer_constant_p (rhs)
+ && !null_pointer_constant
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
WARN_FOR_ASSIGNMENT (input_location, OPT_pedantic,
G_("ISO C forbids passing argument %d of "
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
- if (!null_pointer_constant_p (rhs))
+ if (!null_pointer_constant)
WARN_FOR_ASSIGNMENT (input_location, 0,
G_("passing argument %d of %qE makes "
"pointer from integer without a cast"),
return convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
- return convert (type, rhs);
+ {
+ tree ret;
+ bool save = in_late_binary_op;
+ in_late_binary_op = true;
+ ret = convert (type, rhs);
+ in_late_binary_op = save;
+ return ret;
+ }
switch (errtype)
{
case ic_argpass:
- case ic_argpass_nonproto:
- /* ??? This should not be an error when inlining calls to
- unprototyped functions. */
error ("incompatible type for argument %d of %qE", parmnum, rname);
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
+ ? DECL_SOURCE_LOCATION (fundecl) : input_location,
+ "expected %qT but argument is of type %qT", type, rhstype);
break;
case ic_assign:
- error ("incompatible types in assignment");
+ error ("incompatible types when assigning to type %qT from type %qT",
+ type, rhstype);
break;
case ic_init:
- error ("incompatible types in initialization");
+ error ("incompatible types when initializing type %qT using type %qT",
+ type, rhstype);
break;
case ic_return:
- error ("incompatible types in return");
+ error ("incompatible types when returning type %qT but %qT was expected",
+ rhstype, type);
break;
default:
gcc_unreachable ();
store_init_value (tree decl, tree init)
{
tree value, type;
+ bool npc = false;
/* If variable's type was invalidly declared, just ignore it. */
/* Digest the specified initializer into an expression. */
- value = digest_init (type, init, true, TREE_STATIC (decl));
+ if (init)
+ npc = null_pointer_constant_p (init);
+ value = digest_init (type, init, 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.
+ 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
unparenthesized or we should not warn here for it being parenthesized.
For other types of INIT, STRICT_STRING is not used.
elements are seen. */
static tree
-digest_init (tree type, tree init, bool strict_string, int require_constant)
+digest_init (tree type, tree init, 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
|| !init
STRIP_TYPE_NOPS (inside_init);
- inside_init = fold (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);
/* Initialization of an array of chars from a string constant
optionally enclosed in braces. */
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 (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
return error_mark_node;
}
- if (optimize && TREE_CODE (inside_init) == VAR_DECL)
- inside_init = decl_constant_value_for_broken_optimization (inside_init);
-
/* Compound expressions can only occur here if -pedantic or
-pedantic-errors is specified. In the later case, we always want
an error. In the former case, we simply want a warning. */
error_init ("initializer element is not constant");
inside_init = error_mark_node;
}
+ else if (require_constant && !maybe_const)
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
/* 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_TREE,
- NULL_TREE, 0);
+ inside_init = convert_for_assignment (type, inside_init, ic_init,
+ null_pointer_constant,
+ NULL_TREE, NULL_TREE, 0);
return inside_init;
}
if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
&& (TREE_CODE (init) == STRING_CST
|| TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
- init = array_to_pointer_conversion (init);
+ 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, init, ic_init,
+ = convert_for_assignment (type, inside_init, ic_init,
+ null_pointer_constant,
NULL_TREE, NULL_TREE, 0);
/* Check to see if we have already given an error message. */
error_init ("initializer element is not computable at load time");
inside_init = error_mark_node;
}
+ else if (require_constant && !maybe_const)
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
return inside_init;
}
/* 1 if so far this constructor's elements are all valid address constants. */
static int constructor_simple;
+/* 1 if this constructor has an element that cannot be part of a
+ constant expression. */
+static int constructor_nonconst;
+
/* 1 if this constructor is erroneous so far. */
static int constructor_erroneous;
struct constructor_range_stack *range_stack;
char constant;
char simple;
+ char nonconst;
char implicit;
char erroneous;
char outer;
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->elements = constructor_elements;
p->constant = constructor_constant;
p->simple = constructor_simple;
+ p->nonconst = constructor_nonconst;
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
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;
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_pending_elts = 0;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& constructor_max_index
&& tree_int_cst_lt (constructor_max_index,
constructor_index))
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
else
break;
}
p->elements = constructor_elements;
p->constant = constructor_constant;
p->simple = constructor_simple;
+ p->nonconst = constructor_nonconst;
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
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;
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_incremental = 1;
{
constructor_constant = TREE_CONSTANT (value);
constructor_simple = TREE_STATIC (value);
+ constructor_nonconst = CONSTRUCTOR_NON_CONST (value);
constructor_elements = CONSTRUCTOR_ELTS (value);
if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
struct c_expr ret;
ret.value = 0;
ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
if (implicit == 0)
{
/* When we come to an explicit close brace,
pop any inner levels that didn't have explicit braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
gcc_assert (!constructor_range_stack);
}
TREE_CONSTANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
TREE_STATIC (ret.value) = 1;
+ if (constructor_nonconst)
+ CONSTRUCTOR_NON_CONST (ret.value) = 1;
}
}
+ if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR)
+ {
+ if (constructor_nonconst)
+ ret.original_code = C_MAYBE_CONST_EXPR;
+ else if (ret.original_code == C_MAYBE_CONST_EXPR)
+ ret.original_code = ERROR_MARK;
+ }
+
constructor_type = p->type;
constructor_fields = p->fields;
constructor_index = p->index;
constructor_elements = p->elements;
constructor_constant = p->constant;
constructor_simple = p->simple;
+ constructor_nonconst = p->nonconst;
constructor_erroneous = p->erroneous;
constructor_incremental = p->incremental;
constructor_designated = p->designated;
/* Designator list starts at the level of closest explicit
braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
constructor_designated = 1;
return 0;
}
error_init ("array index in initializer exceeds array bounds");
else
{
+ constant_expression_warning (first);
+ if (last)
+ constant_expression_warning (last);
constructor_index = convert (bitsizetype, first);
if (last)
\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.
+
+ IMPLICIT is true if value comes from pop_init_level (1),
+ the new initializer has been merged with the existing one
+ and thus no warnings should be emitted about overriding an
+ existing initializer. */
static void
-add_pending_init (tree purpose, tree value)
+add_pending_init (tree purpose, tree value, bool implicit)
{
struct init_node *p, **q, *r;
q = &p->right;
else
{
- if (TREE_SIDE_EFFECTS (p->value))
- warning_init (0, "initialized field with side-effects overwritten");
- else if (warn_override_init)
- warning_init (OPT_Woverride_init, "initialized field overwritten");
+ if (!implicit)
+ {
+ if (TREE_SIDE_EFFECTS (p->value))
+ warning_init (0, "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
+ }
p->value = value;
return;
}
q = &p->right;
else
{
- if (TREE_SIDE_EFFECTS (p->value))
- warning_init (0, "initialized field with side-effects overwritten");
- else if (warn_override_init)
- warning_init (OPT_Woverride_init, "initialized field overwritten");
+ if (!implicit)
+ {
+ if (TREE_SIDE_EFFECTS (p->value))
+ warning_init (0, "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
+ }
p->value = value;
return;
}
return;
FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
- add_pending_init (index, value);
+ add_pending_init (index, value, 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);
+ add_pending_init (purpose, value, false);
}
constructor_incremental = 0;
PENDING if non-nil means output pending elements that belong
right after this element. (PENDING is normally 1;
- it is 0 while outputting pending elements, to avoid recursion.) */
+ it is 0 while outputting pending elements, to avoid recursion.)
+
+ IMPLICIT is true if value comes from pop_init_level (1),
+ the new initializer has been merged with the existing one
+ and thus no warnings should be emitted about overriding an
+ existing initializer. */
static void
output_init_element (tree value, bool strict_string, tree type, tree field,
- int pending)
+ int pending, bool implicit)
{
+ tree semantic_type = NULL_TREE;
constructor_elt *celt;
+ bool maybe_const = true;
+ bool npc;
if (type == error_mark_node || value == error_mark_node)
{
value = DECL_INITIAL (decl);
}
+ 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)
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
&& DECL_C_BIT_FIELD (field)
&& TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
+ if (!maybe_const)
+ constructor_nonconst = 1;
if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
{
pedwarn (input_location, 0,
"initializer element is not computable at load time");
}
+ else if (!maybe_const
+ && (require_constant_value || require_constant_elements))
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
/* If this field is empty (and not at the end of structure),
don't do anything other than checking the initializer. */
|| TREE_CHAIN (field)))))
return;
- value = digest_init (type, value, strict_string, require_constant_value);
+ if (semantic_type)
+ value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value);
+ value = digest_init (type, value, npc, strict_string,
+ require_constant_value);
if (value == error_mark_node)
{
constructor_erroneous = 1;
return;
}
+ if (require_constant_value || require_constant_elements)
+ constant_expression_warning (value);
/* If this element doesn't come next in sequence,
put it on constructor_pending_elts. */
&& tree_int_cst_lt (field, constructor_unfilled_index))
set_nonincremental_init ();
- add_pending_init (field, value);
+ add_pending_init (field, value, implicit);
return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
}
}
- add_pending_init (field, value);
+ add_pending_init (field, value, implicit);
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
&& !VEC_empty (constructor_elt, constructor_elements))
{
- if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
- constructor_elements)->value))
- warning_init (0, "initialized field with side-effects overwritten");
- else if (warn_override_init)
- warning_init (OPT_Woverride_init, "initialized field overwritten");
+ if (!implicit)
+ {
+ if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
+ constructor_elements)->value))
+ warning_init (0,
+ "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
+ }
/* We can have just one union field set. */
constructor_elements = 0;
constructor_unfilled_index))
output_init_element (elt->value, true,
TREE_TYPE (constructor_type),
- constructor_unfilled_index, 0);
+ constructor_unfilled_index, 0, false);
else if (tree_int_cst_lt (constructor_unfilled_index,
elt->purpose))
{
{
constructor_unfilled_fields = elt->purpose;
output_init_element (elt->value, true, TREE_TYPE (elt->purpose),
- elt->purpose, 0);
+ elt->purpose, 0, false);
}
else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
{
to handle a partly-braced initializer.
Once this has found the correct level for the new element,
- it calls output_init_element. */
+ it calls output_init_element.
+
+ IMPLICIT is true if value comes from pop_init_level (1),
+ the new initializer has been merged with the existing one
+ and thus no warnings should be emitted about overriding an
+ existing initializer. */
void
-process_init_element (struct c_expr value)
+process_init_element (struct c_expr value, bool implicit)
{
tree orig_value = value.value;
int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& (constructor_max_index == 0
|| tree_int_cst_lt (constructor_max_index,
constructor_index)))
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
else
break;
}
if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
|| !require_constant_value
|| flag_isoc99)
- value.value = 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)
{
push_member_name (constructor_fields);
output_init_element (value.value, strict_string,
- fieldtype, constructor_fields, 1);
+ fieldtype, constructor_fields, 1, implicit);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
{
push_member_name (constructor_fields);
output_init_element (value.value, strict_string,
- fieldtype, constructor_fields, 1);
+ fieldtype, constructor_fields, 1, implicit);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
{
push_array_bounds (tree_low_cst (constructor_index, 1));
output_init_element (value.value, strict_string,
- elttype, constructor_index, 1);
+ 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);
+ elttype, constructor_index, 1, implicit);
constructor_index
= size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
{
if (value.value)
output_init_element (value.value, strict_string,
- constructor_type, NULL_TREE, 1);
+ constructor_type, NULL_TREE, 1, implicit);
constructor_fields = 0;
}
while (constructor_stack != range_stack->stack)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
}
for (p = range_stack;
!p->range_end || tree_int_cst_equal (p->index, p->range_end);
p = p->prev)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1));
+ process_init_element (pop_init_level (1), true);
}
p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
c_finish_goto_ptr (tree expr)
{
pedwarn (input_location, OPT_pedantic, "ISO C forbids %<goto *expr;%>");
+ expr = c_fully_fold (expr, false, NULL);
expr = convert (ptr_type_node, expr);
return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt;
bool no_warning = false;
+ bool npc = false;
if (TREE_THIS_VOLATILE (current_function_decl))
warning (0, "function declared %<noreturn%> has a %<return%> statement");
+ 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)
{
current_function_returns_null = 1;
}
else
{
- tree t = convert_for_assignment (valtype, retval, ic_return,
+ tree t = convert_for_assignment (valtype, retval, ic_return, npc,
NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
tree inner;
{
switch (TREE_CODE (inner))
{
- CASE_CONVERT: case NON_LVALUE_EXPR:
+ CASE_CONVERT:
+ case NON_LVALUE_EXPR:
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
inner = TREE_OPERAND (inner, 0);
continue;
warning (OPT_Wtraditional, "%<long%> switch expression not "
"converted to %<int%> in ISO C");
+ exp = c_fully_fold (exp, false, NULL);
exp = default_conversion (exp);
if (warn_sequence_point)
{
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)
{
&if_locus);
}
- empty_if_body_warning (then_block, else_block);
-
stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
SET_EXPR_LOCATION (stmt, if_locus);
add_stmt (stmt);
if (!expr)
return NULL_TREE;
+ expr = c_fully_fold (expr, false, NULL);
+
if (warn_sequence_point)
verify_sequence_points (expr);
|| (last == BIND_EXPR_BODY (body)
&& BIND_EXPR_VARS (body) == NULL))
{
+ /* Even if this looks constant, do not allow it in a constant
+ expression. */
+ last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
+ C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
/* Do not warn if the return value of a statement expression is
unused. */
- if (CAN_HAVE_LOCATION_P (last))
- TREE_NO_WARNING (last) = 1;
+ TREE_NO_WARNING (last) = 1;
return last;
}
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.
Normally this is CODE, which is what the caller asked for,
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;
- if (convert_p)
+ 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)
{
- op0 = default_conversion (orig_op0);
- op1 = default_conversion (orig_op1);
+ int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST
+ && TREE_CODE (orig_op1) == INTEGER_CST);
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && !TREE_OVERFLOW (orig_op1));
}
else
+ int_const = int_const_or_overflow = false;
+
+ if (convert_p)
{
- 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)
case PLUS_EXPR:
/* Handle the pointer + int case. */
if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
- return pointer_int_sum (PLUS_EXPR, op0, op1);
+ {
+ ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
+ goto return_build_binary_op;
+ }
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
- return pointer_int_sum (PLUS_EXPR, op1, op0);
+ {
+ ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
+ goto return_build_binary_op;
+ }
else
common = 1;
break;
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
&& comp_target_types (type0, type1))
- return pointer_diff (op0, op1);
+ {
+ ret = pointer_diff (op0, op1);
+ goto return_build_binary_op;
+ }
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
- return pointer_int_sum (MINUS_EXPR, op0, op1);
+ {
+ ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
+ goto return_build_binary_op;
+ }
else
common = 1;
break;
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
- warn_for_div_by_zero (op1);
+ warn_for_div_by_zero (location, op1);
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == FIXED_POINT_TYPE
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
- warn_for_div_by_zero (op1);
+ warn_for_div_by_zero (location, op1);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
op1 = c_common_truthvalue_conversion (location, op1);
converted = 1;
}
+ if (code == TRUTH_ANDIF_EXPR)
+ {
+ int_const_or_overflow = (int_operands
+ && TREE_CODE (orig_op0) == INTEGER_CST
+ && (op0 == truthvalue_false_node
+ || TREE_CODE (orig_op1) == INTEGER_CST));
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && (op0 == truthvalue_false_node
+ || !TREE_OVERFLOW (orig_op1)));
+ }
+ else if (code == TRUTH_ORIF_EXPR)
+ {
+ int_const_or_overflow = (int_operands
+ && TREE_CODE (orig_op0) == INTEGER_CST
+ && (op0 == truthvalue_true_node
+ || TREE_CODE (orig_op1) == INTEGER_CST));
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && (op0 == truthvalue_true_node
+ || !TREE_OVERFLOW (orig_op1)));
+ }
break;
/* Shift operations: result has same type as first operand;
if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+ if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_sgn (op1) < 0)
- warning (0, "right shift count is negative");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "right shift count is negative");
+ }
else
{
if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, "right shift count >= width of type");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "right shift count >= width of type");
+ }
}
}
if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+ if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_sgn (op1) < 0)
- warning (0, "left shift count is negative");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "left shift count is negative");
+ }
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, "left shift count >= width of type");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "left shift count >= width of type");
+ }
}
/* Use the type of the value to be shifted. */
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
- return val;
+ {
+ ret = val;
+ goto return_build_binary_op;
+ }
op0 = xop0, op1 = xop1;
converted = 1;
resultcode = xresultcode;
- if (warn_sign_compare && !skip_evaluation)
- {
- warn_for_sign_compare (location, orig_op0, orig_op1, op0, op1,
- result_type, resultcode);
+ if (!skip_evaluation)
+ {
+ bool op0_maybe_const = true;
+ bool op1_maybe_const = true;
+ tree orig_op0_folded, orig_op1_folded;
+
+ if (in_late_binary_op)
+ {
+ orig_op0_folded = orig_op0;
+ orig_op1_folded = orig_op1;
+ }
+ else
+ {
+ /* Fold for the sake of possible warnings, as in
+ build_conditional_expr. This requires the
+ "original" values to be folded, not just op0 and
+ op1. */
+ op0 = c_fully_fold (op0, require_constant_value,
+ &op0_maybe_const);
+ op1 = c_fully_fold (op1, require_constant_value,
+ &op1_maybe_const);
+ orig_op0_folded = c_fully_fold (orig_op0,
+ require_constant_value,
+ NULL);
+ orig_op1_folded = c_fully_fold (orig_op1,
+ require_constant_value,
+ NULL);
+ }
+
+ if (warn_sign_compare)
+ warn_for_sign_compare (location, orig_op0_folded,
+ orig_op1_folded, op0, op1,
+ result_type, resultcode);
+ if (!in_late_binary_op)
+ {
+ if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
+ {
+ op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0),
+ NULL, op0);
+ C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const;
+ }
+ if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
+ {
+ op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
+ NULL, op1);
+ C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
+ }
+ }
}
}
}
}
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. */
- tree result = require_constant_value ? fold_build2_initializer (resultcode,
- build_type,
- op0, op1)
- : fold_build2 (resultcode, build_type,
- op0, op1);
-
- if (final_type != 0)
- result = convert (final_type, result);
- return result;
- }
+ /* Treat expressions in initializers specially as they can't trap. */
+ if (int_const_or_overflow)
+ ret = (require_constant_value
+ ? fold_build2_initializer (resultcode, build_type, op0, op1)
+ : fold_build2 (resultcode, build_type, op0, op1));
+ else
+ ret = build2 (resultcode, build_type, op0, op1);
+ if (final_type != 0)
+ ret = convert (final_type, ret);
+
+ return_build_binary_op:
+ gcc_assert (ret != error_mark_node);
+ if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const)
+ ret = (int_operands
+ ? note_integer_operands (ret)
+ : build1 (NOP_EXPR, TREE_TYPE (ret), ret));
+ 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;
}
tree
c_objc_common_truthvalue_conversion (location_t location, tree expr)
{
+ bool int_const, int_operands;
+
switch (TREE_CODE (TREE_TYPE (expr)))
{
case ARRAY_TYPE:
break;
}
+ 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? */
- return c_common_truthvalue_conversion (location, expr);
+ expr = c_common_truthvalue_conversion (location, expr);
+
+ if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
+ {
+ if (TREE_OVERFLOW (expr))
+ return expr;
+ else
+ return note_integer_operands (expr);
+ }
+ if (TREE_CODE (expr) == INTEGER_CST && !int_const)
+ return build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+ return expr;
}
\f