| Index: gcc/gcc/c-typeck.c
|
| diff --git a/gcc/gcc/c-typeck.c b/gcc/gcc/c-typeck.c
|
| index d9c0c1e2216b34e398573bf9046ba85b560f1d60..89e534aa0b3f4492ed1259256a560209777d3654 100644
|
| --- a/gcc/gcc/c-typeck.c
|
| +++ b/gcc/gcc/c-typeck.c
|
| @@ -1,6 +1,6 @@
|
| /* 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, 2009
|
| + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
| Free Software Foundation, Inc.
|
|
|
| This file is part of GCC.
|
| @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
|
| #include "tree.h"
|
| #include "langhooks.h"
|
| #include "c-tree.h"
|
| +#include "c-lang.h"
|
| #include "tm_p.h"
|
| #include "flags.h"
|
| #include "output.h"
|
| @@ -54,6 +55,13 @@ enum impl_conv {
|
| 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;
|
|
|
| @@ -63,9 +71,6 @@ int in_sizeof;
|
| /* The level of nesting inside "typeof". */
|
| int in_typeof;
|
|
|
| -struct c_label_context_se *label_context_stack_se;
|
| -struct c_label_context_vm *label_context_stack_vm;
|
| -
|
| /* Nonzero if we've already printed a "missing braces around initializer"
|
| message within this initializer. */
|
| static int missing_braces_mentioned;
|
| @@ -75,36 +80,36 @@ static int require_constant_elements;
|
|
|
| static bool null_pointer_constant_p (const_tree);
|
| static tree qualify_type (tree, tree);
|
| -static int tagged_types_tu_compatible_p (const_tree, const_tree);
|
| -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 int tagged_types_tu_compatible_p (const_tree, const_tree, bool *);
|
| +static int comp_target_types (location_t, tree, tree);
|
| +static int function_types_compatible_p (const_tree, const_tree, bool *);
|
| +static int type_lists_compatible_p (const_tree, const_tree, bool *);
|
| 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 int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree,
|
| + tree);
|
| +static tree pointer_diff (location_t, tree, tree);
|
| +static tree convert_for_assignment (location_t, 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 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, bool);
|
| +static tree digest_init (location_t, 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);
|
| +static int comptypes_internal (const_tree, const_tree, bool *);
|
|
|
| /* Return true if EXP is a null pointer constant, false otherwise. */
|
|
|
| @@ -122,6 +127,43 @@ null_pointer_constant_p (const_tree expr)
|
| && 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;
|
| +}
|
| +
|
| /* This is a cache to hold if two types are compatible or not. */
|
|
|
| struct tagged_tu_seen_cache {
|
| @@ -242,14 +284,55 @@ c_type_promotes_to (tree type)
|
| return type;
|
| }
|
|
|
| +/* Return true if between two named address spaces, whether there is a superset
|
| + named address space that encompasses both address spaces. If there is a
|
| + superset, return which address space is the superset. */
|
| +
|
| +static bool
|
| +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common)
|
| +{
|
| + if (as1 == as2)
|
| + {
|
| + *common = as1;
|
| + return true;
|
| + }
|
| + else if (targetm.addr_space.subset_p (as1, as2))
|
| + {
|
| + *common = as2;
|
| + return true;
|
| + }
|
| + else if (targetm.addr_space.subset_p (as2, as1))
|
| + {
|
| + *common = as1;
|
| + return true;
|
| + }
|
| + else
|
| + return false;
|
| +}
|
| +
|
| /* Return a variant of TYPE which has all the type qualifiers of LIKE
|
| as well as those of TYPE. */
|
|
|
| static tree
|
| qualify_type (tree type, tree like)
|
| {
|
| + addr_space_t as_type = TYPE_ADDR_SPACE (type);
|
| + addr_space_t as_like = TYPE_ADDR_SPACE (like);
|
| + addr_space_t as_common;
|
| +
|
| + /* If the two named address spaces are different, determine the common
|
| + superset address space. If there isn't one, raise an error. */
|
| + if (!addr_space_superset (as_type, as_like, &as_common))
|
| + {
|
| + as_common = as_type;
|
| + error ("%qT and %qT are in disjoint named address spaces",
|
| + type, like);
|
| + }
|
| +
|
| return c_build_qualified_type (type,
|
| - TYPE_QUALS (type) | TYPE_QUALS (like));
|
| + TYPE_QUALS_NO_ADDR_SPACE (type)
|
| + | TYPE_QUALS_NO_ADDR_SPACE (like)
|
| + | ENCODE_QUAL_ADDR_SPACE (as_common));
|
| }
|
|
|
| /* Return true iff the given tree T is a variable length array. */
|
| @@ -329,7 +412,8 @@ composite_type (tree t1, tree t2)
|
| bool t1_complete, t2_complete;
|
|
|
| /* We should not have any type quals on arrays at all. */
|
| - gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
|
| + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1)
|
| + && !TYPE_QUALS_NO_ADDR_SPACE (t2));
|
|
|
| t1_complete = COMPLETE_TYPE_P (t1);
|
| t2_complete = COMPLETE_TYPE_P (t2);
|
| @@ -482,7 +566,7 @@ composite_type (tree t1, tree t2)
|
| {
|
| TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
|
| TREE_VALUE (p2));
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (input_location, OPT_pedantic,
|
| "function types not truly compatible in ISO C");
|
| goto parm_done;
|
| }
|
| @@ -507,7 +591,7 @@ composite_type (tree t1, tree t2)
|
| {
|
| TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
|
| TREE_VALUE (p1));
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (input_location, OPT_pedantic,
|
| "function types not truly compatible in ISO C");
|
| goto parm_done;
|
| }
|
| @@ -543,6 +627,8 @@ common_pointer_type (tree t1, tree t2)
|
| tree pointed_to_2, mv2;
|
| tree target;
|
| unsigned target_quals;
|
| + addr_space_t as1, as2, as_common;
|
| + int quals1, quals2;
|
|
|
| /* Save time if the two types are the same. */
|
|
|
| @@ -574,10 +660,24 @@ common_pointer_type (tree t1, tree t2)
|
| /* For function types do not merge const qualifiers, but drop them
|
| if used inconsistently. The middle-end uses these to mark const
|
| and noreturn functions. */
|
| + quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
|
| + quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
|
| +
|
| if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
|
| - target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2);
|
| + target_quals = (quals1 & quals2);
|
| else
|
| - target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2);
|
| + target_quals = (quals1 | quals2);
|
| +
|
| + /* If the two named address spaces are different, determine the common
|
| + superset address space. This is guaranteed to exist due to the
|
| + assumption that comp_target_type returned non-zero. */
|
| + as1 = TYPE_ADDR_SPACE (pointed_to_1);
|
| + as2 = TYPE_ADDR_SPACE (pointed_to_2);
|
| + if (!addr_space_superset (as1, as2, &as_common))
|
| + gcc_unreachable ();
|
| +
|
| + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
|
| +
|
| t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
|
| return build_type_attribute_variant (t1, attributes);
|
| }
|
| @@ -875,7 +975,22 @@ comptypes (tree type1, tree type2)
|
| const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
|
| int val;
|
|
|
| - val = comptypes_internal (type1, type2);
|
| + val = comptypes_internal (type1, type2, NULL);
|
| + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
|
| +
|
| + return val;
|
| +}
|
| +
|
| +/* Like comptypes, but if it returns non-zero because enum and int are
|
| + compatible, it sets *ENUM_AND_INT_P to true. */
|
| +
|
| +static int
|
| +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
|
| +{
|
| + const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
|
| + int val;
|
| +
|
| + val = comptypes_internal (type1, type2, enum_and_int_p);
|
| free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
|
|
|
| return val;
|
| @@ -883,11 +998,14 @@ comptypes (tree type1, tree type2)
|
|
|
| /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
|
| or various other operations. Return 2 if they are compatible
|
| - but a warning may be needed if you use them together. This
|
| - differs from comptypes, in that we don't free the seen types. */
|
| + but a warning may be needed if you use them together. If
|
| + ENUM_AND_INT_P is not NULL, and one type is an enum and the other a
|
| + compatible integer type, then this sets *ENUM_AND_INT_P to true;
|
| + *ENUM_AND_INT_P is never set to false. This differs from
|
| + comptypes, in that we don't free the seen types. */
|
|
|
| static int
|
| -comptypes_internal (const_tree type1, const_tree type2)
|
| +comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p)
|
| {
|
| const_tree t1 = type1;
|
| const_tree t2 = type2;
|
| @@ -915,9 +1033,17 @@ comptypes_internal (const_tree type1, const_tree type2)
|
| are compatible with each other only if they are the same type. */
|
|
|
| if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
|
| - t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
|
| + {
|
| + t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
|
| + if (enum_and_int_p != NULL && TREE_CODE (t2) != VOID_TYPE)
|
| + *enum_and_int_p = true;
|
| + }
|
| else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE)
|
| - t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
|
| + {
|
| + t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
|
| + if (enum_and_int_p != NULL && TREE_CODE (t1) != VOID_TYPE)
|
| + *enum_and_int_p = true;
|
| + }
|
|
|
| if (t1 == t2)
|
| return 1;
|
| @@ -955,11 +1081,12 @@ comptypes_internal (const_tree type1, const_tree type2)
|
| || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
|
| break;
|
| val = (TREE_TYPE (t1) == TREE_TYPE (t2)
|
| - ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2)));
|
| + ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
|
| + enum_and_int_p));
|
| break;
|
|
|
| case FUNCTION_TYPE:
|
| - val = function_types_compatible_p (t1, t2);
|
| + val = function_types_compatible_p (t1, t2, enum_and_int_p);
|
| break;
|
|
|
| case ARRAY_TYPE:
|
| @@ -972,7 +1099,8 @@ comptypes_internal (const_tree type1, const_tree type2)
|
|
|
| /* Target types must match incl. qualifiers. */
|
| if (TREE_TYPE (t1) != TREE_TYPE (t2)
|
| - && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2))))
|
| + && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
|
| + enum_and_int_p)))
|
| return 0;
|
|
|
| /* Sizes must match unless one is missing or variable. */
|
| @@ -1016,14 +1144,15 @@ comptypes_internal (const_tree type1, const_tree type2)
|
| break;
|
|
|
| if (attrval != 2)
|
| - return tagged_types_tu_compatible_p (t1, t2);
|
| - val = tagged_types_tu_compatible_p (t1, t2);
|
| + return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
|
| + val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
|
| }
|
| break;
|
|
|
| case VECTOR_TYPE:
|
| - val = TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
|
| - && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2));
|
| + val = (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
|
| + && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
|
| + enum_and_int_p));
|
| break;
|
|
|
| default:
|
| @@ -1032,27 +1161,42 @@ comptypes_internal (const_tree type1, const_tree type2)
|
| return attrval == 2 && val == 1 ? 2 : val;
|
| }
|
|
|
| -/* Return 1 if TTL and TTR are pointers to types that are equivalent,
|
| - ignoring their qualifiers. */
|
| +/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring
|
| + their qualifiers, except for named address spaces. If the pointers point to
|
| + different named addresses, then we must determine if one address space is a
|
| + subset of the other. */
|
|
|
| static int
|
| -comp_target_types (tree ttl, tree ttr)
|
| +comp_target_types (location_t location, tree ttl, tree ttr)
|
| {
|
| int val;
|
| - tree mvl, mvr;
|
| + tree mvl = TREE_TYPE (ttl);
|
| + tree mvr = TREE_TYPE (ttr);
|
| + addr_space_t asl = TYPE_ADDR_SPACE (mvl);
|
| + addr_space_t asr = TYPE_ADDR_SPACE (mvr);
|
| + addr_space_t as_common;
|
| + bool enum_and_int_p;
|
| +
|
| + /* Fail if pointers point to incompatible address spaces. */
|
| + if (!addr_space_superset (asl, asr, &as_common))
|
| + return 0;
|
|
|
| /* Do not lose qualifiers on element types of array types that are
|
| pointer targets by taking their TYPE_MAIN_VARIANT. */
|
| - mvl = TREE_TYPE (ttl);
|
| - mvr = TREE_TYPE (ttr);
|
| if (TREE_CODE (mvl) != ARRAY_TYPE)
|
| mvl = TYPE_MAIN_VARIANT (mvl);
|
| if (TREE_CODE (mvr) != ARRAY_TYPE)
|
| mvr = TYPE_MAIN_VARIANT (mvr);
|
| - val = comptypes (mvl, mvr);
|
| + enum_and_int_p = false;
|
| + val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
|
|
|
| if (val == 2)
|
| - pedwarn (input_location, OPT_pedantic, "types are not quite compatible");
|
| + pedwarn (location, OPT_pedantic, "types are not quite compatible");
|
| +
|
| + if (val == 1 && enum_and_int_p && warn_cxx_compat)
|
| + warning_at (location, OPT_Wc___compat,
|
| + "pointer target types incompatible in C++");
|
| +
|
| return val;
|
| }
|
|
|
| @@ -1140,10 +1284,11 @@ free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til)
|
| compatible. If the two types are not the same (which has been
|
| checked earlier), this can only happen when multiple translation
|
| units are being compiled. See C99 6.2.7 paragraph 1 for the exact
|
| - rules. */
|
| + rules. ENUM_AND_INT_P is as in comptypes_internal. */
|
|
|
| static int
|
| -tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
|
| +tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
|
| + bool *enum_and_int_p)
|
| {
|
| tree s1, s2;
|
| bool needs_warning = false;
|
| @@ -1253,7 +1398,8 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
|
|
|
| if (DECL_NAME (s1) != DECL_NAME (s2))
|
| break;
|
| - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
|
| + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
|
| + enum_and_int_p);
|
|
|
| if (result != 1 && !DECL_NAME (s1))
|
| break;
|
| @@ -1288,7 +1434,8 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
|
| {
|
| int result;
|
|
|
| - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
|
| + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
|
| + enum_and_int_p);
|
|
|
| if (result != 1 && !DECL_NAME (s1))
|
| continue;
|
| @@ -1330,7 +1477,8 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
|
| if (TREE_CODE (s1) != TREE_CODE (s2)
|
| || DECL_NAME (s1) != DECL_NAME (s2))
|
| break;
|
| - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
|
| + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
|
| + enum_and_int_p);
|
| if (result == 0)
|
| break;
|
| if (result == 2)
|
| @@ -1358,10 +1506,12 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
|
| the other must specify a fixed number of self-promoting arg types.
|
| Otherwise, if one type specifies only the number of arguments,
|
| the other must specify that number of self-promoting arg types.
|
| - Otherwise, the argument types must match. */
|
| + Otherwise, the argument types must match.
|
| + ENUM_AND_INT_P is as in comptypes_internal. */
|
|
|
| static int
|
| -function_types_compatible_p (const_tree f1, const_tree f2)
|
| +function_types_compatible_p (const_tree f1, const_tree f2,
|
| + bool *enum_and_int_p)
|
| {
|
| tree args1, args2;
|
| /* 1 if no need for warning yet, 2 if warning cause has been seen. */
|
| @@ -1382,7 +1532,7 @@ function_types_compatible_p (const_tree f1, const_tree f2)
|
| if (TYPE_VOLATILE (ret2))
|
| ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
|
| TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
|
| - val = comptypes_internal (ret1, ret2);
|
| + val = comptypes_internal (ret1, ret2, enum_and_int_p);
|
| if (val == 0)
|
| return 0;
|
|
|
| @@ -1400,7 +1550,8 @@ function_types_compatible_p (const_tree f1, const_tree f2)
|
| compare that with the other type's arglist.
|
| If they don't match, ask for a warning (but no error). */
|
| if (TYPE_ACTUAL_ARG_TYPES (f1)
|
| - && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
|
| + && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
|
| + enum_and_int_p))
|
| val = 2;
|
| return val;
|
| }
|
| @@ -1409,22 +1560,24 @@ function_types_compatible_p (const_tree f1, const_tree f2)
|
| if (!self_promoting_args_p (args1))
|
| return 0;
|
| if (TYPE_ACTUAL_ARG_TYPES (f2)
|
| - && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2)))
|
| + && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
|
| + enum_and_int_p))
|
| val = 2;
|
| return val;
|
| }
|
|
|
| /* Both types have argument lists: compare them and propagate results. */
|
| - val1 = type_lists_compatible_p (args1, args2);
|
| + val1 = type_lists_compatible_p (args1, args2, enum_and_int_p);
|
| return val1 != 1 ? val1 : val;
|
| }
|
|
|
| -/* Check two lists of types for compatibility,
|
| - returning 0 for incompatible, 1 for compatible,
|
| - or 2 for compatible with warning. */
|
| +/* Check two lists of types for compatibility, returning 0 for
|
| + incompatible, 1 for compatible, or 2 for compatible with
|
| + warning. ENUM_AND_INT_P is as in comptypes_internal. */
|
|
|
| static int
|
| -type_lists_compatible_p (const_tree args1, const_tree args2)
|
| +type_lists_compatible_p (const_tree args1, const_tree args2,
|
| + bool *enum_and_int_p)
|
| {
|
| /* 1 if no need for warning yet, 2 if warning cause has been seen. */
|
| int val = 1;
|
| @@ -1463,13 +1616,13 @@ type_lists_compatible_p (const_tree args1, const_tree args2)
|
| else if (TREE_CODE (a1) == ERROR_MARK
|
| || TREE_CODE (a2) == ERROR_MARK)
|
| ;
|
| - else if (!(newval = comptypes_internal (mv1, mv2)))
|
| + else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p)))
|
| {
|
| /* Allow wait (union {union wait *u; int *i} *)
|
| and wait (union wait *) to be compatible. */
|
| if (TREE_CODE (a1) == UNION_TYPE
|
| && (TYPE_NAME (a1) == 0
|
| - || TYPE_TRANSPARENT_UNION (a1))
|
| + || TYPE_TRANSPARENT_AGGR (a1))
|
| && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
|
| && tree_int_cst_equal (TYPE_SIZE (a1),
|
| TYPE_SIZE (a2)))
|
| @@ -1482,7 +1635,7 @@ type_lists_compatible_p (const_tree args1, const_tree args2)
|
| if (mv3 && mv3 != error_mark_node
|
| && TREE_CODE (mv3) != ARRAY_TYPE)
|
| mv3 = TYPE_MAIN_VARIANT (mv3);
|
| - if (comptypes_internal (mv3, mv2))
|
| + if (comptypes_internal (mv3, mv2, enum_and_int_p))
|
| break;
|
| }
|
| if (memb == 0)
|
| @@ -1490,7 +1643,7 @@ type_lists_compatible_p (const_tree args1, const_tree args2)
|
| }
|
| else if (TREE_CODE (a2) == UNION_TYPE
|
| && (TYPE_NAME (a2) == 0
|
| - || TYPE_TRANSPARENT_UNION (a2))
|
| + || TYPE_TRANSPARENT_AGGR (a2))
|
| && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
|
| && tree_int_cst_equal (TYPE_SIZE (a2),
|
| TYPE_SIZE (a1)))
|
| @@ -1503,7 +1656,7 @@ type_lists_compatible_p (const_tree args1, const_tree args2)
|
| if (mv3 && mv3 != error_mark_node
|
| && TREE_CODE (mv3) != ARRAY_TYPE)
|
| mv3 = TYPE_MAIN_VARIANT (mv3);
|
| - if (comptypes_internal (mv3, mv1))
|
| + if (comptypes_internal (mv3, mv1, enum_and_int_p))
|
| break;
|
| }
|
| if (memb == 0)
|
| @@ -1539,9 +1692,9 @@ c_size_in_bytes (const_tree type)
|
| }
|
|
|
| /* Convert in case a char is more than one unit. */
|
| - return size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
|
| - size_int (TYPE_PRECISION (char_type_node)
|
| - / BITS_PER_UNIT));
|
| + return size_binop_loc (input_location, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
|
| + size_int (TYPE_PRECISION (char_type_node)
|
| + / BITS_PER_UNIT));
|
| }
|
|
|
| /* Return either DECL or its known constant value (if it has one). */
|
| @@ -1568,34 +1721,9 @@ decl_constant_value (tree decl)
|
| 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)
|
| +array_to_pointer_conversion (location_t loc, tree exp)
|
| {
|
| tree orig_exp = exp;
|
| tree type = TREE_TYPE (exp);
|
| @@ -1615,28 +1743,13 @@ array_to_pointer_conversion (tree exp)
|
| if (TREE_CODE (exp) == INDIRECT_REF)
|
| return convert (ptrtype, TREE_OPERAND (exp, 0));
|
|
|
| - if (TREE_CODE (exp) == VAR_DECL)
|
| - {
|
| - /* We are making an ADDR_EXPR of ptrtype. This is a valid
|
| - ADDR_EXPR because it's the best way of representing what
|
| - happens in C when we take the address of an array and place
|
| - it in a pointer to the element type. */
|
| - adr = build1 (ADDR_EXPR, ptrtype, exp);
|
| - if (!c_mark_addressable (exp))
|
| - return error_mark_node;
|
| - TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
|
| - return adr;
|
| - }
|
| -
|
| - /* This way is better for a COMPONENT_REF since it can
|
| - simplify the offset for a component. */
|
| - adr = build_unary_op (EXPR_LOCATION (exp), ADDR_EXPR, exp, 1);
|
| + adr = build_unary_op (loc, ADDR_EXPR, exp, 1);
|
| return convert (ptrtype, adr);
|
| }
|
|
|
| /* Convert the function expression EXP to a pointer. */
|
| static tree
|
| -function_to_pointer_conversion (tree exp)
|
| +function_to_pointer_conversion (location_t loc, tree exp)
|
| {
|
| tree orig_exp = exp;
|
|
|
| @@ -1647,15 +1760,17 @@ function_to_pointer_conversion (tree exp)
|
| if (TREE_NO_WARNING (orig_exp))
|
| TREE_NO_WARNING (exp) = 1;
|
|
|
| - return build_unary_op (EXPR_LOCATION (exp), ADDR_EXPR, exp, 0);
|
| + return build_unary_op (loc, 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.
|
| +
|
| + LOC is the location of the expression. */
|
|
|
| struct c_expr
|
| -default_function_array_conversion (struct c_expr exp)
|
| +default_function_array_conversion (location_t loc, struct c_expr exp)
|
| {
|
| tree orig_exp = exp.value;
|
| tree type = TREE_TYPE (exp.value);
|
| @@ -1690,16 +1805,13 @@ default_function_array_conversion (struct c_expr exp)
|
| return exp;
|
| }
|
|
|
| - exp.value = array_to_pointer_conversion (exp.value);
|
| + exp.value = array_to_pointer_conversion (loc, exp.value);
|
| }
|
| break;
|
| case FUNCTION_TYPE:
|
| - exp.value = function_to_pointer_conversion (exp.value);
|
| + exp.value = function_to_pointer_conversion (loc, exp.value);
|
| break;
|
| default:
|
| - STRIP_TYPE_NOPS (exp.value);
|
| - if (TREE_NO_WARNING (orig_exp))
|
| - TREE_NO_WARNING (exp.value) = 1;
|
| break;
|
| }
|
|
|
| @@ -1765,6 +1877,7 @@ default_conversion (tree exp)
|
| tree orig_exp;
|
| tree type = TREE_TYPE (exp);
|
| enum tree_code code = TREE_CODE (type);
|
| + tree promoted_type;
|
|
|
| /* Functions and arrays have been converted during parsing. */
|
| gcc_assert (code != FUNCTION_TYPE);
|
| @@ -1775,15 +1888,6 @@ default_conversion (tree exp)
|
| 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);
|
| @@ -1801,6 +1905,10 @@ default_conversion (tree exp)
|
| if (exp == error_mark_node)
|
| return error_mark_node;
|
|
|
| + promoted_type = targetm.promoted_type (type);
|
| + if (promoted_type)
|
| + return convert (promoted_type, exp);
|
| +
|
| if (INTEGRAL_TYPE_P (type))
|
| return perform_integral_promotions (exp);
|
|
|
| @@ -1902,16 +2010,18 @@ lookup_field (tree decl, tree component)
|
| return tree_cons (NULL_TREE, field, NULL_TREE);
|
| }
|
|
|
| -/* Make an expression to refer to the COMPONENT field of
|
| - structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. */
|
| +/* Make an expression to refer to the COMPONENT field of structure or
|
| + union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
|
| + location of the COMPONENT_REF. */
|
|
|
| tree
|
| -build_component_ref (tree datum, tree component)
|
| +build_component_ref (location_t loc, tree datum, tree component)
|
| {
|
| tree type = TREE_TYPE (datum);
|
| 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;
|
| @@ -1930,7 +2040,7 @@ build_component_ref (tree datum, tree component)
|
|
|
| if (!field)
|
| {
|
| - error ("%qT has no member named %qE", type, component);
|
| + error_at (loc, "%qT has no member named %qE", type, component);
|
| return error_mark_node;
|
| }
|
|
|
| @@ -1944,23 +2054,35 @@ build_component_ref (tree datum, tree component)
|
| 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))
|
| + SET_EXPR_LOCATION (ref, loc);
|
| + 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))
|
| - warn_deprecated_use (subdatum);
|
| + warn_deprecated_use (subdatum, NULL_TREE);
|
|
|
| datum = ref;
|
|
|
| @@ -1971,8 +2093,9 @@ build_component_ref (tree datum, tree component)
|
| return ref;
|
| }
|
| else if (code != ERROR_MARK)
|
| - error ("request for member %qE in something not a structure or union",
|
| - component);
|
| + error_at (loc,
|
| + "request for member %qE in something not a structure or union",
|
| + component);
|
|
|
| return error_mark_node;
|
| }
|
| @@ -1984,7 +2107,7 @@ build_component_ref (tree datum, tree component)
|
| LOC is the location to use for the generated tree. */
|
|
|
| tree
|
| -build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
|
| +build_indirect_ref (location_t loc, tree ptr, ref_operator errstring)
|
| {
|
| tree pointer = default_conversion (ptr);
|
| tree type = TREE_TYPE (pointer);
|
| @@ -2023,7 +2146,7 @@ build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
|
| error_at (loc, "dereferencing pointer to incomplete type");
|
| return error_mark_node;
|
| }
|
| - if (VOID_TYPE_P (t) && skip_evaluation == 0)
|
| + if (VOID_TYPE_P (t) && c_inhibit_evaluation_warnings == 0)
|
| warning_at (loc, 0, "dereferencing %<void *%> pointer");
|
|
|
| /* We *must* set TREE_READONLY when dereferencing a pointer to const,
|
| @@ -2042,8 +2165,26 @@ build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
|
| }
|
| }
|
| else if (TREE_CODE (pointer) != ERROR_MARK)
|
| - error_at (loc,
|
| - "invalid type argument of %qs (have %qT)", errorstring, type);
|
| + switch (errstring)
|
| + {
|
| + case RO_ARRAY_INDEXING:
|
| + error_at (loc,
|
| + "invalid type argument of array indexing (have %qT)",
|
| + type);
|
| + break;
|
| + case RO_UNARY_STAR:
|
| + error_at (loc,
|
| + "invalid type argument of unary %<*%> (have %qT)",
|
| + type);
|
| + break;
|
| + case RO_ARROW:
|
| + error_at (loc,
|
| + "invalid type argument of %<->%> (have %qT)",
|
| + type);
|
| + break;
|
| + default:
|
| + gcc_unreachable ();
|
| + }
|
| return error_mark_node;
|
| }
|
|
|
| @@ -2059,7 +2200,7 @@ build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
|
| LOC is the location to use for the returned expression. */
|
|
|
| tree
|
| -build_array_ref (tree array, tree index, location_t loc)
|
| +build_array_ref (location_t loc, tree array, tree index)
|
| {
|
| tree ret;
|
| bool swapped = false;
|
| @@ -2138,10 +2279,10 @@ build_array_ref (tree array, tree index, location_t loc)
|
| while (TREE_CODE (foo) == COMPONENT_REF)
|
| foo = TREE_OPERAND (foo, 0);
|
| if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
|
| - pedwarn (loc, OPT_pedantic,
|
| + pedwarn (loc, OPT_pedantic,
|
| "ISO C forbids subscripting %<register%> array");
|
| else if (!flag_isoc99 && !lvalue_p (foo))
|
| - pedwarn (loc, OPT_pedantic,
|
| + pedwarn (loc, OPT_pedantic,
|
| "ISO C90 forbids subscripting non-lvalue array");
|
| }
|
|
|
| @@ -2162,7 +2303,7 @@ build_array_ref (tree array, tree index, location_t loc)
|
| 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;
|
| }
|
| @@ -2178,15 +2319,18 @@ build_array_ref (tree array, tree index, location_t loc)
|
|
|
| return build_indirect_ref
|
| (loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0),
|
| - "array indexing");
|
| + RO_ARRAY_INDEXING);
|
| }
|
| }
|
|
|
| /* 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 (location_t loc, tree id, int fun, tree *type)
|
| {
|
| tree ref;
|
| tree decl = lookup_name (id);
|
| @@ -2195,18 +2339,22 @@ build_external_ref (tree id, int fun, location_t loc)
|
| 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);
|
| + ref = implicitly_declare (loc, id);
|
| else if (decl == error_mark_node)
|
| /* Don't complain about something that's already been
|
| complained about. */
|
| return error_mark_node;
|
| else
|
| {
|
| - undeclared_variable (id, loc);
|
| + undeclared_variable (loc, id);
|
| return error_mark_node;
|
| }
|
|
|
| @@ -2214,10 +2362,10 @@ build_external_ref (tree id, int fun, location_t loc)
|
| return error_mark_node;
|
|
|
| if (TREE_DEPRECATED (ref))
|
| - warn_deprecated_use (ref);
|
| + warn_deprecated_use (ref, NULL_TREE);
|
|
|
| /* Recursive call does not count as usage. */
|
| - if (ref != current_function_decl)
|
| + if (ref != current_function_decl)
|
| {
|
| TREE_USED (ref) = 1;
|
| }
|
| @@ -2235,6 +2383,17 @@ build_external_ref (tree id, int fun, location_t loc)
|
| if (TREE_CODE (ref) == CONST_DECL)
|
| {
|
| used_types_insert (TREE_TYPE (ref));
|
| +
|
| + if (warn_cxx_compat
|
| + && TREE_CODE (TREE_TYPE (ref)) == ENUMERAL_TYPE
|
| + && C_TYPE_DEFINED_IN_STRUCT (TREE_TYPE (ref)))
|
| + {
|
| + warning_at (loc, OPT_Wc___compat,
|
| + ("enum constant defined in struct or union "
|
| + "is not visible in C++"));
|
| + inform (DECL_SOURCE_LOCATION (ref), "enum constant defined here");
|
| + }
|
| +
|
| ref = DECL_INITIAL (ref);
|
| TREE_CONSTANT (ref) = 1;
|
| }
|
| @@ -2259,8 +2418,8 @@ build_external_ref (tree id, int fun, location_t loc)
|
| && (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;
|
| }
|
| @@ -2321,59 +2480,111 @@ pop_maybe_used (bool used)
|
| /* Return the result of sizeof applied to EXPR. */
|
|
|
| struct c_expr
|
| -c_expr_sizeof_expr (struct c_expr expr)
|
| +c_expr_sizeof_expr (location_t loc, struct c_expr expr)
|
| {
|
| struct c_expr ret;
|
| if (expr.value == error_mark_node)
|
| {
|
| 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 (loc, 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;
|
| + SET_EXPR_LOCATION (ret.value, loc);
|
| }
|
| - pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
|
| + pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)));
|
| }
|
| return ret;
|
| }
|
|
|
| /* Return the result of sizeof applied to T, a structure for the type
|
| - name passed to sizeof (rather than the type itself). */
|
| + name passed to sizeof (rather than the type itself). LOC is the
|
| + location of the original expression. */
|
|
|
| struct c_expr
|
| -c_expr_sizeof_type (struct c_type_name *t)
|
| +c_expr_sizeof_type (location_t loc, struct c_type_name *t)
|
| {
|
| tree type;
|
| struct c_expr ret;
|
| - type = groktypename (t);
|
| - ret.value = c_sizeof (type);
|
| + tree type_expr = NULL_TREE;
|
| + bool type_expr_const = true;
|
| + type = groktypename (t, &type_expr, &type_expr_const);
|
| + ret.value = c_sizeof (loc, type);
|
| ret.original_code = ERROR_MARK;
|
| + 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;
|
| + }
|
| pop_maybe_used (type != error_mark_node
|
| ? C_TYPE_VARIABLE_SIZE (type) : false);
|
| return ret;
|
| }
|
|
|
| /* Build a function call to function FUNCTION with parameters PARAMS.
|
| + The function call is at LOC.
|
| PARAMS is a list--a chain of TREE_LIST nodes--in which the
|
| TREE_VALUE of each node is a parameter-expression.
|
| FUNCTION's data type may be a function type or a pointer-to-function. */
|
|
|
| tree
|
| -build_function_call (tree function, tree params)
|
| +build_function_call (location_t loc, 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 (loc, 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 (location_t loc, tree function, VEC(tree,gc) *params,
|
| + VEC(tree,gc) *origtypes)
|
| {
|
| tree fntype, fundecl = 0;
|
| tree name = NULL_TREE, result;
|
| tree tem;
|
| int nargs;
|
| tree *argarray;
|
| -
|
| +
|
|
|
| /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
|
| STRIP_TYPE_NOPS (function);
|
| @@ -2385,7 +2596,7 @@ build_function_call (tree function, tree params)
|
| resolve_overloaded_builtin and targetm.resolve_overloaded_builtin
|
| handle all the type checking. The result is a complete expression
|
| that implements this function call. */
|
| - tem = resolve_overloaded_builtin (function, params);
|
| + tem = resolve_overloaded_builtin (loc, function, params);
|
| if (tem)
|
| return tem;
|
|
|
| @@ -2393,11 +2604,15 @@ build_function_call (tree function, tree params)
|
| fundecl = function;
|
| }
|
| if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
|
| - function = function_to_pointer_conversion (function);
|
| + function = function_to_pointer_conversion (loc, function);
|
|
|
| /* 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);
|
|
|
| fntype = TREE_TYPE (function);
|
|
|
| @@ -2407,7 +2622,7 @@ build_function_call (tree function, tree params)
|
| if (!(TREE_CODE (fntype) == POINTER_TYPE
|
| && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))
|
| {
|
| - error ("called object %qE is not a function", function);
|
| + error_at (loc, "called object %qE is not a function", function);
|
| return error_mark_node;
|
| }
|
|
|
| @@ -2420,10 +2635,8 @@ build_function_call (tree function, tree params)
|
| /* 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;
|
|
|
| @@ -2438,38 +2651,48 @@ build_function_call (tree function, tree params)
|
| && !comptypes (fntype, TREE_TYPE (tem)))
|
| {
|
| tree return_type = TREE_TYPE (fntype);
|
| - tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
|
| + tree trap = build_function_call (loc, 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
|
| executions of the program must execute the code. */
|
| - if (warning (0, "function called through a non-compatible type"))
|
| + if (warning_at (loc, 0, "function called through a non-compatible type"))
|
| /* 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");
|
| + inform (loc, "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);
|
| + 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 (loc, 0,
|
| + "function with qualified void return type called");
|
| + return trap;
|
| + }
|
| else
|
| {
|
| tree rhs;
|
|
|
| if (AGGREGATE_TYPE_P (return_type))
|
| - rhs = build_compound_literal (return_type,
|
| - build_constructor (return_type, 0));
|
| + rhs = build_compound_literal (loc, return_type,
|
| + build_constructor (return_type, 0),
|
| + false);
|
| else
|
| - rhs = fold_convert (return_type, integer_zero_node);
|
| + rhs = fold_convert_loc (loc, 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)
|
| @@ -2481,55 +2704,63 @@ build_function_call (tree function, tree params)
|
| 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_loc (loc, TREE_TYPE (fntype),
|
| + function, nargs, argarray);
|
| + else
|
| + result = fold_build_call_array_loc (loc, 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_loc (loc, TREE_TYPE (fntype),
|
| + function, nargs, argarray);
|
|
|
| if (VOID_TYPE_P (TREE_TYPE (result)))
|
| - return result;
|
| + {
|
| + if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED)
|
| + pedwarn (loc, 0,
|
| + "function with qualified void return type called");
|
| + return result;
|
| + }
|
| return require_complete_type (result);
|
| }
|
|
|
| -/* 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;
|
| bool error_args = false;
|
| 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
|
| @@ -2541,22 +2772,52 @@ convert_arguments (int nargs, tree *argarray,
|
| /* 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)
|
| {
|
| - error ("too many arguments to function %qE", function);
|
| + error_at (input_location,
|
| + "too many arguments to function %qE", function);
|
| + if (fundecl && !DECL_BUILT_IN (fundecl))
|
| + inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
|
| return parmnum;
|
| }
|
|
|
| @@ -2566,6 +2827,21 @@ convert_arguments (int nargs, tree *argarray,
|
| 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);
|
| @@ -2573,7 +2849,6 @@ convert_arguments (int nargs, tree *argarray,
|
| if (type != 0)
|
| {
|
| /* Formal parm type is specified by a function prototype. */
|
| - tree parmval;
|
|
|
| if (type == error_mark_node || !COMPLETE_TYPE_P (type))
|
| {
|
| @@ -2582,6 +2857,8 @@ convert_arguments (int nargs, tree *argarray,
|
| }
|
| else
|
| {
|
| + tree origtype;
|
| +
|
| /* Optionally warn about conversions that
|
| differ from the default conversions. */
|
| if (warn_traditional_conversion || warn_traditional)
|
| @@ -2589,32 +2866,32 @@ convert_arguments (int nargs, tree *argarray,
|
| 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);
|
| @@ -2622,7 +2899,7 @@ convert_arguments (int nargs, tree *argarray,
|
| 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'. */
|
| @@ -2636,45 +2913,46 @@ convert_arguments (int nargs, tree *argarray,
|
| 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. */
|
| ;
|
| else if (formal_prec != TYPE_PRECISION (type1))
|
| - warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
|
| + warning (OPT_Wtraditional_conversion,
|
| + "passing argument %d of %qE "
|
| "with different width due to prototype",
|
| argnum, rname);
|
| else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
|
| @@ -2693,20 +2971,30 @@ convert_arguments (int nargs, tree *argarray,
|
| 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 "
|
| + warning (OPT_Wtraditional_conversion,
|
| + "passing argument %d of %qE "
|
| "as unsigned due to prototype",
|
| argnum, rname);
|
| else
|
| - warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
|
| + warning (OPT_Wtraditional_conversion,
|
| + "passing argument %d of %qE "
|
| "as signed due to prototype", argnum, rname);
|
| }
|
| }
|
|
|
| - 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);
|
| + origtype = (origtypes == NULL
|
| + ? NULL_TREE
|
| + : VEC_index (tree, origtypes, parmnum));
|
| + parmval = convert_for_assignment (input_location, type, val,
|
| + origtype, ic_argpass, npc,
|
| fundecl, function,
|
| parmnum + 1);
|
|
|
| @@ -2715,19 +3003,22 @@ convert_arguments (int nargs, tree *argarray,
|
| && (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)))
|
| {
|
| @@ -2736,24 +3027,28 @@ convert_arguments (int nargs, tree *argarray,
|
| }
|
| else
|
| /* Convert `short' and `char' to full-size `int'. */
|
| - argarray[parmnum] = default_conversion (val);
|
| + parmval = default_conversion (val);
|
|
|
| - if (argarray[parmnum] == error_mark_node)
|
| + VEC_replace (tree, values, parmnum, parmval);
|
| + if (parmval == error_mark_node)
|
| error_args = true;
|
|
|
| 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)
|
| {
|
| - error ("too few arguments to function %qE", function);
|
| + error_at (input_location,
|
| + "too few arguments to function %qE", function);
|
| + if (fundecl && !DECL_BUILT_IN (fundecl))
|
| + inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
|
| return -1;
|
| }
|
|
|
| - return error_args ? -1 : parmnum;
|
| + return error_args ? -1 : (int) parmnum;
|
| }
|
|
|
| /* This is the entry point used by the parser to build unary operators
|
| @@ -2765,15 +3060,16 @@ convert_arguments (int nargs, tree *argarray,
|
| */
|
|
|
| struct c_expr
|
| -parser_build_unary_op (enum tree_code code, struct c_expr arg, location_t loc)
|
| +parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg)
|
| {
|
| struct c_expr result;
|
|
|
| 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);
|
| + overflow_warning (loc, result.value);
|
|
|
| return result;
|
| }
|
| @@ -2794,10 +3090,17 @@ parser_build_binary_op (location_t location, enum tree_code code,
|
|
|
| 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;
|
| @@ -2810,8 +3113,9 @@ parser_build_binary_op (location_t location, enum tree_code code,
|
| 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, TREE_TYPE (result.value),
|
| + 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. */
|
| @@ -2819,16 +3123,28 @@ parser_build_binary_op (location_t location, enum tree_code code,
|
| {
|
| if ((code1 == STRING_CST && !integer_zerop (arg2.value))
|
| || (code2 == STRING_CST && !integer_zerop (arg1.value)))
|
| - warning (OPT_Waddress, "comparison with string literal results in unspecified behavior");
|
| + warning_at (location, OPT_Waddress,
|
| + "comparison with string literal results in unspecified behavior");
|
| }
|
| else if (TREE_CODE_CLASS (code) == tcc_comparison
|
| && (code1 == STRING_CST || code2 == STRING_CST))
|
| - warning (OPT_Waddress, "comparison with string literal results in unspecified behavior");
|
| + warning_at (location, OPT_Waddress,
|
| + "comparison with string literal results in unspecified behavior");
|
|
|
| - if (TREE_OVERFLOW_P (result.value)
|
| - && !TREE_OVERFLOW_P (arg1.value)
|
| + if (TREE_OVERFLOW_P (result.value)
|
| + && !TREE_OVERFLOW_P (arg1.value)
|
| && !TREE_OVERFLOW_P (arg2.value))
|
| - overflow_warning (result.value);
|
| + overflow_warning (location, 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;
|
| }
|
| @@ -2837,19 +3153,51 @@ parser_build_binary_op (location_t location, enum tree_code code,
|
| The resulting tree has type int. */
|
|
|
| static tree
|
| -pointer_diff (tree op0, tree op1)
|
| +pointer_diff (location_t loc, tree op0, tree op1)
|
| {
|
| tree restype = ptrdiff_type_node;
|
| + tree result, inttype;
|
|
|
| + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
|
| + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
|
| tree target_type = TREE_TYPE (TREE_TYPE (op0));
|
| tree con0, con1, lit0, lit1;
|
| tree orig_op1 = op1;
|
|
|
| + /* If the operands point into different address spaces, we need to
|
| + explicitly convert them to pointers into the common address space
|
| + before we can subtract the numerical address values. */
|
| + if (as0 != as1)
|
| + {
|
| + addr_space_t as_common;
|
| + tree common_type;
|
| +
|
| + /* Determine the common superset address space. This is guaranteed
|
| + to exist because the caller verified that comp_target_types
|
| + returned non-zero. */
|
| + if (!addr_space_superset (as0, as1, &as_common))
|
| + gcc_unreachable ();
|
| +
|
| + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1));
|
| + op0 = convert (common_type, op0);
|
| + op1 = convert (common_type, op1);
|
| + }
|
| +
|
| + /* Determine integer type to perform computations in. This will usually
|
| + be the same as the result type (ptrdiff_t), but may need to be a wider
|
| + type if pointers for the address space are wider than ptrdiff_t. */
|
| + if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
|
| + inttype = lang_hooks.types.type_for_size
|
| + (TYPE_PRECISION (TREE_TYPE (op0)), 0);
|
| + else
|
| + inttype = restype;
|
| +
|
| +
|
| if (TREE_CODE (target_type) == VOID_TYPE)
|
| - pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| "pointer of type %<void *%> used in subtraction");
|
| if (TREE_CODE (target_type) == FUNCTION_TYPE)
|
| - pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| + pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| "pointer to a function used in subtraction");
|
|
|
| /* If the conversion to ptrdiff_type does anything like widening or
|
| @@ -2901,18 +3249,22 @@ pointer_diff (tree op0, tree op1)
|
| Do not do default conversions on the minus operator
|
| in case restype is a short type. */
|
|
|
| - op0 = build_binary_op (input_location,
|
| - MINUS_EXPR, convert (restype, op0),
|
| - convert (restype, op1), 0);
|
| + op0 = build_binary_op (loc,
|
| + MINUS_EXPR, convert (inttype, op0),
|
| + convert (inttype, op1), 0);
|
| /* This generates an error if op1 is pointer to incomplete type. */
|
| if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
|
| - error ("arithmetic on pointer to an incomplete type");
|
| + error_at (loc, "arithmetic on pointer to an incomplete type");
|
|
|
| /* This generates an error if op0 is pointer to incomplete type. */
|
| op1 = c_size_in_bytes (target_type);
|
|
|
| /* Divide by the size, in easiest possible way. */
|
| - return fold_build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
|
| + result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype,
|
| + op0, convert (inttype, op1));
|
| +
|
| + /* Convert to final result type if necessary. */
|
| + return convert (restype, result);
|
| }
|
|
|
| /* Construct and perhaps optimize a tree representation
|
| @@ -2936,8 +3288,14 @@ build_unary_op (location_t location,
|
| 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);
|
| @@ -2955,6 +3313,12 @@ build_unary_op (location_t location,
|
| 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:
|
| @@ -2970,7 +3334,7 @@ build_unary_op (location_t location,
|
| }
|
| else if (!noconvert)
|
| arg = default_conversion (arg);
|
| - arg = non_lvalue (arg);
|
| + arg = non_lvalue_loc (location, arg);
|
| break;
|
|
|
| case NEGATE_EXPR:
|
| @@ -2997,7 +3361,7 @@ build_unary_op (location_t location,
|
| else if (typecode == COMPLEX_TYPE)
|
| {
|
| code = CONJ_EXPR;
|
| - pedwarn (location, OPT_pedantic,
|
| + pedwarn (location, OPT_pedantic,
|
| "ISO C does not support %<~%> for complex conjugation");
|
| if (!noconvert)
|
| arg = default_conversion (arg);
|
| @@ -3041,25 +3405,35 @@ build_unary_op (location_t location,
|
| return error_mark_node;
|
| }
|
| arg = c_objc_common_truthvalue_conversion (location, arg);
|
| - ret = invert_truthvalue (arg);
|
| + ret = invert_truthvalue_loc (location, 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:
|
| if (TREE_CODE (arg) == COMPLEX_CST)
|
| ret = TREE_REALPART (arg);
|
| else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
|
| - ret = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
|
| + ret = fold_build1_loc (location,
|
| + 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:
|
| if (TREE_CODE (arg) == COMPLEX_CST)
|
| ret = TREE_IMAGPART (arg);
|
| else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
|
| - ret = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
|
| + ret = fold_build1_loc (location,
|
| + IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
|
| else
|
| - ret = omit_one_operand (TREE_TYPE (arg), integer_zero_node, arg);
|
| + ret = omit_one_operand_loc (location, 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:
|
| @@ -3067,13 +3441,46 @@ build_unary_op (location_t location,
|
| 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;
|
| +
|
| + if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE)
|
| + {
|
| + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
|
| + warning_at (location, OPT_Wc___compat,
|
| + "increment of enumeration value is invalid in C++");
|
| + else
|
| + warning_at (location, OPT_Wc___compat,
|
| + "decrement of enumeration value is invalid in C++");
|
| + }
|
| +
|
| + /* 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 (location, OPT_pedantic,
|
| + pedwarn (location, OPT_pedantic,
|
| "ISO C does not support %<++%> and %<--%> on complex types");
|
|
|
| arg = stabilize_reference (arg);
|
| @@ -3124,15 +3531,15 @@ build_unary_op (location_t location,
|
| || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE)
|
| {
|
| if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
|
| - pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| + pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
|
| "wrong type argument to increment");
|
| else
|
| - pedwarn (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 (argtype));
|
| - inc = fold_convert (sizetype, inc);
|
| + inc = fold_convert_loc (location, sizetype, inc);
|
| }
|
| else if (FRACT_MODE_P (TYPE_MODE (argtype)))
|
| {
|
| @@ -3159,15 +3566,8 @@ build_unary_op (location_t location,
|
| 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))
|
| + if (TYPE_READONLY (argtype))
|
| {
|
| readonly_error (arg,
|
| ((code == PREINCREMENT_EXPR
|
| @@ -3175,6 +3575,11 @@ build_unary_op (location_t location,
|
| ? 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);
|
| @@ -3190,12 +3595,21 @@ build_unary_op (location_t location,
|
| 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)
|
| {
|
| /* Don't let this be an lvalue. */
|
| if (lvalue_p (TREE_OPERAND (arg, 0)))
|
| - return non_lvalue (TREE_OPERAND (arg, 0));
|
| + return non_lvalue_loc (location, TREE_OPERAND (arg, 0));
|
| ret = TREE_OPERAND (arg, 0);
|
| goto return_build_unary_op;
|
| }
|
| @@ -3208,7 +3622,8 @@ build_unary_op (location_t location,
|
| return error_mark_node;
|
| return build_binary_op (location, PLUS_EXPR,
|
| (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
|
| - ? array_to_pointer_conversion (op0)
|
| + ? array_to_pointer_conversion (location,
|
| + op0)
|
| : op0),
|
| TREE_OPERAND (arg, 1), 1);
|
| }
|
| @@ -3219,6 +3634,20 @@ build_unary_op (location_t location,
|
| && !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);
|
|
|
| @@ -3246,10 +3675,11 @@ build_unary_op (location_t location,
|
| if (val && TREE_CODE (val) == INDIRECT_REF
|
| && TREE_CONSTANT (TREE_OPERAND (val, 0)))
|
| {
|
| - tree op0 = fold_convert (sizetype, fold_offsetof (arg, val)), op1;
|
| + tree op0 = fold_convert_loc (location, sizetype,
|
| + fold_offsetof (arg, val)), op1;
|
|
|
| - op1 = fold_convert (argtype, TREE_OPERAND (val, 0));
|
| - ret = fold_build2 (POINTER_PLUS_EXPR, argtype, op1, op0);
|
| + op1 = fold_convert_loc (location, argtype, TREE_OPERAND (val, 0));
|
| + ret = fold_build2_loc (location, POINTER_PLUS_EXPR, argtype, op1, op0);
|
| goto return_build_unary_op;
|
| }
|
|
|
| @@ -3264,10 +3694,21 @@ build_unary_op (location_t location,
|
|
|
| if (argtype == 0)
|
| argtype = TREE_TYPE (arg);
|
| - ret = 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_loc (location, code, argtype, arg)
|
| + : fold_build1_loc (location, 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;
|
| }
|
| @@ -3276,7 +3717,7 @@ build_unary_op (location_t location,
|
| 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);
|
| @@ -3288,6 +3729,9 @@ lvalue_p (const_tree ref)
|
| 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;
|
| @@ -3347,6 +3791,29 @@ readonly_error (tree arg, enum lvalue_use use)
|
| 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
|
| @@ -3430,19 +3897,67 @@ c_mark_addressable (tree exp)
|
| }
|
| }
|
|
|
| -/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
|
| +/* Convert EXPR to TYPE, warning about conversion problems with
|
| + constants. SEMANTIC_TYPE is the type this conversion would use
|
| + without excess precision. If SEMANTIC_TYPE is NULL, this function
|
| + is equivalent to convert_and_check. This function is a wrapper that
|
| + handles conversions that may be different than
|
| + the usual ones because of excess precision. */
|
| +
|
| +static tree
|
| +ep_convert_and_check (tree type, tree expr, tree semantic_type)
|
| +{
|
| + if (TREE_TYPE (expr) == type)
|
| + return expr;
|
| +
|
| + if (!semantic_type)
|
| + return convert_and_check (type, expr);
|
| +
|
| + if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
|
| + && TREE_TYPE (expr) != semantic_type)
|
| + {
|
| + /* For integers, we need to check the real conversion, not
|
| + the conversion to the excess precision type. */
|
| + expr = convert_and_check (semantic_type, expr);
|
| + }
|
| + /* Result type is the excess precision type, which should be
|
| + large enough, so do not check. */
|
| + return convert (type, expr);
|
| +}
|
| +
|
| +/* 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. Set the location of the expression to LOC. */
|
|
|
| tree
|
| -build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| +build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
|
| + tree op1, tree op1_original_type, tree op2,
|
| + tree op2_original_type)
|
| {
|
| tree type1;
|
| tree type2;
|
| enum tree_code code1;
|
| enum tree_code code2;
|
| tree result_type = NULL;
|
| + tree semantic_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)
|
| @@ -3464,12 +3979,48 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| In C99 they will be pointers by now. */
|
| if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE)
|
| {
|
| - error ("non-lvalue array in conditional expression");
|
| + error_at (colon_loc, "non-lvalue array in conditional expression");
|
| 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))
|
| + {
|
| + semantic_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);
|
| + }
|
| + }
|
| +
|
| + if (warn_cxx_compat)
|
| + {
|
| + tree t1 = op1_original_type ? op1_original_type : TREE_TYPE (orig_op1);
|
| + tree t2 = op2_original_type ? op2_original_type : TREE_TYPE (orig_op2);
|
| +
|
| + if (TREE_CODE (t1) == ENUMERAL_TYPE
|
| + && TREE_CODE (t2) == ENUMERAL_TYPE
|
| + && TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2))
|
| + warning_at (colon_loc, OPT_Wc___compat,
|
| + ("different enum types in conditional is "
|
| + "invalid in C++: %qT vs %qT"),
|
| + t1, t2);
|
| + }
|
| +
|
| /* Quickly detect the usual case where op1 and op2 have the same type
|
| after promotion. */
|
| if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
|
| @@ -3491,7 +4042,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| 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 (c_inhibit_evaluation_warnings == 0)
|
| {
|
| int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1));
|
| int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2));
|
| @@ -3505,38 +4056,82 @@ build_conditional_expr (tree ifexp, tree op1, tree 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. */
|
| + c_inhibit_evaluation_warnings
|
| + += (ifexp == truthvalue_false_node);
|
| + op1 = c_fully_fold (op1, require_constant_value,
|
| + &op1_maybe_const);
|
| + c_inhibit_evaluation_warnings
|
| + -= (ifexp == truthvalue_false_node);
|
| +
|
| + c_inhibit_evaluation_warnings
|
| + += (ifexp == truthvalue_true_node);
|
| + op2 = c_fully_fold (op2, require_constant_value,
|
| + &op2_maybe_const);
|
| + c_inhibit_evaluation_warnings
|
| + -= (ifexp == truthvalue_true_node);
|
| +
|
| + 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_at (colon_loc, OPT_Wsign_compare,
|
| + ("signed and unsigned type in "
|
| + "conditional expression"));
|
| + }
|
| + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
|
| + op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
|
| + if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
|
| + op2 = c_wrap_maybe_const (op2, !op2_maybe_const);
|
| + }
|
| }
|
| }
|
| }
|
| else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
|
| {
|
| if (code1 != VOID_TYPE || code2 != VOID_TYPE)
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (colon_loc, OPT_pedantic,
|
| "ISO C forbids conditional expr with only one void side");
|
| result_type = void_type_node;
|
| }
|
| else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
|
| {
|
| - if (comp_target_types (type1, type2))
|
| + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
|
| + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2));
|
| + addr_space_t as_common;
|
| +
|
| + if (comp_target_types (colon_loc, type1, type2))
|
| result_type = common_pointer_type (type1, type2);
|
| else if (null_pointer_constant_p (orig_op1))
|
| - result_type = qualify_type (type2, type1);
|
| + result_type = type2;
|
| else if (null_pointer_constant_p (orig_op2))
|
| - result_type = qualify_type (type1, type2);
|
| + result_type = type1;
|
| + else if (!addr_space_superset (as1, as2, &as_common))
|
| + {
|
| + error_at (colon_loc, "pointers to disjoint address spaces "
|
| + "used in conditional expression");
|
| + return error_mark_node;
|
| + }
|
| else if (VOID_TYPE_P (TREE_TYPE (type1)))
|
| {
|
| if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (colon_loc, OPT_pedantic,
|
| "ISO C forbids conditional expr between "
|
| "%<void *%> and function pointer");
|
| result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
|
| @@ -3545,7 +4140,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| else if (VOID_TYPE_P (TREE_TYPE (type2)))
|
| {
|
| if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (colon_loc, OPT_pedantic,
|
| "ISO C forbids conditional expr between "
|
| "%<void *%> and function pointer");
|
| result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
|
| @@ -3553,16 +4148,19 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| }
|
| else
|
| {
|
| + int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
|
| +
|
| if (!objc_ok)
|
| - pedwarn (input_location, 0,
|
| + pedwarn (colon_loc, 0,
|
| "pointer type mismatch in conditional expression");
|
| - result_type = build_pointer_type (void_type_node);
|
| + result_type = build_pointer_type
|
| + (build_qualified_type (void_type_node, qual));
|
| }
|
| }
|
| else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
|
| {
|
| if (!null_pointer_constant_p (orig_op2))
|
| - pedwarn (input_location, 0,
|
| + pedwarn (colon_loc, 0,
|
| "pointer/integer type mismatch in conditional expression");
|
| else
|
| {
|
| @@ -3573,7 +4171,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
| {
|
| if (!null_pointer_constant_p (orig_op1))
|
| - pedwarn (input_location, 0,
|
| + pedwarn (colon_loc, 0,
|
| "pointer/integer type mismatch in conditional expression");
|
| else
|
| {
|
| @@ -3588,7 +4186,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| result_type = void_type_node;
|
| else
|
| {
|
| - error ("type mismatch in conditional expression");
|
| + error_at (colon_loc, "type mismatch in conditional expression");
|
| return error_mark_node;
|
| }
|
| }
|
| @@ -3596,23 +4194,76 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
| /* Merge const and volatile flags of the incoming types. */
|
| result_type
|
| = build_type_variant (result_type,
|
| - TREE_READONLY (op1) || TREE_READONLY (op2),
|
| - TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
|
| + TYPE_READONLY (type1) || TYPE_READONLY (type2),
|
| + TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2));
|
| +
|
| + op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
|
| + op2 = ep_convert_and_check (result_type, op2, semantic_result_type);
|
|
|
| - if (result_type != TREE_TYPE (op1))
|
| - op1 = convert_and_check (result_type, op1);
|
| - if (result_type != TREE_TYPE (op2))
|
| - op2 = convert_and_check (result_type, 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_loc (colon_loc, 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 (semantic_result_type)
|
| + ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
|
|
|
| - return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
|
| + protected_set_expr_location (ret, colon_loc);
|
| + return ret;
|
| }
|
|
|
| /* Return a compound expression that performs two expressions and
|
| - returns the value of the second of them. */
|
| + returns the value of the second of them.
|
| +
|
| + LOC is the location of the COMPOUND_EXPR. */
|
|
|
| tree
|
| -build_compound_expr (tree expr1, tree expr2)
|
| +build_compound_expr (location_t loc, 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
|
| @@ -3628,8 +4279,8 @@ build_compound_expr (tree expr1, tree expr2)
|
| && CONVERT_EXPR_P (TREE_OPERAND (expr1, 1)))
|
| ; /* (void) a, (void) b, c */
|
| else
|
| - warning (OPT_Wunused_value,
|
| - "left-hand operand of comma expression has no effect");
|
| + warning_at (loc, OPT_Wunused_value,
|
| + "left-hand operand of comma expression has no effect");
|
| }
|
| }
|
|
|
| @@ -3638,20 +4289,127 @@ build_compound_expr (tree expr1, tree expr2)
|
| `foo() + bar(), baz()' the result of the `+' operator is not used,
|
| so we should issue a warning. */
|
| else if (warn_unused_value)
|
| - warn_if_unused_value (expr1, input_location);
|
| + warn_if_unused_value (expr1, loc);
|
|
|
| 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);
|
| +
|
| + protected_set_expr_location (ret, loc);
|
| + return ret;
|
| }
|
|
|
| -/* Build an expression representing a cast to type TYPE of expression EXPR. */
|
| +/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to
|
| + which we are casting. OTYPE is the type of the expression being
|
| + cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared
|
| + on the command line. Named address space qualifiers are not handled
|
| + here, because they result in different warnings. */
|
| +
|
| +static void
|
| +handle_warn_cast_qual (tree type, tree otype)
|
| +{
|
| + tree in_type = type;
|
| + tree in_otype = otype;
|
| + int added = 0;
|
| + int discarded = 0;
|
| + bool is_const;
|
| +
|
| + /* Check that the qualifiers on IN_TYPE are a superset of the
|
| + qualifiers of IN_OTYPE. The outermost level of POINTER_TYPE
|
| + nodes is uninteresting and we stop as soon as we hit a
|
| + non-POINTER_TYPE node on either type. */
|
| + do
|
| + {
|
| + in_otype = TREE_TYPE (in_otype);
|
| + in_type = TREE_TYPE (in_type);
|
| +
|
| + /* GNU C allows cv-qualified function types. 'const' means the
|
| + function is very pure, 'volatile' means it can't return. We
|
| + need to warn when such qualifiers are added, not when they're
|
| + taken away. */
|
| + if (TREE_CODE (in_otype) == FUNCTION_TYPE
|
| + && TREE_CODE (in_type) == FUNCTION_TYPE)
|
| + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
|
| + else
|
| + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));
|
| + }
|
| + while (TREE_CODE (in_type) == POINTER_TYPE
|
| + && TREE_CODE (in_otype) == POINTER_TYPE);
|
| +
|
| + if (added)
|
| + warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
|
| +
|
| + if (discarded)
|
| + /* There are qualifiers present in IN_OTYPE that are not present
|
| + in IN_TYPE. */
|
| + warning (OPT_Wcast_qual,
|
| + "cast discards qualifiers from pointer target type");
|
| +
|
| + if (added || discarded)
|
| + return;
|
| +
|
| + /* A cast from **T to const **T is unsafe, because it can cause a
|
| + const value to be changed with no additional warning. We only
|
| + issue this warning if T is the same on both sides, and we only
|
| + issue the warning if there are the same number of pointers on
|
| + both sides, as otherwise the cast is clearly unsafe anyhow. A
|
| + cast is unsafe when a qualifier is added at one level and const
|
| + is not present at all outer levels.
|
| +
|
| + To issue this warning, we check at each level whether the cast
|
| + adds new qualifiers not already seen. We don't need to special
|
| + case function types, as they won't have the same
|
| + TYPE_MAIN_VARIANT. */
|
| +
|
| + if (TYPE_MAIN_VARIANT (in_type) != TYPE_MAIN_VARIANT (in_otype))
|
| + return;
|
| + if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE)
|
| + return;
|
| +
|
| + in_type = type;
|
| + in_otype = otype;
|
| + is_const = TYPE_READONLY (TREE_TYPE (in_type));
|
| + do
|
| + {
|
| + in_type = TREE_TYPE (in_type);
|
| + in_otype = TREE_TYPE (in_otype);
|
| + if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
|
| + && !is_const)
|
| + {
|
| + warning (OPT_Wcast_qual,
|
| + ("new qualifiers in middle of multi-level non-const cast "
|
| + "are unsafe"));
|
| + break;
|
| + }
|
| + if (is_const)
|
| + is_const = TYPE_READONLY (in_type);
|
| + }
|
| + while (TREE_CODE (in_type) == POINTER_TYPE);
|
| +}
|
| +
|
| +/* Build an expression representing a cast to type TYPE of expression EXPR.
|
| + LOC is the location of the cast-- typically the open paren of the cast. */
|
|
|
| tree
|
| -build_c_cast (tree type, tree expr)
|
| +build_c_cast (location_t loc, 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;
|
| @@ -3666,13 +4424,13 @@ build_c_cast (tree type, tree expr)
|
|
|
| if (TREE_CODE (type) == ARRAY_TYPE)
|
| {
|
| - error ("cast specifies array type");
|
| + error_at (loc, "cast specifies array type");
|
| return error_mark_node;
|
| }
|
|
|
| if (TREE_CODE (type) == FUNCTION_TYPE)
|
| {
|
| - error ("cast specifies function type");
|
| + error_at (loc, "cast specifies function type");
|
| return error_mark_node;
|
| }
|
|
|
| @@ -3687,7 +4445,7 @@ build_c_cast (tree type, tree expr)
|
| {
|
| if (TREE_CODE (type) == RECORD_TYPE
|
| || TREE_CODE (type) == UNION_TYPE)
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (loc, OPT_pedantic,
|
| "ISO C forbids casting nonscalar to the same type");
|
| }
|
| else if (TREE_CODE (type) == UNION_TYPE)
|
| @@ -3703,16 +4461,19 @@ build_c_cast (tree type, tree expr)
|
| if (field)
|
| {
|
| tree t;
|
| -
|
| - pedwarn (input_location, OPT_pedantic,
|
| - "ISO C forbids casts to union type");
|
| - t = digest_init (type,
|
| - build_constructor_single (type, field, value),
|
| - true, 0);
|
| + bool maybe_const = true;
|
| +
|
| + pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type");
|
| + t = c_fully_fold (value, false, &maybe_const);
|
| + t = build_constructor_single (type, field, t);
|
| + if (!maybe_const)
|
| + t = c_wrap_maybe_const (t, true);
|
| + t = digest_init (loc, type, t,
|
| + NULL_TREE, false, true, 0);
|
| TREE_CONSTANT (t) = TREE_CONSTANT (value);
|
| return t;
|
| }
|
| - error ("cast to union type from type not present in union");
|
| + error_at (loc, "cast to union type from type not present in union");
|
| return error_mark_node;
|
| }
|
| else
|
| @@ -3720,50 +4481,48 @@ build_c_cast (tree type, tree expr)
|
| tree otype, ovalue;
|
|
|
| if (type == void_type_node)
|
| - return build1 (CONVERT_EXPR, type, value);
|
| + {
|
| + tree t = build1 (CONVERT_EXPR, type, value);
|
| + SET_EXPR_LOCATION (t, loc);
|
| + return t;
|
| + }
|
|
|
| otype = TREE_TYPE (value);
|
|
|
| /* Optionally warn about potentially worrisome casts. */
|
| -
|
| if (warn_cast_qual
|
| && TREE_CODE (type) == POINTER_TYPE
|
| && TREE_CODE (otype) == POINTER_TYPE)
|
| + handle_warn_cast_qual (type, otype);
|
| +
|
| + /* Warn about conversions between pointers to disjoint
|
| + address spaces. */
|
| + if (TREE_CODE (type) == POINTER_TYPE
|
| + && TREE_CODE (otype) == POINTER_TYPE
|
| + && !null_pointer_constant_p (value))
|
| {
|
| - tree in_type = type;
|
| - tree in_otype = otype;
|
| - int added = 0;
|
| - int discarded = 0;
|
| + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
|
| + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype));
|
| + addr_space_t as_common;
|
|
|
| - /* Check that the qualifiers on IN_TYPE are a superset of
|
| - the qualifiers of IN_OTYPE. The outermost level of
|
| - POINTER_TYPE nodes is uninteresting and we stop as soon
|
| - as we hit a non-POINTER_TYPE node on either type. */
|
| - do
|
| + if (!addr_space_superset (as_to, as_from, &as_common))
|
| {
|
| - in_otype = TREE_TYPE (in_otype);
|
| - in_type = TREE_TYPE (in_type);
|
| -
|
| - /* GNU C allows cv-qualified function types. 'const'
|
| - means the function is very pure, 'volatile' means it
|
| - can't return. We need to warn when such qualifiers
|
| - are added, not when they're taken away. */
|
| - if (TREE_CODE (in_otype) == FUNCTION_TYPE
|
| - && TREE_CODE (in_type) == FUNCTION_TYPE)
|
| - added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
|
| - else
|
| - discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
|
| - }
|
| - while (TREE_CODE (in_type) == POINTER_TYPE
|
| - && TREE_CODE (in_otype) == POINTER_TYPE);
|
| + if (ADDR_SPACE_GENERIC_P (as_from))
|
| + warning_at (loc, 0, "cast to %s address space pointer "
|
| + "from disjoint generic address space pointer",
|
| + c_addr_space_name (as_to));
|
|
|
| - if (added)
|
| - warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
|
| + else if (ADDR_SPACE_GENERIC_P (as_to))
|
| + warning_at (loc, 0, "cast to generic address space pointer "
|
| + "from disjoint %s address space pointer",
|
| + c_addr_space_name (as_from));
|
|
|
| - if (discarded)
|
| - /* There are qualifiers present in IN_OTYPE that are not
|
| - present in IN_TYPE. */
|
| - warning (OPT_Wcast_qual, "cast discards qualifiers from pointer target type");
|
| + else
|
| + warning_at (loc, 0, "cast to %s address space pointer "
|
| + "from disjoint %s address space pointer",
|
| + c_addr_space_name (as_to),
|
| + c_addr_space_name (as_from));
|
| + }
|
| }
|
|
|
| /* Warn about possible alignment problems. */
|
| @@ -3778,8 +4537,8 @@ build_c_cast (tree type, tree expr)
|
| || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
|
| && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
|
| && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
|
| - warning (OPT_Wcast_align,
|
| - "cast increases required alignment of target type");
|
| + warning_at (loc, OPT_Wcast_align,
|
| + "cast increases required alignment of target type");
|
|
|
| if (TREE_CODE (type) == INTEGER_TYPE
|
| && TREE_CODE (otype) == POINTER_TYPE
|
| @@ -3789,21 +4548,23 @@ build_c_cast (tree type, tree expr)
|
| of cases such as SIG_*, warn about converting constant
|
| pointers to integers. In some cases it may cause unwanted
|
| sign extension, and a warning is appropriate. */
|
| - warning (OPT_Wpointer_to_int_cast,
|
| - "cast from pointer to integer of different size");
|
| + warning_at (loc, OPT_Wpointer_to_int_cast,
|
| + "cast from pointer to integer of different size");
|
|
|
| if (TREE_CODE (value) == CALL_EXPR
|
| && TREE_CODE (type) != TREE_CODE (otype))
|
| - warning (OPT_Wbad_function_cast, "cast from function call of type %qT "
|
| - "to non-matching type %qT", otype, type);
|
| + warning_at (loc, OPT_Wbad_function_cast,
|
| + "cast from function call of type %qT "
|
| + "to non-matching type %qT", otype, type);
|
|
|
| if (TREE_CODE (type) == POINTER_TYPE
|
| && TREE_CODE (otype) == INTEGER_TYPE
|
| && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
|
| /* Don't warn about converting any constant. */
|
| && !TREE_CONSTANT (value))
|
| - warning (OPT_Wint_to_pointer_cast, "cast to pointer from integer "
|
| - "of different size");
|
| + warning_at (loc,
|
| + OPT_Wint_to_pointer_cast, "cast to pointer from integer "
|
| + "of different size");
|
|
|
| if (warn_strict_aliasing <= 2)
|
| strict_aliasing_warning (otype, type, expr);
|
| @@ -3816,7 +4577,7 @@ build_c_cast (tree type, tree expr)
|
| && TREE_CODE (otype) == POINTER_TYPE
|
| && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE
|
| && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
|
| - pedwarn (input_location, OPT_pedantic, "ISO C forbids "
|
| + pedwarn (loc, OPT_pedantic, "ISO C forbids "
|
| "conversion of function pointer to object pointer type");
|
|
|
| if (pedantic
|
| @@ -3825,14 +4586,14 @@ build_c_cast (tree type, tree expr)
|
| && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|
| && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
|
| && !null_pointer_constant_p (value))
|
| - pedwarn (input_location, OPT_pedantic, "ISO C forbids "
|
| + pedwarn (loc, OPT_pedantic, "ISO C forbids "
|
| "conversion of object pointer to function pointer type");
|
|
|
| ovalue = value;
|
| 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))
|
| {
|
| @@ -3853,43 +4614,88 @@ build_c_cast (tree type, tree expr)
|
|
|
| /* Don't let a cast be an lvalue. */
|
| if (value == expr)
|
| - value = non_lvalue (value);
|
| -
|
| + value = non_lvalue_loc (loc, 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);
|
| +
|
| + if (CAN_HAVE_LOCATION_P (value))
|
| + SET_EXPR_LOCATION (value, loc);
|
| return value;
|
| }
|
|
|
| -/* Interpret a cast of expression EXPR to type TYPE. */
|
| +/* Interpret a cast of expression EXPR to type TYPE. LOC is the
|
| + location of the open paren of the cast, or the position of the cast
|
| + expr. */
|
| tree
|
| -c_cast_expr (struct c_type_name *type_name, tree expr)
|
| +c_cast_expr (location_t loc, 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 (loc, 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;
|
| + SET_EXPR_LOCATION (ret, loc);
|
| + }
|
| +
|
| + if (CAN_HAVE_LOCATION_P (ret) && !EXPR_HAS_LOCATION (ret))
|
| + SET_EXPR_LOCATION (ret, loc);
|
| +
|
| + /* C++ does not permits types to be defined in a cast. */
|
| + if (warn_cxx_compat && type_name->specs->tag_defined_p)
|
| + warning_at (loc, OPT_Wc___compat,
|
| + "defining a type in a cast is invalid in C++");
|
| +
|
| + return ret;
|
| }
|
|
|
| /* 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. */
|
| + LOCATION is the location of the MODIFYCODE operator.
|
| + RHS_LOC is the location of the RHS. */
|
|
|
| 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,
|
| + location_t rhs_loc, 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;
|
|
|
| /* Types that aren't fully specified cannot be used in assignments. */
|
| lhs = require_complete_type (lhs);
|
| @@ -3901,23 +4707,47 @@ build_modify_expr (location_t location,
|
| 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),
|
| + lhs_origtype, modifycode, rhs_loc, rhs,
|
| + rhs_origtype);
|
| + 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 (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)))
|
| @@ -3925,6 +4755,8 @@ build_modify_expr (location_t location,
|
| 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'.
|
| @@ -3947,10 +4779,33 @@ build_modify_expr (location_t location,
|
| TREE_TYPE (lhs) = lhstype;
|
| }
|
|
|
| - /* Convert new value to destination type. */
|
| -
|
| - newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
|
| - NULL_TREE, NULL_TREE, 0);
|
| + /* 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);
|
| + if (rhs_semantic_type)
|
| + newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
|
| + newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype,
|
| + ic_assign, npc, NULL_TREE, NULL_TREE, 0);
|
| if (TREE_CODE (newrhs) == ERROR_MARK)
|
| return error_mark_node;
|
|
|
| @@ -3979,28 +4834,35 @@ build_modify_expr (location_t location,
|
| if (olhstype == TREE_TYPE (result))
|
| return result;
|
|
|
| - result = convert_for_assignment (olhstype, result, ic_assign,
|
| - NULL_TREE, NULL_TREE, 0);
|
| + result = convert_for_assignment (location, olhstype, result, rhs_origtype,
|
| + ic_assign, false, NULL_TREE, NULL_TREE, 0);
|
| protected_set_expr_location (result, location);
|
| return result;
|
| }
|
|
|
| -/* Convert value RHS to type TYPE as preparation for an assignment
|
| - to an lvalue of type TYPE.
|
| +/* 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.
|
| ERRTYPE says whether it is argument passing, assignment,
|
| initialization or return.
|
|
|
| + LOCATION is the location of the RHS.
|
| FUNCTION is a tree for the function being called.
|
| 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,
|
| - tree fundecl, tree function, int parmnum)
|
| +convert_for_assignment (location_t location, 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;
|
| @@ -4028,14 +4890,14 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| /* This macro is used to emit diagnostics to ensure that all format
|
| strings are complete sentences, visible to gettext and checked at
|
| compile time. */
|
| -#define WARN_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \
|
| +#define WARN_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \
|
| do { \
|
| switch (errtype) \
|
| { \
|
| case ic_argpass: \
|
| if (pedwarn (LOCATION, OPT, AR, parmnum, rname)) \
|
| - inform ((fundecl && !DECL_IS_BUILTIN (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; \
|
| @@ -4046,18 +4908,15 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| pedwarn (LOCATION, OPT, IN); \
|
| break; \
|
| case ic_return: \
|
| - pedwarn (LOCATION, OPT, RE); \
|
| + pedwarn (LOCATION, OPT, RE); \
|
| break; \
|
| default: \
|
| gcc_unreachable (); \
|
| } \
|
| } 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);
|
| @@ -4091,6 +4950,25 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| 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;
|
|
|
| @@ -4101,7 +4979,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| an unprototyped function, it is compile-time undefined;
|
| making it a constraint in that case was rejected in
|
| DR#252. */
|
| - error ("void value not ignored as it ought to be");
|
| + error_at (location, "void value not ignored as it ought to be");
|
| return error_mark_node;
|
| }
|
| rhs = require_complete_type (rhs);
|
| @@ -4115,12 +4993,13 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| {
|
| if (!lvalue_p (rhs))
|
| {
|
| - error ("cannot pass rvalue to reference parameter");
|
| + error_at (location, "cannot pass rvalue to reference parameter");
|
| return error_mark_node;
|
| }
|
| if (!c_mark_addressable (rhs))
|
| return error_mark_node;
|
| rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs);
|
| + SET_EXPR_LOCATION (rhs, location);
|
|
|
| /* We already know that these two types are compatible, but they
|
| may not be exactly identical. In fact, `TREE_TYPE (type)' is
|
| @@ -4128,9 +5007,13 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| likely to be va_list, a typedef to __builtin_va_list, which
|
| is different enough that it will cause problems later. */
|
| if (TREE_TYPE (TREE_TYPE (rhs)) != TREE_TYPE (type))
|
| - rhs = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), rhs);
|
| + {
|
| + rhs = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), rhs);
|
| + SET_EXPR_LOCATION (rhs, location);
|
| + }
|
|
|
| rhs = build1 (NOP_EXPR, type, rhs);
|
| + SET_EXPR_LOCATION (rhs, location);
|
| return rhs;
|
| }
|
| /* Some types can interconvert without explicit casts. */
|
| @@ -4146,7 +5029,16 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| || 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)
|
| @@ -4154,9 +5046,10 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| && comptypes (type, rhstype))
|
| return convert_and_check (type, rhs);
|
|
|
| - /* Conversion to a transparent union from its member types.
|
| + /* Conversion to a transparent union or record from its member types.
|
| This applies only to function arguments. */
|
| - if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
|
| + if (((codel == UNION_TYPE || codel == RECORD_TYPE)
|
| + && TYPE_TRANSPARENT_AGGR (type))
|
| && errtype == ic_argpass)
|
| {
|
| tree memb, marginal_memb = NULL_TREE;
|
| @@ -4182,7 +5075,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| Meanwhile, the lhs target must have all the qualifiers of
|
| the rhs. */
|
| if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
|
| - || comp_target_types (memb_type, rhstype))
|
| + || comp_target_types (location, memb_type, rhstype))
|
| {
|
| /* If this type won't generate any warnings, use it. */
|
| if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
|
| @@ -4201,7 +5094,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| }
|
|
|
| /* Can convert integer zero to any pointer type. */
|
| - if (null_pointer_constant_p (rhs))
|
| + if (null_pointer_constant)
|
| {
|
| rhs = null_pointer_node;
|
| break;
|
| @@ -4227,8 +5120,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| certain things, it is okay to use a const or volatile
|
| function where an ordinary one is wanted, but not
|
| vice-versa. */
|
| - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE "
|
| "makes qualified function "
|
| "pointer from unqualified"),
|
| @@ -4241,8 +5135,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| G_("return makes qualified function "
|
| "pointer from unqualified"));
|
| }
|
| - else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE discards "
|
| "qualifiers from pointer target type"),
|
| G_("assignment discards qualifiers "
|
| @@ -4256,10 +5151,10 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| }
|
|
|
| if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
|
| - pedwarn (input_location, OPT_pedantic,
|
| + pedwarn (location, OPT_pedantic,
|
| "ISO C prohibits argument conversion to union type");
|
|
|
| - rhs = fold_convert (TREE_TYPE (memb), rhs);
|
| + rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs);
|
| return build_constructor_single (type, memb, rhs);
|
| }
|
| }
|
| @@ -4274,6 +5169,8 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| tree mvr = ttr;
|
| bool is_opaque_pointer;
|
| int target_cmp = 0; /* Cache comp_target_types () result. */
|
| + addr_space_t asl;
|
| + addr_space_t asr;
|
|
|
| if (TREE_CODE (mvl) != ARRAY_TYPE)
|
| mvl = TYPE_MAIN_VARIANT (mvl);
|
| @@ -4290,8 +5187,39 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
|
|
| where NULL is typically defined in C to be '(void *) 0'. */
|
| if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl))
|
| - warning (OPT_Wc___compat, "request for implicit conversion from "
|
| - "%qT to %qT not permitted in C++", rhstype, type);
|
| + warning_at (location, OPT_Wc___compat,
|
| + "request for implicit conversion "
|
| + "from %qT to %qT not permitted in C++", rhstype, type);
|
| +
|
| + /* See if the pointers point to incompatible address spaces. */
|
| + asl = TYPE_ADDR_SPACE (ttl);
|
| + asr = TYPE_ADDR_SPACE (ttr);
|
| + if (!null_pointer_constant_p (rhs)
|
| + && asr != asl && !targetm.addr_space.subset_p (asr, asl))
|
| + {
|
| + switch (errtype)
|
| + {
|
| + case ic_argpass:
|
| + error_at (location, "passing argument %d of %qE from pointer to "
|
| + "non-enclosed address space", parmnum, rname);
|
| + break;
|
| + case ic_assign:
|
| + error_at (location, "assignment from pointer to "
|
| + "non-enclosed address space");
|
| + break;
|
| + case ic_init:
|
| + error_at (location, "initialization from pointer to "
|
| + "non-enclosed address space");
|
| + break;
|
| + case ic_return:
|
| + error_at (location, "return from pointer to "
|
| + "non-enclosed address space");
|
| + break;
|
| + default:
|
| + gcc_unreachable ();
|
| + }
|
| + return error_mark_node;
|
| + }
|
|
|
| /* Check if the right-hand side has a format attribute but the
|
| left-hand side doesn't. */
|
| @@ -4301,25 +5229,25 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| switch (errtype)
|
| {
|
| case ic_argpass:
|
| - warning (OPT_Wmissing_format_attribute,
|
| - "argument %d of %qE might be "
|
| - "a candidate for a format attribute",
|
| - parmnum, rname);
|
| + warning_at (location, OPT_Wmissing_format_attribute,
|
| + "argument %d of %qE might be "
|
| + "a candidate for a format attribute",
|
| + parmnum, rname);
|
| break;
|
| case ic_assign:
|
| - warning (OPT_Wmissing_format_attribute,
|
| - "assignment left-hand side might be "
|
| - "a candidate for a format attribute");
|
| + warning_at (location, OPT_Wmissing_format_attribute,
|
| + "assignment left-hand side might be "
|
| + "a candidate for a format attribute");
|
| break;
|
| case ic_init:
|
| - warning (OPT_Wmissing_format_attribute,
|
| - "initialization left-hand side might be "
|
| - "a candidate for a format attribute");
|
| + warning_at (location, OPT_Wmissing_format_attribute,
|
| + "initialization left-hand side might be "
|
| + "a candidate for a format attribute");
|
| break;
|
| case ic_return:
|
| - warning (OPT_Wmissing_format_attribute,
|
| - "return type might be "
|
| - "a candidate for a format attribute");
|
| + warning_at (location, OPT_Wmissing_format_attribute,
|
| + "return type might be "
|
| + "a candidate for a format attribute");
|
| break;
|
| default:
|
| gcc_unreachable ();
|
| @@ -4330,7 +5258,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| and vice versa; otherwise, targets must be the same.
|
| Meanwhile, the lhs target must have all the qualifiers of the rhs. */
|
| if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
|
| - || (target_cmp = comp_target_types (type, rhstype))
|
| + || (target_cmp = comp_target_types (location, type, rhstype))
|
| || is_opaque_pointer
|
| || (c_common_unsigned_type (mvl)
|
| == c_common_unsigned_type (mvr)))
|
| @@ -4339,9 +5267,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| && ((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,
|
| + WARN_FOR_ASSIGNMENT (location, OPT_pedantic,
|
| G_("ISO C forbids passing argument %d of "
|
| "%qE between function pointer "
|
| "and %<void *%>"),
|
| @@ -4356,13 +5284,14 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| else if (TREE_CODE (ttr) != FUNCTION_TYPE
|
| && TREE_CODE (ttl) != FUNCTION_TYPE)
|
| {
|
| - if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
|
| + if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
|
| {
|
| /* Types differing only by the presence of the 'volatile'
|
| qualifier are acceptable if the 'volatile' has been added
|
| in by the Objective-C EH machinery. */
|
| if (!objc_type_quals_match (ttl, ttr))
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE discards "
|
| "qualifiers from pointer target type"),
|
| G_("assignment discards qualifiers "
|
| @@ -4379,7 +5308,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| ;
|
| /* If there is a mismatch, do warn. */
|
| else if (warn_pointer_sign)
|
| - WARN_FOR_ASSIGNMENT (input_location, OPT_Wpointer_sign,
|
| + WARN_FOR_ASSIGNMENT (location, OPT_Wpointer_sign,
|
| G_("pointer targets in passing argument "
|
| "%d of %qE differ in signedness"),
|
| G_("pointer targets in assignment "
|
| @@ -4396,8 +5325,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| that say the function will not do certain things,
|
| it is okay to use a const or volatile function
|
| where an ordinary one is wanted, but not vice-versa. */
|
| - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
|
| + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE makes "
|
| "qualified function pointer "
|
| "from unqualified"),
|
| @@ -4412,7 +5342,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| else
|
| /* Avoid warning about the volatile ObjC EH puts on decls. */
|
| if (!objc_ok)
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE from "
|
| "incompatible pointer type"),
|
| G_("assignment from incompatible pointer type"),
|
| @@ -4426,7 +5356,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| {
|
| /* ??? This should not be an error when inlining calls to
|
| unprototyped functions. */
|
| - error ("invalid use of non-lvalue array");
|
| + error_at (location, "invalid use of non-lvalue array");
|
| return error_mark_node;
|
| }
|
| else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
|
| @@ -4434,8 +5364,8 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| /* 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))
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + if (!null_pointer_constant)
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE makes "
|
| "pointer from integer without a cast"),
|
| G_("assignment makes pointer from integer "
|
| @@ -4449,7 +5379,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| }
|
| else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
|
| {
|
| - WARN_FOR_ASSIGNMENT (input_location, 0,
|
| + WARN_FOR_ASSIGNMENT (location, 0,
|
| G_("passing argument %d of %qE makes integer "
|
| "from pointer without a cast"),
|
| G_("assignment makes integer from pointer "
|
| @@ -4461,27 +5391,36 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
| 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:
|
| - error ("incompatible type for argument %d of %qE", parmnum, rname);
|
| + error_at (location, "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 when assigning to type %qT from type %qT",
|
| - type, rhstype);
|
| + error_at (location, "incompatible types when assigning to type %qT from "
|
| + "type %qT", type, rhstype);
|
| break;
|
| case ic_init:
|
| - error ("incompatible types when initializing type %qT using type %qT",
|
| - type, rhstype);
|
| + error_at (location,
|
| + "incompatible types when initializing type %qT using type %qT",
|
| + type, rhstype);
|
| break;
|
| case ic_return:
|
| - error ("incompatible types when returning type %qT but %qT was expected",
|
| - rhstype, type);
|
| + error_at (location,
|
| + "incompatible types when returning type %qT but %qT was "
|
| + "expected", rhstype, type);
|
| break;
|
| default:
|
| gcc_unreachable ();
|
| @@ -4516,12 +5455,16 @@ valid_compound_expr_initializer (tree value, tree endtype)
|
| /* 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 the init is invalid, store an ERROR_MARK. */
|
| + If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
|
| + If the init is invalid, store an ERROR_MARK.
|
| +
|
| + INIT_LOC is the location of the initial value. */
|
|
|
| void
|
| -store_init_value (tree decl, tree init)
|
| +store_init_value (location_t init_loc, tree decl, tree init, tree origtype)
|
| {
|
| tree value, type;
|
| + bool npc = false;
|
|
|
| /* If variable's type was invalidly declared, just ignore it. */
|
|
|
| @@ -4531,7 +5474,10 @@ store_init_value (tree decl, tree init)
|
|
|
| /* 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 (init_loc, type, init, origtype, npc,
|
| + true, TREE_STATIC (decl));
|
|
|
| /* Store the expression if valid; else report error. */
|
|
|
| @@ -4544,7 +5490,7 @@ store_init_value (tree decl, tree init)
|
|
|
| /* ANSI wants warnings about out-of-range constant initializers. */
|
| STRIP_TYPE_NOPS (value);
|
| - if (TREE_STATIC (decl))
|
| + if (TREE_STATIC (decl))
|
| constant_expression_warning (value);
|
|
|
| /* Check if we need to set array size from compound literal size. */
|
| @@ -4639,7 +5585,9 @@ static void
|
| push_member_name (tree decl)
|
| {
|
| const char *const string
|
| - = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
|
| + = (DECL_NAME (decl)
|
| + ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl)))
|
| + : _("<anonymous>"));
|
| PUSH_SPELLING (SPELLING_MEMBER, string, u.s);
|
| }
|
|
|
| @@ -4727,7 +5675,7 @@ pedwarn_init (location_t location, int opt, const char *msgid)
|
| pedwarn (location, opt, "(near initialization for %qs)", ofwhat);
|
| }
|
|
|
| -/* Issue a warning for a bad initializer component.
|
| +/* Issue a warning for a bad initializer component.
|
|
|
| OPT is the OPT_W* value corresponding to the warning option that
|
| controls this warning. MSGID identifies the message. The
|
| @@ -4755,25 +5703,35 @@ maybe_warn_string_init (tree type, struct c_expr expr)
|
| && TREE_CODE (type) == ARRAY_TYPE
|
| && TREE_CODE (expr.value) == STRING_CST
|
| && expr.original_code != STRING_CST)
|
| - pedwarn_init (input_location, OPT_pedantic,
|
| + pedwarn_init (input_location, OPT_pedantic,
|
| "array initialized from parenthesized string constant");
|
| }
|
|
|
| /* 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
|
| unparenthesized or we should not warn here for it being parenthesized.
|
| For other types of INIT, STRICT_STRING is not used.
|
|
|
| + INIT_LOC is the location of the INIT.
|
| +
|
| REQUIRE_CONSTANT requests an error if non-constant initializers or
|
| elements are seen. */
|
|
|
| static tree
|
| -digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| +digest_init (location_t init_loc, 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
|
| || !init
|
| @@ -4783,7 +5741,13 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
|
|
| 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. */
|
| @@ -4808,8 +5772,13 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| 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 (init_loc, OPT_pedantic,
|
| + "initialization of a flexible array member");
|
| +
|
| if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
|
| TYPE_MAIN_VARIANT (type)))
|
| return inside_init;
|
| @@ -4841,16 +5810,26 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| TREE_TYPE (inside_init) = type;
|
| if (TYPE_DOMAIN (type) != 0
|
| && TYPE_SIZE (type) != 0
|
| - && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
|
| + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
|
| + {
|
| + unsigned HOST_WIDE_INT len = TREE_STRING_LENGTH (inside_init);
|
| +
|
| /* Subtract the size of a single (possibly wide) character
|
| because it's ok to ignore the terminating null char
|
| that is counted in the length of the constant. */
|
| - && 0 > compare_tree_int (TYPE_SIZE_UNIT (type),
|
| - TREE_STRING_LENGTH (inside_init)
|
| - - (TYPE_PRECISION (typ1)
|
| - / BITS_PER_UNIT)))
|
| - pedwarn_init (input_location, 0,
|
| - "initializer-string for array of chars is too long");
|
| + if (0 > compare_tree_int (TYPE_SIZE_UNIT (type),
|
| + (len
|
| + - (TYPE_PRECISION (typ1)
|
| + / BITS_PER_UNIT))))
|
| + pedwarn_init (init_loc, 0,
|
| + ("initializer-string for array of chars "
|
| + "is too long"));
|
| + else if (warn_cxx_compat
|
| + && 0 > compare_tree_int (TYPE_SIZE_UNIT (type), len))
|
| + warning_at (init_loc, OPT_Wc___compat,
|
| + ("initializer-string for array chars "
|
| + "is too long for C++"));
|
| + }
|
|
|
| return inside_init;
|
| }
|
| @@ -4920,7 +5899,8 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| {
|
| if (TREE_CODE (inside_init) == STRING_CST
|
| || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
|
| - inside_init = array_to_pointer_conversion (inside_init);
|
| + inside_init = array_to_pointer_conversion
|
| + (init_loc, inside_init);
|
| else
|
| {
|
| error_init ("invalid use of non-lvalue array");
|
| @@ -4953,9 +5933,6 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| 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. */
|
| @@ -4968,7 +5945,7 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| if (inside_init == error_mark_node)
|
| error_init ("initializer element is not constant");
|
| else
|
| - pedwarn_init (input_location, OPT_pedantic,
|
| + pedwarn_init (init_loc, OPT_pedantic,
|
| "initializer element is not constant");
|
| if (flag_pedantic_errors)
|
| inside_init = error_mark_node;
|
| @@ -4980,11 +5957,16 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| error_init ("initializer element is not constant");
|
| inside_init = error_mark_node;
|
| }
|
| + else if (require_constant && !maybe_const)
|
| + pedwarn_init (init_loc, 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 (init_loc, type, inside_init,
|
| + origtype,
|
| + ic_init, null_pointer_constant,
|
| + NULL_TREE, NULL_TREE, 0);
|
| return inside_init;
|
| }
|
|
|
| @@ -4997,9 +5979,13 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| 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_loc, 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 (init_loc, type, inside_init, origtype,
|
| + ic_init, null_pointer_constant,
|
| NULL_TREE, NULL_TREE, 0);
|
|
|
| /* Check to see if we have already given an error message. */
|
| @@ -5017,6 +6003,9 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
|
| error_init ("initializer element is not computable at load time");
|
| inside_init = error_mark_node;
|
| }
|
| + else if (require_constant && !maybe_const)
|
| + pedwarn_init (init_loc, 0,
|
| + "initializer element is not a constant expression");
|
|
|
| return inside_init;
|
| }
|
| @@ -5076,6 +6065,10 @@ static int constructor_constant;
|
| /* 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;
|
|
|
| @@ -5089,6 +6082,7 @@ struct init_node
|
| int balance;
|
| tree purpose;
|
| tree value;
|
| + tree origtype;
|
| };
|
|
|
| /* Tree of pending elements at this constructor level.
|
| @@ -5145,6 +6139,7 @@ struct constructor_stack
|
| struct constructor_range_stack *range_stack;
|
| char constant;
|
| char simple;
|
| + char nonconst;
|
| char implicit;
|
| char erroneous;
|
| char outer;
|
| @@ -5226,13 +6221,13 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level)
|
| || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
|
| || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
|
| || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
|
| - locus = IDENTIFIER_POINTER (DECL_NAME (decl));
|
| + locus = identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (decl)));
|
| }
|
| else
|
| {
|
| require_constant_value = 0;
|
| require_constant_elements = 0;
|
| - locus = "(anonymous)";
|
| + locus = _("(anonymous)");
|
| }
|
|
|
| constructor_stack = 0;
|
| @@ -5295,7 +6290,8 @@ really_start_incremental_init (tree type)
|
| 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;
|
| @@ -5308,11 +6304,13 @@ really_start_incremental_init (tree 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;
|
| @@ -5323,6 +6321,7 @@ really_start_incremental_init (tree type)
|
|
|
| constructor_constant = 1;
|
| constructor_simple = 1;
|
| + constructor_nonconst = 0;
|
| constructor_depth = SPELLING_DEPTH ();
|
| constructor_elements = 0;
|
| constructor_pending_elts = 0;
|
| @@ -5449,11 +6448,13 @@ push_init_level (int implicit)
|
| 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;
|
| @@ -5464,6 +6465,7 @@ push_init_level (int implicit)
|
|
|
| constructor_constant = 1;
|
| constructor_simple = 1;
|
| + constructor_nonconst = 0;
|
| constructor_depth = SPELLING_DEPTH ();
|
| constructor_elements = 0;
|
| constructor_incremental = 1;
|
| @@ -5513,6 +6515,7 @@ push_init_level (int implicit)
|
| {
|
| 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
|
| @@ -5608,6 +6611,7 @@ pop_init_level (int implicit)
|
| struct c_expr ret;
|
| ret.value = 0;
|
| ret.original_code = ERROR_MARK;
|
| + ret.original_type = NULL;
|
|
|
| if (implicit == 0)
|
| {
|
| @@ -5717,9 +6721,19 @@ pop_init_level (int implicit)
|
| 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;
|
| @@ -5730,6 +6744,7 @@ pop_init_level (int implicit)
|
| 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;
|
| @@ -5852,6 +6867,24 @@ set_init_index (tree first, tree last)
|
| }
|
|
|
| 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");
|
| @@ -5864,6 +6897,9 @@ set_init_index (tree first, tree last)
|
| 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)
|
| @@ -5934,7 +6970,8 @@ set_init_label (tree fieldname)
|
|
|
| /* 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
|
| @@ -5942,7 +6979,7 @@ set_init_label (tree fieldname)
|
| 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;
|
|
|
| @@ -5968,6 +7005,7 @@ add_pending_init (tree purpose, tree value, bool implicit)
|
| warning_init (OPT_Woverride_init, "initialized field overwritten");
|
| }
|
| p->value = value;
|
| + p->origtype = origtype;
|
| return;
|
| }
|
| }
|
| @@ -5994,6 +7032,7 @@ add_pending_init (tree purpose, tree value, bool implicit)
|
| warning_init (OPT_Woverride_init, "initialized field overwritten");
|
| }
|
| p->value = value;
|
| + p->origtype = origtype;
|
| return;
|
| }
|
| }
|
| @@ -6002,6 +7041,7 @@ add_pending_init (tree purpose, tree value, bool implicit)
|
| r = GGC_NEW (struct init_node);
|
| r->purpose = purpose;
|
| r->value = value;
|
| + r->origtype = origtype;
|
|
|
| *q = r;
|
| r->parent = p;
|
| @@ -6177,7 +7217,7 @@ set_nonincremental_init (void)
|
| 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)
|
| {
|
| @@ -6267,7 +7307,7 @@ set_nonincremental_init_from_string (tree str)
|
| }
|
|
|
| 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;
|
| @@ -6332,6 +7372,7 @@ find_init_member (tree field)
|
| /* "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
|
| @@ -6348,10 +7389,13 @@ find_init_member (tree field)
|
| 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;
|
|
|
| if (type == error_mark_node || value == error_mark_node)
|
| {
|
| @@ -6366,7 +7410,7 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| && INTEGRAL_TYPE_P (TREE_TYPE (type)))
|
| && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
|
| TYPE_MAIN_VARIANT (type)))
|
| - value = array_to_pointer_conversion (value);
|
| + value = array_to_pointer_conversion (input_location, value);
|
|
|
| if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
|
| && require_constant_value && !flag_isoc99 && pending)
|
| @@ -6378,6 +7422,14 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| 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))
|
| @@ -6388,6 +7440,8 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| && 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)))
|
| {
|
| @@ -6400,6 +7454,28 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| 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");
|
| +
|
| + /* 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. */
|
| @@ -6411,12 +7487,17 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| || 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 (input_location, type, value, origtype, 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. */
|
| @@ -6428,7 +7509,7 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| && 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
|
| @@ -6454,7 +7535,7 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| }
|
| }
|
|
|
| - add_pending_init (field, value, implicit);
|
| + add_pending_init (field, value, origtype, implicit);
|
| return;
|
| }
|
| else if (TREE_CODE (constructor_type) == UNION_TYPE
|
| @@ -6484,8 +7565,8 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|
| /* Advance the variable that indicates sequential elements output. */
|
| if (TREE_CODE (constructor_type) == ARRAY_TYPE)
|
| constructor_unfilled_index
|
| - = size_binop (PLUS_EXPR, constructor_unfilled_index,
|
| - bitsize_one_node);
|
| + = size_binop_loc (input_location, PLUS_EXPR, constructor_unfilled_index,
|
| + bitsize_one_node);
|
| else if (TREE_CODE (constructor_type) == RECORD_TYPE)
|
| {
|
| constructor_unfilled_fields
|
| @@ -6537,7 +7618,7 @@ output_pending_init_elements (int all)
|
| {
|
| 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,
|
| @@ -6591,7 +7672,8 @@ output_pending_init_elements (int all)
|
| 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))
|
| @@ -6705,7 +7787,8 @@ process_init_element (struct c_expr value, bool implicit)
|
| || 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)))
|
| @@ -6722,7 +7805,18 @@ process_init_element (struct c_expr value, bool implicit)
|
| 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)
|
| @@ -6766,7 +7860,7 @@ process_init_element (struct c_expr value, bool implicit)
|
| && 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;
|
| @@ -6775,8 +7869,9 @@ process_init_element (struct c_expr value, bool implicit)
|
| 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
|
| @@ -6786,9 +7881,9 @@ process_init_element (struct c_expr value, bool implicit)
|
| /* For a record, keep track of end position of last field. */
|
| if (DECL_SIZE (constructor_fields))
|
| constructor_bit_index
|
| - = size_binop (PLUS_EXPR,
|
| - bit_position (constructor_fields),
|
| - DECL_SIZE (constructor_fields));
|
| + = size_binop_loc (input_location, PLUS_EXPR,
|
| + bit_position (constructor_fields),
|
| + DECL_SIZE (constructor_fields));
|
|
|
| /* If the current field was the first one not yet written out,
|
| it isn't now, so update. */
|
| @@ -6856,7 +7951,7 @@ process_init_element (struct c_expr value, bool implicit)
|
| && 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;
|
| @@ -6865,8 +7960,9 @@ process_init_element (struct c_expr value, bool implicit)
|
| 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
|
| @@ -6896,7 +7992,7 @@ process_init_element (struct c_expr value, bool implicit)
|
| && 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;
|
| @@ -6915,13 +8011,15 @@ process_init_element (struct c_expr value, bool implicit)
|
| 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);
|
| }
|
|
|
| constructor_index
|
| - = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
|
| + = size_binop_loc (input_location, PLUS_EXPR,
|
| + constructor_index, bitsize_one_node);
|
|
|
| if (!value.value)
|
| /* If we are doing the bookkeeping for an element that was
|
| @@ -6944,11 +8042,17 @@ process_init_element (struct c_expr value, bool implicit)
|
|
|
| /* 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);
|
| + = size_binop_loc (input_location,
|
| + PLUS_EXPR, constructor_index, bitsize_one_node);
|
|
|
| if (!value.value)
|
| /* If we are doing the bookkeeping for an element that was
|
| @@ -6969,8 +8073,9 @@ process_init_element (struct c_expr value, bool implicit)
|
| 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;
|
| }
|
|
|
| @@ -6996,7 +8101,8 @@ process_init_element (struct c_expr value, bool implicit)
|
| process_init_element (pop_init_level (1), true);
|
| }
|
|
|
| - p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
|
| + p->index = size_binop_loc (input_location,
|
| + PLUS_EXPR, p->index, bitsize_one_node);
|
| if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
|
| finish = 1;
|
|
|
| @@ -7046,8 +8152,8 @@ build_asm_stmt (tree cv_qualifier, tree args)
|
| string in the asm expression -- asm("blah") and asm("blah" : )
|
| are subtly different. We use a ASM_EXPR node to represent this. */
|
| tree
|
| -build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
|
| - bool simple)
|
| +build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
|
| + tree clobbers, tree labels, bool simple)
|
| {
|
| tree tail;
|
| tree args;
|
| @@ -7061,7 +8167,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
|
| noutputs = list_length (outputs);
|
| oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
|
|
|
| - string = resolve_asm_operand_names (string, outputs, inputs);
|
| + string = resolve_asm_operand_names (string, outputs, inputs, labels);
|
|
|
| /* Remove output conversions that change the type but not the mode. */
|
| for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
|
| @@ -7131,7 +8237,11 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
|
| TREE_VALUE (tail) = input;
|
| }
|
|
|
| - args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
|
| + /* ASMs with labels cannot have outputs. This should have been
|
| + enforced by the parser. */
|
| + gcc_assert (outputs == NULL || labels == NULL);
|
| +
|
| + args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels);
|
|
|
| /* asm statements without outputs, including simple ones, are treated
|
| as volatile. */
|
| @@ -7141,75 +8251,67 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
|
| return args;
|
| }
|
|
|
| -/* Generate a goto statement to LABEL. */
|
| +/* Generate a goto statement to LABEL. LOC is the location of the
|
| + GOTO. */
|
|
|
| tree
|
| -c_finish_goto_label (tree label)
|
| +c_finish_goto_label (location_t loc, tree label)
|
| {
|
| - tree decl = lookup_label (label);
|
| + tree decl = lookup_label_for_goto (loc, label);
|
| if (!decl)
|
| return NULL_TREE;
|
| -
|
| - if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
|
| - {
|
| - error ("jump into statement expression");
|
| - return NULL_TREE;
|
| - }
|
| -
|
| - if (C_DECL_UNJUMPABLE_VM (decl))
|
| - {
|
| - error ("jump into scope of identifier with variably modified type");
|
| - return NULL_TREE;
|
| - }
|
| -
|
| - if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
|
| - {
|
| - /* No jump from outside this statement expression context, so
|
| - record that there is a jump from within this context. */
|
| - struct c_label_list *nlist;
|
| - nlist = XOBNEW (&parser_obstack, struct c_label_list);
|
| - nlist->next = label_context_stack_se->labels_used;
|
| - nlist->label = decl;
|
| - label_context_stack_se->labels_used = nlist;
|
| - }
|
| -
|
| - if (!C_DECL_UNDEFINABLE_VM (decl))
|
| - {
|
| - /* No jump from outside this context context of identifiers with
|
| - variably modified type, so record that there is a jump from
|
| - within this context. */
|
| - struct c_label_list *nlist;
|
| - nlist = XOBNEW (&parser_obstack, struct c_label_list);
|
| - nlist->next = label_context_stack_vm->labels_used;
|
| - nlist->label = decl;
|
| - label_context_stack_vm->labels_used = nlist;
|
| - }
|
| -
|
| TREE_USED (decl) = 1;
|
| - return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
|
| + {
|
| + tree t = build1 (GOTO_EXPR, void_type_node, decl);
|
| + SET_EXPR_LOCATION (t, loc);
|
| + return add_stmt (t);
|
| + }
|
| }
|
|
|
| -/* Generate a computed goto statement to EXPR. */
|
| +/* Generate a computed goto statement to EXPR. LOC is the location of
|
| + the GOTO. */
|
|
|
| tree
|
| -c_finish_goto_ptr (tree expr)
|
| +c_finish_goto_ptr (location_t loc, tree expr)
|
| {
|
| - pedwarn (input_location, OPT_pedantic, "ISO C forbids %<goto *expr;%>");
|
| + tree t;
|
| + pedwarn (loc, 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));
|
| + t = build1 (GOTO_EXPR, void_type_node, expr);
|
| + SET_EXPR_LOCATION (t, loc);
|
| + return add_stmt (t);
|
| }
|
|
|
| /* 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. LOC is
|
| + the location of the return statement. If ORIGTYPE is not NULL_TREE, it
|
| + is the original type of RETVAL. */
|
|
|
| tree
|
| -c_finish_return (tree retval)
|
| +c_finish_return (location_t loc, tree retval, tree origtype)
|
| {
|
| 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");
|
| + warning_at (loc, 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)
|
| {
|
| @@ -7217,7 +8319,7 @@ c_finish_return (tree retval)
|
| if ((warn_return_type || flag_isoc99)
|
| && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
|
| {
|
| - pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wreturn_type,
|
| + pedwarn_c99 (loc, flag_isoc99 ? 0 : OPT_Wreturn_type,
|
| "%<return%> with no value, in "
|
| "function returning non-void");
|
| no_warning = true;
|
| @@ -7227,16 +8329,17 @@ c_finish_return (tree retval)
|
| {
|
| current_function_returns_null = 1;
|
| if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
|
| - pedwarn (input_location, 0,
|
| + pedwarn (loc, 0,
|
| "%<return%> with a value, in function returning void");
|
| - else
|
| - pedwarn (input_location, OPT_pedantic, "ISO C forbids "
|
| + else
|
| + pedwarn (loc, OPT_pedantic, "ISO C forbids "
|
| "%<return%> with expression, in function returning void");
|
| }
|
| else
|
| {
|
| - tree t = convert_for_assignment (valtype, retval, ic_return,
|
| - NULL_TREE, NULL_TREE, 0);
|
| + tree t = convert_for_assignment (loc, valtype, retval, origtype,
|
| + ic_return,
|
| + npc, NULL_TREE, NULL_TREE, 0);
|
| tree res = DECL_RESULT (current_function_decl);
|
| tree inner;
|
|
|
| @@ -7289,7 +8392,8 @@ c_finish_return (tree retval)
|
| && !DECL_EXTERNAL (inner)
|
| && !TREE_STATIC (inner)
|
| && DECL_CONTEXT (inner) == current_function_decl)
|
| - warning (0, "function returns address of local variable");
|
| + warning_at (loc,
|
| + 0, "function returns address of local variable");
|
| break;
|
|
|
| default:
|
| @@ -7300,12 +8404,13 @@ c_finish_return (tree retval)
|
| }
|
|
|
| retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t);
|
| + SET_EXPR_LOCATION (retval, loc);
|
|
|
| if (warn_sequence_point)
|
| verify_sequence_points (retval);
|
| }
|
|
|
| - ret_stmt = build_stmt (RETURN_EXPR, retval);
|
| + ret_stmt = build_stmt (loc, RETURN_EXPR, retval);
|
| TREE_NO_WARNING (ret_stmt) |= no_warning;
|
| return add_stmt (ret_stmt);
|
| }
|
| @@ -7325,15 +8430,9 @@ struct c_switch {
|
| of the GNU case range extension. */
|
| splay_tree cases;
|
|
|
| - /* Number of nested statement expressions within this switch
|
| - statement; if nonzero, case and default labels may not
|
| - appear. */
|
| - unsigned int blocked_stmt_expr;
|
| -
|
| - /* Scope of outermost declarations of identifiers with variably
|
| - modified type within this switch statement; if nonzero, case and
|
| - default labels may not appear. */
|
| - unsigned int blocked_vm;
|
| + /* The bindings at the point of the switch. This is used for
|
| + warnings crossing decls when branching to a case label. */
|
| + struct c_spot_bindings *bindings;
|
|
|
| /* The next node on the stack. */
|
| struct c_switch *next;
|
| @@ -7348,10 +8447,13 @@ struct c_switch {
|
| struct c_switch *c_switch_stack;
|
|
|
| /* Start a C switch statement, testing expression EXP. Return the new
|
| - SWITCH_EXPR. */
|
| + SWITCH_EXPR. SWITCH_LOC is the location of the `switch'.
|
| + SWITCH_COND_LOC is the location of the switch's condition. */
|
|
|
| tree
|
| -c_start_case (tree exp)
|
| +c_start_case (location_t switch_loc,
|
| + location_t switch_cond_loc,
|
| + tree exp)
|
| {
|
| tree orig_type = error_mark_node;
|
| struct c_switch *cs;
|
| @@ -7364,7 +8466,7 @@ c_start_case (tree exp)
|
| {
|
| if (orig_type != error_mark_node)
|
| {
|
| - error ("switch quantity not an integer");
|
| + error_at (switch_cond_loc, "switch quantity not an integer");
|
| orig_type = error_mark_node;
|
| }
|
| exp = integer_zero_node;
|
| @@ -7376,9 +8478,11 @@ c_start_case (tree exp)
|
| if (!in_system_header
|
| && (type == long_integer_type_node
|
| || type == long_unsigned_type_node))
|
| - warning (OPT_Wtraditional, "%<long%> switch expression not "
|
| - "converted to %<int%> in ISO C");
|
| + warning_at (switch_cond_loc,
|
| + 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)
|
| @@ -7389,56 +8493,59 @@ c_start_case (tree exp)
|
| /* Add this new SWITCH_EXPR to the stack. */
|
| cs = XNEW (struct c_switch);
|
| cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE);
|
| + SET_EXPR_LOCATION (cs->switch_expr, switch_loc);
|
| cs->orig_type = orig_type;
|
| cs->cases = splay_tree_new (case_compare, NULL, NULL);
|
| - cs->blocked_stmt_expr = 0;
|
| - cs->blocked_vm = 0;
|
| + cs->bindings = c_get_switch_bindings ();
|
| cs->next = c_switch_stack;
|
| c_switch_stack = cs;
|
|
|
| return add_stmt (cs->switch_expr);
|
| }
|
|
|
| -/* Process a case label. */
|
| +/* Process a case label at location LOC. */
|
|
|
| tree
|
| -do_case (tree low_value, tree high_value)
|
| +do_case (location_t loc, tree low_value, tree high_value)
|
| {
|
| tree label = NULL_TREE;
|
|
|
| - if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
|
| - && !c_switch_stack->blocked_vm)
|
| + if (low_value && TREE_CODE (low_value) != INTEGER_CST)
|
| {
|
| - label = c_add_case_label (c_switch_stack->cases,
|
| - SWITCH_COND (c_switch_stack->switch_expr),
|
| - c_switch_stack->orig_type,
|
| - low_value, high_value);
|
| - if (label == error_mark_node)
|
| - label = NULL_TREE;
|
| + 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");
|
| }
|
| - else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
|
| +
|
| + if (high_value && TREE_CODE (high_value) != INTEGER_CST)
|
| {
|
| - if (low_value)
|
| - error ("case label in statement expression not containing "
|
| - "enclosing switch statement");
|
| - else
|
| - error ("%<default%> label in statement expression not containing "
|
| - "enclosing switch statement");
|
| + 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");
|
| }
|
| - else if (c_switch_stack && c_switch_stack->blocked_vm)
|
| +
|
| + if (c_switch_stack == NULL)
|
| {
|
| if (low_value)
|
| - error ("case label in scope of identifier with variably modified "
|
| - "type not containing enclosing switch statement");
|
| + error_at (loc, "case label not within a switch statement");
|
| else
|
| - error ("%<default%> label in scope of identifier with variably "
|
| - "modified type not containing enclosing switch statement");
|
| + error_at (loc, "%<default%> label not within a switch statement");
|
| + return NULL_TREE;
|
| }
|
| - else if (low_value)
|
| - error ("case label not within a switch statement");
|
| - else
|
| - error ("%<default%> label not within a switch statement");
|
|
|
| + if (c_check_switch_jump_warnings (c_switch_stack->bindings,
|
| + EXPR_LOCATION (c_switch_stack->switch_expr),
|
| + loc))
|
| + return NULL_TREE;
|
| +
|
| + label = c_add_case_label (loc, c_switch_stack->cases,
|
| + SWITCH_COND (c_switch_stack->switch_expr),
|
| + c_switch_stack->orig_type,
|
| + low_value, high_value);
|
| + if (label == error_mark_node)
|
| + label = NULL_TREE;
|
| return label;
|
| }
|
|
|
| @@ -7452,16 +8559,8 @@ c_finish_case (tree body)
|
|
|
| SWITCH_BODY (cs->switch_expr) = body;
|
|
|
| - /* We must not be within a statement expression nested in the switch
|
| - at this point; we might, however, be within the scope of an
|
| - identifier with variably modified type nested in the switch. */
|
| - gcc_assert (!cs->blocked_stmt_expr);
|
| -
|
| /* Emit warnings as needed. */
|
| - if (EXPR_HAS_LOCATION (cs->switch_expr))
|
| - switch_location = EXPR_LOCATION (cs->switch_expr);
|
| - else
|
| - switch_location = input_location;
|
| + switch_location = EXPR_LOCATION (cs->switch_expr);
|
| c_do_switch_warnings (cs->cases, switch_location,
|
| TREE_TYPE (cs->switch_expr),
|
| SWITCH_COND (cs->switch_expr));
|
| @@ -7469,6 +8568,7 @@ c_finish_case (tree body)
|
| /* Pop the stack. */
|
| c_switch_stack = cs->next;
|
| splay_tree_delete (cs->cases);
|
| + c_release_switch_bindings (cs->bindings);
|
| XDELETE (cs);
|
| }
|
|
|
| @@ -7513,9 +8613,8 @@ c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
|
| found:
|
|
|
| if (COND_EXPR_ELSE (inner_if))
|
| - warning (OPT_Wparentheses,
|
| - "%Hsuggest explicit braces to avoid ambiguous %<else%>",
|
| - &if_locus);
|
| + warning_at (if_locus, OPT_Wparentheses,
|
| + "suggest explicit braces to avoid ambiguous %<else%>");
|
| }
|
|
|
| stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
|
| @@ -7573,11 +8672,12 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
|
| }
|
|
|
| t = build_and_jump (&blab);
|
| - exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t);
|
| if (cond_is_first)
|
| - SET_EXPR_LOCATION (exit, start_locus);
|
| + exit = fold_build3_loc (start_locus,
|
| + COND_EXPR, void_type_node, cond, exit, t);
|
| else
|
| - SET_EXPR_LOCATION (exit, input_location);
|
| + exit = fold_build3_loc (input_location,
|
| + COND_EXPR, void_type_node, cond, exit, t);
|
| }
|
|
|
| add_stmt (top);
|
| @@ -7598,7 +8698,7 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
|
| }
|
|
|
| tree
|
| -c_finish_bc_stmt (tree *label_p, bool is_break)
|
| +c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
|
| {
|
| bool skip;
|
| tree label = *label_p;
|
| @@ -7615,7 +8715,7 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
|
| if (!label)
|
| {
|
| if (!skip)
|
| - *label_p = label = create_artificial_label ();
|
| + *label_p = label = create_artificial_label (loc);
|
| }
|
| else if (TREE_CODE (label) == LABEL_DECL)
|
| ;
|
| @@ -7623,14 +8723,14 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
|
| {
|
| case 0:
|
| if (is_break)
|
| - error ("break statement not within loop or switch");
|
| + error_at (loc, "break statement not within loop or switch");
|
| else
|
| - error ("continue statement not within a loop");
|
| + error_at (loc, "continue statement not within a loop");
|
| return NULL_TREE;
|
|
|
| case 1:
|
| gcc_assert (is_break);
|
| - error ("break statement used with OpenMP for loop");
|
| + error_at (loc, "break statement used with OpenMP for loop");
|
| return NULL_TREE;
|
|
|
| default:
|
| @@ -7649,62 +8749,65 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
|
| /* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */
|
|
|
| static void
|
| -emit_side_effect_warnings (tree expr)
|
| +emit_side_effect_warnings (location_t loc, tree expr)
|
| {
|
| if (expr == error_mark_node)
|
| ;
|
| else if (!TREE_SIDE_EFFECTS (expr))
|
| {
|
| if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
|
| - warning (OPT_Wunused_value, "%Hstatement with no effect",
|
| - EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
|
| + warning_at (loc, OPT_Wunused_value, "statement with no effect");
|
| }
|
| else
|
| - warn_if_unused_value (expr, input_location);
|
| + warn_if_unused_value (expr, loc);
|
| }
|
|
|
| /* Process an expression as if it were a complete statement. Emit
|
| - diagnostics, but do not call ADD_STMT. */
|
| + diagnostics, but do not call ADD_STMT. LOC is the location of the
|
| + statement. */
|
|
|
| tree
|
| -c_process_expr_stmt (tree expr)
|
| +c_process_expr_stmt (location_t loc, tree expr)
|
| {
|
| if (!expr)
|
| return NULL_TREE;
|
|
|
| + expr = c_fully_fold (expr, false, NULL);
|
| +
|
| if (warn_sequence_point)
|
| verify_sequence_points (expr);
|
|
|
| if (TREE_TYPE (expr) != error_mark_node
|
| && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
|
| && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
|
| - error ("expression statement has incomplete type");
|
| + error_at (loc, "expression statement has incomplete type");
|
|
|
| /* If we're not processing a statement expression, warn about unused values.
|
| Warnings for statement expressions will be emitted later, once we figure
|
| out which is the result. */
|
| if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
|
| && warn_unused_value)
|
| - emit_side_effect_warnings (expr);
|
| + emit_side_effect_warnings (loc, expr);
|
|
|
| /* If the expression is not of a type to which we cannot assign a line
|
| number, wrap the thing in a no-op NOP_EXPR. */
|
| if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
|
| - expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
|
| -
|
| - if (CAN_HAVE_LOCATION_P (expr))
|
| - SET_EXPR_LOCATION (expr, input_location);
|
| + {
|
| + expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
|
| + SET_EXPR_LOCATION (expr, loc);
|
| + }
|
|
|
| return expr;
|
| }
|
|
|
| -/* Emit an expression as a statement. */
|
| +/* Emit an expression as a statement. LOC is the location of the
|
| + expression. */
|
|
|
| tree
|
| -c_finish_expr_stmt (tree expr)
|
| +c_finish_expr_stmt (location_t loc, tree expr)
|
| {
|
| if (expr)
|
| - return add_stmt (c_process_expr_stmt (expr));
|
| + return add_stmt (c_process_expr_stmt (loc, expr));
|
| else
|
| return NULL;
|
| }
|
| @@ -7716,30 +8819,16 @@ tree
|
| c_begin_stmt_expr (void)
|
| {
|
| tree ret;
|
| - struct c_label_context_se *nstack;
|
| - struct c_label_list *glist;
|
|
|
| /* We must force a BLOCK for this level so that, if it is not expanded
|
| later, there is a way to turn off the entire subtree of blocks that
|
| are contained in it. */
|
| keep_next_level ();
|
| ret = c_begin_compound_stmt (true);
|
| - if (c_switch_stack)
|
| - {
|
| - c_switch_stack->blocked_stmt_expr++;
|
| - gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
|
| - }
|
| - for (glist = label_context_stack_se->labels_used;
|
| - glist != NULL;
|
| - glist = glist->next)
|
| - {
|
| - C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
|
| - }
|
| - nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
|
| - nstack->labels_def = NULL;
|
| - nstack->labels_used = NULL;
|
| - nstack->next = label_context_stack_se;
|
| - label_context_stack_se = nstack;
|
| +
|
| + c_bindings_start_stmt_expr (c_switch_stack == NULL
|
| + ? NULL
|
| + : c_switch_stack->bindings);
|
|
|
| /* Mark the current statement list as belonging to a statement list. */
|
| STATEMENT_LIST_STMT_EXPR (ret) = 1;
|
| @@ -7747,42 +8836,20 @@ c_begin_stmt_expr (void)
|
| return ret;
|
| }
|
|
|
| +/* LOC is the location of the compound statement to which this body
|
| + belongs. */
|
| +
|
| tree
|
| -c_finish_stmt_expr (tree body)
|
| +c_finish_stmt_expr (location_t loc, tree body)
|
| {
|
| tree last, type, tmp, val;
|
| tree *last_p;
|
| - struct c_label_list *dlist, *glist, *glist_prev = NULL;
|
|
|
| - body = c_end_compound_stmt (body, true);
|
| - if (c_switch_stack)
|
| - {
|
| - gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
|
| - c_switch_stack->blocked_stmt_expr--;
|
| - }
|
| - /* It is no longer possible to jump to labels defined within this
|
| - statement expression. */
|
| - for (dlist = label_context_stack_se->labels_def;
|
| - dlist != NULL;
|
| - dlist = dlist->next)
|
| - {
|
| - C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
|
| - }
|
| - /* It is again possible to define labels with a goto just outside
|
| - this statement expression. */
|
| - for (glist = label_context_stack_se->next->labels_used;
|
| - glist != NULL;
|
| - glist = glist->next)
|
| - {
|
| - C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
|
| - glist_prev = glist;
|
| - }
|
| - if (glist_prev != NULL)
|
| - glist_prev->next = label_context_stack_se->labels_used;
|
| - else
|
| - label_context_stack_se->next->labels_used
|
| - = label_context_stack_se->labels_used;
|
| - label_context_stack_se = label_context_stack_se->next;
|
| + body = c_end_compound_stmt (loc, body, true);
|
| +
|
| + c_bindings_end_stmt_expr (c_switch_stack == NULL
|
| + ? NULL
|
| + : c_switch_stack->bindings);
|
|
|
| /* Locate the last statement in BODY. See c_end_compound_stmt
|
| about always returning a BIND_EXPR. */
|
| @@ -7803,7 +8870,13 @@ c_finish_stmt_expr (tree body)
|
| if (warn_unused_value)
|
| {
|
| for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
|
| - emit_side_effect_warnings (tsi_stmt (i));
|
| + {
|
| + location_t tloc;
|
| + tree t = tsi_stmt (i);
|
| +
|
| + tloc = EXPR_HAS_LOCATION (t) ? EXPR_LOCATION (t) : loc;
|
| + emit_side_effect_warnings (tloc, t);
|
| + }
|
| }
|
| else
|
| i = tsi_last (last);
|
| @@ -7821,16 +8894,20 @@ c_finish_stmt_expr (tree body)
|
| goto continue_searching;
|
| }
|
|
|
| + if (last == error_mark_node)
|
| + return last;
|
| +
|
| /* In the case that the BIND_EXPR is not necessary, return the
|
| expression out from inside it. */
|
| - if (last == error_mark_node
|
| - || (last == BIND_EXPR_BODY (body)
|
| - && BIND_EXPR_VARS (body) == NULL))
|
| + if (last == BIND_EXPR_BODY (body)
|
| + && BIND_EXPR_VARS (body) == NULL)
|
| {
|
| + /* Even if this looks constant, do not allow it in a constant
|
| + expression. */
|
| + last = c_wrap_maybe_const (last, true);
|
| /* 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;
|
| }
|
|
|
| @@ -7855,83 +8932,13 @@ c_finish_stmt_expr (tree body)
|
| val = TREE_OPERAND (val, 0);
|
|
|
| *last_p = build2 (MODIFY_EXPR, void_type_node, tmp, val);
|
| - SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
|
| -
|
| - return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
|
| -}
|
| -
|
| -/* Begin the scope of an identifier of variably modified type, scope
|
| - number SCOPE. Jumping from outside this scope to inside it is not
|
| - permitted. */
|
| -
|
| -void
|
| -c_begin_vm_scope (unsigned int scope)
|
| -{
|
| - struct c_label_context_vm *nstack;
|
| - struct c_label_list *glist;
|
| -
|
| - gcc_assert (scope > 0);
|
| -
|
| - /* At file_scope, we don't have to do any processing. */
|
| - if (label_context_stack_vm == NULL)
|
| - return;
|
| + SET_EXPR_LOCATION (*last_p, EXPR_LOCATION (last));
|
|
|
| - if (c_switch_stack && !c_switch_stack->blocked_vm)
|
| - c_switch_stack->blocked_vm = scope;
|
| - for (glist = label_context_stack_vm->labels_used;
|
| - glist != NULL;
|
| - glist = glist->next)
|
| - {
|
| - C_DECL_UNDEFINABLE_VM (glist->label) = 1;
|
| - }
|
| - nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
|
| - nstack->labels_def = NULL;
|
| - nstack->labels_used = NULL;
|
| - nstack->scope = scope;
|
| - nstack->next = label_context_stack_vm;
|
| - label_context_stack_vm = nstack;
|
| -}
|
| -
|
| -/* End a scope which may contain identifiers of variably modified
|
| - type, scope number SCOPE. */
|
| -
|
| -void
|
| -c_end_vm_scope (unsigned int scope)
|
| -{
|
| - if (label_context_stack_vm == NULL)
|
| - return;
|
| - if (c_switch_stack && c_switch_stack->blocked_vm == scope)
|
| - c_switch_stack->blocked_vm = 0;
|
| - /* We may have a number of nested scopes of identifiers with
|
| - variably modified type, all at this depth. Pop each in turn. */
|
| - while (label_context_stack_vm->scope == scope)
|
| - {
|
| - struct c_label_list *dlist, *glist, *glist_prev = NULL;
|
| -
|
| - /* It is no longer possible to jump to labels defined within this
|
| - scope. */
|
| - for (dlist = label_context_stack_vm->labels_def;
|
| - dlist != NULL;
|
| - dlist = dlist->next)
|
| - {
|
| - C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
|
| - }
|
| - /* It is again possible to define labels with a goto just outside
|
| - this scope. */
|
| - for (glist = label_context_stack_vm->next->labels_used;
|
| - glist != NULL;
|
| - glist = glist->next)
|
| - {
|
| - C_DECL_UNDEFINABLE_VM (glist->label) = 0;
|
| - glist_prev = glist;
|
| - }
|
| - if (glist_prev != NULL)
|
| - glist_prev->next = label_context_stack_vm->labels_used;
|
| - else
|
| - label_context_stack_vm->next->labels_used
|
| - = label_context_stack_vm->labels_used;
|
| - label_context_stack_vm = label_context_stack_vm->next;
|
| - }
|
| + {
|
| + tree t = build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
|
| + SET_EXPR_LOCATION (t, loc);
|
| + return t;
|
| + }
|
| }
|
|
|
| /* Begin and end compound statements. This is as simple as pushing
|
| @@ -7946,8 +8953,12 @@ c_begin_compound_stmt (bool do_scope)
|
| return stmt;
|
| }
|
|
|
| +/* End a compound statement. STMT is the statement. LOC is the
|
| + location of the compound statement-- this is usually the location
|
| + of the opening brace. */
|
| +
|
| tree
|
| -c_end_compound_stmt (tree stmt, bool do_scope)
|
| +c_end_compound_stmt (location_t loc, tree stmt, bool do_scope)
|
| {
|
| tree block = NULL;
|
|
|
| @@ -7959,7 +8970,7 @@ c_end_compound_stmt (tree stmt, bool do_scope)
|
| }
|
|
|
| stmt = pop_stmt_list (stmt);
|
| - stmt = c_build_bind_expr (block, stmt);
|
| + stmt = c_build_bind_expr (loc, block, stmt);
|
|
|
| /* If this compound statement is nested immediately inside a statement
|
| expression, then force a BIND_EXPR to be created. Otherwise we'll
|
| @@ -7972,6 +8983,7 @@ c_end_compound_stmt (tree stmt, bool do_scope)
|
| {
|
| stmt = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL);
|
| TREE_SIDE_EFFECTS (stmt) = 1;
|
| + SET_EXPR_LOCATION (stmt, loc);
|
| }
|
|
|
| return stmt;
|
| @@ -7982,14 +8994,14 @@ c_end_compound_stmt (tree stmt, bool do_scope)
|
| meant to apply to normal control flow transfer. */
|
|
|
| void
|
| -push_cleanup (tree ARG_UNUSED (decl), tree cleanup, bool eh_only)
|
| +push_cleanup (tree decl, tree cleanup, bool eh_only)
|
| {
|
| enum tree_code code;
|
| tree stmt, list;
|
| bool stmt_expr;
|
|
|
| code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
|
| - stmt = build_stmt (code, NULL, cleanup);
|
| + stmt = build_stmt (DECL_SOURCE_LOCATION (decl), code, NULL, cleanup);
|
| add_stmt (stmt);
|
| stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list);
|
| list = push_stmt_list ();
|
| @@ -8017,11 +9029,14 @@ tree
|
| 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,
|
| @@ -8032,6 +9047,10 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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 semantic_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. */
|
| @@ -8068,22 +9087,42 @@ build_binary_op (location_t location, enum tree_code code,
|
| /* 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. */
|
| @@ -8107,6 +9146,45 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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)
|
| @@ -8115,12 +9193,12 @@ build_binary_op (location_t location, enum tree_code code,
|
| /* Handle the pointer + int case. */
|
| if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
| {
|
| - ret = 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)
|
| {
|
| - ret = pointer_int_sum (PLUS_EXPR, op1, op0);
|
| + ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
|
| goto return_build_binary_op;
|
| }
|
| else
|
| @@ -8131,15 +9209,15 @@ build_binary_op (location_t location, enum tree_code code,
|
| /* Subtraction of two similar pointers.
|
| We must subtract them as integers, then divide by object size. */
|
| if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
|
| - && comp_target_types (type0, type1))
|
| + && comp_target_types (location, type0, type1))
|
| {
|
| - ret = pointer_diff (op0, op1);
|
| + ret = pointer_diff (location, op0, op1);
|
| goto return_build_binary_op;
|
| }
|
| /* Handle pointer minus int. Just like pointer plus int. */
|
| else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
| {
|
| - ret = pointer_int_sum (MINUS_EXPR, op0, op1);
|
| + ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
|
| goto return_build_binary_op;
|
| }
|
| else
|
| @@ -8204,7 +9282,11 @@ build_binary_op (location_t location, enum tree_code code,
|
| case FLOOR_MOD_EXPR:
|
| warn_for_div_by_zero (location, op1);
|
|
|
| - if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
|
| + if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
|
| + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
|
| + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
|
| + common = 1;
|
| + else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
|
| {
|
| /* Although it would be tempting to shorten always here, that loses
|
| on some targets, since the modulo instruction is undefined if the
|
| @@ -8237,6 +9319,28 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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;
|
| @@ -8247,17 +9351,25 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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 (c_inhibit_evaluation_warnings == 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 (c_inhibit_evaluation_warnings == 0)
|
| + warning (0, "right shift count >= width of type");
|
| + }
|
| }
|
| }
|
|
|
| @@ -8276,13 +9388,21 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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 (c_inhibit_evaluation_warnings == 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 (c_inhibit_evaluation_warnings == 0)
|
| + warning (0, "left shift count >= width of type");
|
| + }
|
| }
|
|
|
| /* Use the type of the value to be shifted. */
|
| @@ -8314,24 +9434,34 @@ build_binary_op (location_t location, enum tree_code code,
|
| {
|
| tree tt0 = TREE_TYPE (type0);
|
| tree tt1 = TREE_TYPE (type1);
|
| + addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
|
| + addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
|
| + addr_space_t as_common = ADDR_SPACE_GENERIC;
|
| +
|
| /* Anything compares with void *. void * compares with anything.
|
| Otherwise, the targets must be compatible
|
| and both must be object or both incomplete. */
|
| - if (comp_target_types (type0, type1))
|
| + if (comp_target_types (location, type0, type1))
|
| result_type = common_pointer_type (type0, type1);
|
| + else if (null_pointer_constant_p (orig_op0))
|
| + result_type = type1;
|
| + else if (null_pointer_constant_p (orig_op1))
|
| + result_type = type0;
|
| + else if (!addr_space_superset (as0, as1, &as_common))
|
| + {
|
| + error_at (location, "comparison of pointers to "
|
| + "disjoint address spaces");
|
| + return error_mark_node;
|
| + }
|
| else if (VOID_TYPE_P (tt0))
|
| {
|
| - /* op0 != orig_op0 detects the case of something
|
| - whose value is 0 but which isn't a valid null ptr const. */
|
| - if (pedantic && !null_pointer_constant_p (orig_op0)
|
| - && TREE_CODE (tt1) == FUNCTION_TYPE)
|
| + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
|
| pedwarn (location, OPT_pedantic, "ISO C forbids "
|
| "comparison of %<void *%> with function pointer");
|
| }
|
| else if (VOID_TYPE_P (tt1))
|
| {
|
| - if (pedantic && !null_pointer_constant_p (orig_op1)
|
| - && TREE_CODE (tt0) == FUNCTION_TYPE)
|
| + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
|
| pedwarn (location, OPT_pedantic, "ISO C forbids "
|
| "comparison of %<void *%> with function pointer");
|
| }
|
| @@ -8342,7 +9472,11 @@ build_binary_op (location_t location, enum tree_code code,
|
| "comparison of distinct pointer types lacks a cast");
|
|
|
| if (result_type == NULL_TREE)
|
| - result_type = ptr_type_node;
|
| + {
|
| + int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
|
| + result_type = build_pointer_type
|
| + (build_qualified_type (void_type_node, qual));
|
| + }
|
| }
|
| else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
|
| {
|
| @@ -8386,7 +9520,11 @@ build_binary_op (location_t location, enum tree_code code,
|
| short_compare = 1;
|
| else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
|
| {
|
| - if (comp_target_types (type0, type1))
|
| + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
|
| + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
|
| + addr_space_t as_common;
|
| +
|
| + if (comp_target_types (location, type0, type1))
|
| {
|
| result_type = common_pointer_type (type0, type1);
|
| if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
|
| @@ -8397,9 +9535,17 @@ build_binary_op (location_t location, enum tree_code code,
|
| pedwarn (location, OPT_pedantic, "ISO C forbids "
|
| "ordered comparisons of pointers to functions");
|
| }
|
| + else if (!addr_space_superset (as0, as1, &as_common))
|
| + {
|
| + error_at (location, "comparison of pointers to "
|
| + "disjoint address spaces");
|
| + return error_mark_node;
|
| + }
|
| else
|
| {
|
| - result_type = ptr_type_node;
|
| + int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
|
| + result_type = build_pointer_type
|
| + (build_qualified_type (void_type_node, qual));
|
| pedwarn (location, 0,
|
| "comparison of distinct pointer types lacks a cast");
|
| }
|
| @@ -8408,7 +9554,7 @@ build_binary_op (location_t location, enum tree_code code,
|
| {
|
| result_type = type0;
|
| if (pedantic)
|
| - pedwarn (location, OPT_pedantic,
|
| + pedwarn (location, OPT_pedantic,
|
| "ordered comparison of pointer with integer zero");
|
| else if (extra_warnings)
|
| warning_at (location, OPT_Wextra,
|
| @@ -8417,7 +9563,7 @@ build_binary_op (location_t location, enum tree_code code,
|
| else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
|
| {
|
| result_type = type1;
|
| - pedwarn (location, OPT_pedantic,
|
| + pedwarn (location, OPT_pedantic,
|
| "ordered comparison of pointer with integer zero");
|
| }
|
| else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
| @@ -8454,7 +9600,9 @@ build_binary_op (location_t location, enum tree_code code,
|
| (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
|
| || code1 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE))
|
| {
|
| - int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
|
| + bool first_complex = (code0 == COMPLEX_TYPE);
|
| + bool second_complex = (code1 == COMPLEX_TYPE);
|
| + int none_complex = (!first_complex && !second_complex);
|
|
|
| if (shorten || common || short_compare)
|
| {
|
| @@ -8463,6 +9611,89 @@ build_binary_op (location_t location, enum tree_code code,
|
| return error_mark_node;
|
| }
|
|
|
| + if (first_complex != second_complex
|
| + && (code == PLUS_EXPR
|
| + || code == MINUS_EXPR
|
| + || code == MULT_EXPR
|
| + || (code == TRUNC_DIV_EXPR && first_complex))
|
| + && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE
|
| + && flag_signed_zeros)
|
| + {
|
| + /* An operation on mixed real/complex operands must be
|
| + handled specially, but the language-independent code can
|
| + more easily optimize the plain complex arithmetic if
|
| + -fno-signed-zeros. */
|
| + tree real_type = TREE_TYPE (result_type);
|
| + tree real, imag;
|
| + if (type0 != orig_type0 || type1 != orig_type1)
|
| + {
|
| + gcc_assert (may_need_excess_precision && common);
|
| + semantic_result_type = c_common_type (orig_type0, orig_type1);
|
| + }
|
| + if (first_complex)
|
| + {
|
| + if (TREE_TYPE (op0) != result_type)
|
| + op0 = convert_and_check (result_type, op0);
|
| + if (TREE_TYPE (op1) != real_type)
|
| + op1 = convert_and_check (real_type, op1);
|
| + }
|
| + else
|
| + {
|
| + if (TREE_TYPE (op0) != real_type)
|
| + op0 = convert_and_check (real_type, op0);
|
| + if (TREE_TYPE (op1) != result_type)
|
| + op1 = convert_and_check (result_type, op1);
|
| + }
|
| + if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
|
| + return error_mark_node;
|
| + if (first_complex)
|
| + {
|
| + op0 = c_save_expr (op0);
|
| + real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
|
| + op0, 1);
|
| + imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
|
| + op0, 1);
|
| + switch (code)
|
| + {
|
| + case MULT_EXPR:
|
| + case TRUNC_DIV_EXPR:
|
| + imag = build2 (resultcode, real_type, imag, op1);
|
| + /* Fall through. */
|
| + case PLUS_EXPR:
|
| + case MINUS_EXPR:
|
| + real = build2 (resultcode, real_type, real, op1);
|
| + break;
|
| + default:
|
| + gcc_unreachable();
|
| + }
|
| + }
|
| + else
|
| + {
|
| + op1 = c_save_expr (op1);
|
| + real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
|
| + op1, 1);
|
| + imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
|
| + op1, 1);
|
| + switch (code)
|
| + {
|
| + case MULT_EXPR:
|
| + imag = build2 (resultcode, real_type, op0, imag);
|
| + /* Fall through. */
|
| + case PLUS_EXPR:
|
| + real = build2 (resultcode, real_type, op0, real);
|
| + break;
|
| + case MINUS_EXPR:
|
| + real = build2 (resultcode, real_type, op0, real);
|
| + imag = build1 (NEGATE_EXPR, real_type, imag);
|
| + break;
|
| + default:
|
| + gcc_unreachable();
|
| + }
|
| + }
|
| + ret = build2 (COMPLEX_EXPR, result_type, real, imag);
|
| + goto return_build_binary_op;
|
| + }
|
| +
|
| /* For certain operations (which identify themselves by shorten != 0)
|
| if both args were extended from the same smaller type,
|
| do the arithmetic in that type and then extend.
|
| @@ -8477,7 +9708,7 @@ build_binary_op (location_t location, enum tree_code code,
|
| if (shorten && none_complex)
|
| {
|
| final_type = result_type;
|
| - result_type = shorten_binary_op (result_type, op0, op1,
|
| + result_type = shorten_binary_op (result_type, op0, op1,
|
| shorten == -1);
|
| }
|
|
|
| @@ -8536,10 +9767,48 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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 (c_inhibit_evaluation_warnings == 0)
|
| + {
|
| + 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. */
|
| + c_inhibit_evaluation_warnings++;
|
| + op0 = c_fully_fold (op0, require_constant_value,
|
| + &op0_maybe_const);
|
| + op1 = c_fully_fold (op1, require_constant_value,
|
| + &op1_maybe_const);
|
| + c_inhibit_evaluation_warnings--;
|
| + 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 = c_wrap_maybe_const (op0, !op0_maybe_const);
|
| + if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
|
| + op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -8556,12 +9825,20 @@ build_binary_op (location_t location, enum tree_code code,
|
| return error_mark_node;
|
| }
|
|
|
| + if (build_type == NULL_TREE)
|
| + {
|
| + build_type = result_type;
|
| + if (type0 != orig_type0 || type1 != orig_type1)
|
| + {
|
| + gcc_assert (may_need_excess_precision && common);
|
| + semantic_result_type = c_common_type (orig_type0, orig_type1);
|
| + }
|
| + }
|
| +
|
| if (!converted)
|
| {
|
| - if (TREE_TYPE (op0) != result_type)
|
| - op0 = convert_and_check (result_type, op0);
|
| - if (TREE_TYPE (op1) != result_type)
|
| - op1 = convert_and_check (result_type, op1);
|
| + op0 = ep_convert_and_check (result_type, op0, semantic_result_type);
|
| + op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
|
|
|
| /* This can happen if one operand has a vector type, and the other
|
| has a different type. */
|
| @@ -8569,20 +9846,28 @@ build_binary_op (location_t location, enum tree_code code,
|
| return error_mark_node;
|
| }
|
|
|
| - if (build_type == NULL_TREE)
|
| - build_type = result_type;
|
| -
|
| /* Treat expressions in initializers specially as they can't trap. */
|
| - ret = require_constant_value ? fold_build2_initializer (resultcode,
|
| - build_type,
|
| - op0, op1)
|
| - : fold_build2 (resultcode, build_type,
|
| - op0, op1);
|
| + if (int_const_or_overflow)
|
| + ret = (require_constant_value
|
| + ? fold_build2_initializer_loc (location, resultcode, build_type,
|
| + op0, op1)
|
| + : fold_build2_loc (location, 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 (semantic_result_type)
|
| + ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
|
| protected_set_expr_location (ret, location);
|
| return ret;
|
| }
|
| @@ -8594,6 +9879,8 @@ build_binary_op (location_t location, enum tree_code code,
|
| 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:
|
| @@ -8615,9 +9902,25 @@ c_objc_common_truthvalue_conversion (location_t location, tree expr)
|
| 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;
|
| }
|
|
|
|
|
| @@ -8653,19 +9956,21 @@ c_begin_omp_parallel (void)
|
| return block;
|
| }
|
|
|
| -/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound statement. */
|
| +/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound
|
| + statement. LOC is the location of the OMP_PARALLEL. */
|
|
|
| tree
|
| -c_finish_omp_parallel (tree clauses, tree block)
|
| +c_finish_omp_parallel (location_t loc, tree clauses, tree block)
|
| {
|
| tree stmt;
|
|
|
| - block = c_end_compound_stmt (block, true);
|
| + block = c_end_compound_stmt (loc, block, true);
|
|
|
| stmt = make_node (OMP_PARALLEL);
|
| TREE_TYPE (stmt) = void_type_node;
|
| OMP_PARALLEL_CLAUSES (stmt) = clauses;
|
| OMP_PARALLEL_BODY (stmt) = block;
|
| + SET_EXPR_LOCATION (stmt, loc);
|
|
|
| return add_stmt (stmt);
|
| }
|
| @@ -8683,19 +9988,21 @@ c_begin_omp_task (void)
|
| return block;
|
| }
|
|
|
| -/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound statement. */
|
| +/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound
|
| + statement. LOC is the location of the #pragma. */
|
|
|
| tree
|
| -c_finish_omp_task (tree clauses, tree block)
|
| +c_finish_omp_task (location_t loc, tree clauses, tree block)
|
| {
|
| tree stmt;
|
|
|
| - block = c_end_compound_stmt (block, true);
|
| + block = c_end_compound_stmt (loc, block, true);
|
|
|
| stmt = make_node (OMP_TASK);
|
| TREE_TYPE (stmt) = void_type_node;
|
| OMP_TASK_CLAUSES (stmt) = clauses;
|
| OMP_TASK_BODY (stmt) = block;
|
| + SET_EXPR_LOCATION (stmt, loc);
|
|
|
| return add_stmt (stmt);
|
| }
|
| @@ -8741,7 +10048,8 @@ c_finish_omp_clauses (tree clauses)
|
| if (AGGREGATE_TYPE_P (TREE_TYPE (t))
|
| || POINTER_TYPE_P (TREE_TYPE (t)))
|
| {
|
| - error ("%qE has invalid type for %<reduction%>", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE has invalid type for %<reduction%>", t);
|
| remove = true;
|
| }
|
| else if (FLOAT_TYPE_P (TREE_TYPE (t)))
|
| @@ -8775,8 +10083,9 @@ c_finish_omp_clauses (tree clauses)
|
| }
|
| if (r_name)
|
| {
|
| - error ("%qE has invalid type for %<reduction(%s)%>",
|
| - t, r_name);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE has invalid type for %<reduction(%s)%>",
|
| + t, r_name);
|
| remove = true;
|
| }
|
| }
|
| @@ -8791,7 +10100,8 @@ c_finish_omp_clauses (tree clauses)
|
| t = OMP_CLAUSE_DECL (c);
|
| if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
|
| {
|
| - error ("%qE must be %<threadprivate%> for %<copyin%>", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE must be %<threadprivate%> for %<copyin%>", t);
|
| remove = true;
|
| }
|
| goto check_dup_generic;
|
| @@ -8800,14 +10110,16 @@ c_finish_omp_clauses (tree clauses)
|
| t = OMP_CLAUSE_DECL (c);
|
| if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
|
| {
|
| - error ("%qE is not a variable in clause %qs", t, name);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE is not a variable in clause %qs", t, name);
|
| remove = true;
|
| }
|
| else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|
| || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
|
| || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
|
| {
|
| - error ("%qE appears more than once in data clauses", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE appears more than once in data clauses", t);
|
| remove = true;
|
| }
|
| else
|
| @@ -8821,13 +10133,15 @@ c_finish_omp_clauses (tree clauses)
|
| need_implicitly_determined = true;
|
| if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
|
| {
|
| - error ("%qE is not a variable in clause %<firstprivate%>", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE is not a variable in clause %<firstprivate%>", t);
|
| remove = true;
|
| }
|
| else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|
| || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
|
| {
|
| - error ("%qE appears more than once in data clauses", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE appears more than once in data clauses", t);
|
| remove = true;
|
| }
|
| else
|
| @@ -8841,13 +10155,15 @@ c_finish_omp_clauses (tree clauses)
|
| need_implicitly_determined = true;
|
| if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
|
| {
|
| - error ("%qE is not a variable in clause %<lastprivate%>", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE is not a variable in clause %<lastprivate%>", t);
|
| remove = true;
|
| }
|
| else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|
| || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
|
| {
|
| - error ("%qE appears more than once in data clauses", t);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE appears more than once in data clauses", t);
|
| remove = true;
|
| }
|
| else
|
| @@ -8901,8 +10217,9 @@ c_finish_omp_clauses (tree clauses)
|
| }
|
| if (share_name)
|
| {
|
| - error ("%qE is predetermined %qs for %qs",
|
| - t, share_name, name);
|
| + error_at (OMP_CLAUSE_LOCATION (c),
|
| + "%qE is predetermined %qs for %qs",
|
| + t, share_name, name);
|
| remove = true;
|
| }
|
| }
|
| @@ -8956,11 +10273,11 @@ c_build_qualified_type (tree type, int type_quals)
|
| else if (TYPE_CANONICAL (element_type) != element_type
|
| || (domain && TYPE_CANONICAL (domain) != domain))
|
| {
|
| - tree unqualified_canon
|
| + tree unqualified_canon
|
| = build_array_type (TYPE_CANONICAL (element_type),
|
| - domain? TYPE_CANONICAL (domain)
|
| + domain? TYPE_CANONICAL (domain)
|
| : NULL_TREE);
|
| - TYPE_CANONICAL (t)
|
| + TYPE_CANONICAL (t)
|
| = c_build_qualified_type (unqualified_canon, type_quals);
|
| }
|
| else
|
| @@ -8982,3 +10299,14 @@ c_build_qualified_type (tree type, int type_quals)
|
|
|
| return build_qualified_type (type, type_quals);
|
| }
|
| +
|
| +/* Build a VA_ARG_EXPR for the C parser. */
|
| +
|
| +tree
|
| +c_build_va_arg (location_t loc, tree expr, tree type)
|
| +{
|
| + if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE)
|
| + warning_at (loc, OPT_Wc___compat,
|
| + "C++ requires promoted type, not enum type, in %<va_arg%>");
|
| + return build_va_arg (loc, expr, type);
|
| +}
|
|
|