/* 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, 2011
Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "rtl.h"
#include "tree.h"
#include "langhooks.h"
#include "c-tree.h"
#include "c-lang.h"
-#include "tm_p.h"
#include "flags.h"
#include "output.h"
-#include "expr.h"
-#include "toplev.h"
#include "intl.h"
-#include "ggc.h"
#include "target.h"
#include "tree-iterator.h"
+#include "bitmap.h"
#include "gimple.h"
-#include "tree-flow.h"
+#include "c-family/c-objc.h"
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
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;
+/* Possibe cases of scalar_to_vector conversion. */
+enum stv_conv {
+ stv_error, /* Error occured. */
+ stv_nothing, /* Nothing happened. */
+ stv_firstarg, /* First argument must be expanded. */
+ stv_secondarg /* Second argument must be expanded. */
+};
/* The level of nesting inside "__alignof__". */
int in_alignof;
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, bool *);
+static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
+ 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 int function_types_compatible_p (const_tree, const_tree, bool *,
+ bool *);
+static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
static tree lookup_field (tree, tree);
static int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree,
tree);
static char *print_spelling (char *);
static void warning_init (int, const char *);
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, 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 output_init_element (tree, tree, bool, tree, tree, int, bool,
+ struct obstack *);
+static void output_pending_init_elements (int, struct obstack *);
+static int set_designator (int, struct obstack *);
+static void push_range_stack (tree, struct obstack *);
+static void add_pending_init (tree, tree, tree, bool, struct obstack *);
+static void set_nonincremental_init (struct obstack *);
+static void set_nonincremental_init_from_string (tree, struct obstack *);
+static tree find_init_member (tree, struct obstack *);
static void readonly_warning (tree, enum lvalue_use);
-static int lvalue_or_else (const_tree, enum lvalue_use);
+static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *);
+static int comptypes_internal (const_tree, const_tree, bool *, bool *);
\f
/* Return true if EXP is a null pointer constant, false otherwise. */
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. */
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
tree target = composite_type (pointed_to_1, pointed_to_2);
- t1 = build_pointer_type (target);
+ t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, 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);
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
- /* Tell global_bindings_p to return false so that variable_size
- doesn't die on VLAs in parameter types. */
- c_override_global_bindings_to_false = true;
len = list_length (p1);
newargs = 0;
&& TREE_CODE (mv2) != ARRAY_TYPE)
mv2 = TYPE_MAIN_VARIANT (mv2);
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
- memb; memb = TREE_CHAIN (memb))
+ memb; memb = DECL_CHAIN (memb))
{
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
{
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;
}
&& TREE_CODE (mv1) != ARRAY_TYPE)
mv1 = TYPE_MAIN_VARIANT (mv1);
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
- memb; memb = TREE_CHAIN (memb))
+ memb; memb = DECL_CHAIN (memb))
{
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
{
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;
}
parm_done: ;
}
- c_override_global_bindings_to_false = false;
t1 = build_function_type (valtype, newargs);
t1 = qualify_type (t1, t2);
/* ... falls through ... */
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. */
/* 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);
}
const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
int val;
- val = comptypes_internal (type1, type2, NULL);
+ val = comptypes_internal (type1, type2, NULL, NULL);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
return val;
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);
+ val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
+ free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+
+ return val;
+}
+
+/* Like comptypes, but if it returns nonzero for different types, it
+ sets *DIFFERENT_TYPES_P to true. */
+
+int
+comptypes_check_different_types (tree type1, tree type2,
+ bool *different_types_p)
+{
+ const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
+ int val;
+
+ val = comptypes_internal (type1, type2, NULL, different_types_p);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
return val;
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. */
+ *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not
+ NULL, and the types are compatible but different enough not to be
+ permitted in C11 typedef redeclarations, then this sets
+ *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to
+ false, but may or may not be set if the types are incompatible.
+ This differs from comptypes, in that we don't free the seen
+ types. */
static int
-comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p)
+comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
+ bool *different_types_p)
{
const_tree t1 = type1;
const_tree t2 = type2;
|| TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
return 1;
- /* If either type is the internal version of sizetype, return the
- language version. */
- if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
- && TYPE_ORIG_SIZE_TYPE (t1))
- t1 = TYPE_ORIG_SIZE_TYPE (t1);
-
- if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
- && TYPE_ORIG_SIZE_TYPE (t2))
- t2 = TYPE_ORIG_SIZE_TYPE (t2);
-
-
/* Enumerated types are compatible with integer types, but this is
not transitive: two enumerated types in the same translation unit
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));
- if (enum_and_int_p != NULL && TREE_CODE (t2) != VOID_TYPE)
- *enum_and_int_p = true;
+ if (TREE_CODE (t2) != VOID_TYPE)
+ {
+ if (enum_and_int_p != NULL)
+ *enum_and_int_p = true;
+ if (different_types_p != NULL)
+ *different_types_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));
- if (enum_and_int_p != NULL && TREE_CODE (t1) != VOID_TYPE)
- *enum_and_int_p = true;
+ if (TREE_CODE (t1) != VOID_TYPE)
+ {
+ if (enum_and_int_p != NULL)
+ *enum_and_int_p = true;
+ if (different_types_p != NULL)
+ *different_types_p = true;
+ }
}
if (t1 == t2)
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- if (!(attrval = targetm.comp_type_attributes (t1, t2)))
+ if (!(attrval = comp_type_attributes (t1, t2)))
return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p));
+ enum_and_int_p, different_types_p));
break;
case FUNCTION_TYPE:
- val = function_types_compatible_p (t1, t2, enum_and_int_p);
+ val = function_types_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
break;
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
&& 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p)))
+ enum_and_int_p,
+ different_types_p)))
return 0;
+ if (different_types_p != NULL
+ && (d1 == 0) != (d2 == 0))
+ *different_types_p = true;
/* Sizes must match unless one is missing or variable. */
if (d1 == 0 || d2 == 0 || d1 == d2)
break;
d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
+ if (different_types_p != NULL
+ && d1_variable != d2_variable)
+ *different_types_p = true;
if (d1_variable || d2_variable)
break;
if (d1_zero && d2_zero)
break;
if (attrval != 2)
- return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
- val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
+ return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
+ val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
}
break;
case VECTOR_TYPE:
val = (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
&& comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p));
+ enum_and_int_p, different_types_p));
break;
default:
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 (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)
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. ENUM_AND_INT_P is as in comptypes_internal. */
+ rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+ comptypes_internal. */
static int
tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
tree s1, s2;
bool needs_warning = false;
/* Speed up the common case where the fields are in the same order. */
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2;
- s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
+ s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
{
int result;
if (DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p, different_types_p);
if (result != 1 && !DECL_NAME (s1))
break;
return tu->val;
}
- for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
+ for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1))
{
bool ok = false;
- for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
+ for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2))
if (DECL_NAME (s1) == DECL_NAME (s2))
{
int result;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p,
+ different_types_p);
if (result != 1 && !DECL_NAME (s1))
continue;
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
s1 && s2;
- s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
+ s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
{
int result;
if (TREE_CODE (s1) != TREE_CODE (s2)
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p, different_types_p);
if (result == 0)
break;
if (result == 2)
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.
- ENUM_AND_INT_P is as in comptypes_internal. */
+ ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */
static int
function_types_compatible_p (const_tree f1, const_tree f2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
tree args1, args2;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
- val = comptypes_internal (ret1, ret2, enum_and_int_p);
+ val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p);
if (val == 0)
return 0;
args1 = TYPE_ARG_TYPES (f1);
args2 = TYPE_ARG_TYPES (f2);
+ if (different_types_p != NULL
+ && (args1 == 0) != (args2 == 0))
+ *different_types_p = true;
+
/* An unspecified parmlist matches any specified parmlist
whose argument types don't need default promotions. */
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),
- enum_and_int_p))
+ enum_and_int_p, different_types_p))
val = 2;
return val;
}
return 0;
if (TYPE_ACTUAL_ARG_TYPES (f2)
&& 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
- enum_and_int_p))
+ enum_and_int_p, different_types_p))
val = 2;
return val;
}
/* Both types have argument lists: compare them and propagate results. */
- val1 = type_lists_compatible_p (args1, args2, enum_and_int_p);
+ val1 = type_lists_compatible_p (args1, args2, enum_and_int_p,
+ different_types_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. ENUM_AND_INT_P is as in comptypes_internal. */
+ warning. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+ comptypes_internal. */
static int
type_lists_compatible_p (const_tree args1, const_tree args2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
means there is supposed to be an argument
but nothing is specified about what type it has.
So match anything that self-promotes. */
+ if (different_types_p != NULL
+ && (a1 == 0) != (a2 == 0))
+ *different_types_p = true;
if (a1 == 0)
{
if (c_type_promotes_to (a2) != a2)
else if (TREE_CODE (a1) == ERROR_MARK
|| TREE_CODE (a2) == ERROR_MARK)
;
- else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p)))
+ else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p,
+ different_types_p)))
{
+ if (different_types_p != NULL)
+ *different_types_p = true;
/* 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)))
{
tree memb;
for (memb = TYPE_FIELDS (a1);
- memb; memb = TREE_CHAIN (memb))
+ memb; memb = DECL_CHAIN (memb))
{
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes_internal (mv3, mv2, enum_and_int_p))
+ if (comptypes_internal (mv3, mv2, enum_and_int_p,
+ different_types_p))
break;
}
if (memb == 0)
}
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)))
{
tree memb;
for (memb = TYPE_FIELDS (a2);
- memb; memb = TREE_CHAIN (memb))
+ memb; memb = DECL_CHAIN (memb))
{
tree mv3 = TREE_TYPE (memb);
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes_internal (mv3, mv1, enum_and_int_p))
+ if (comptypes_internal (mv3, mv1, enum_and_int_p,
+ different_types_p))
break;
}
if (memb == 0)
if (TREE_CODE (exp) == INDIRECT_REF)
return convert (ptrtype, TREE_OPERAND (exp, 0));
+ /* In C++ array compound literals are temporary objects unless they are
+ const or appear in namespace scope, so they are destroyed too soon
+ to use them for much of anything (c++/53220). */
+ if (warn_cxx_compat && TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
+ {
+ tree decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ if (!TREE_READONLY (decl) && !TREE_STATIC (decl))
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
+ "converting an array compound literal to a pointer "
+ "is ill-formed in C++");
+ }
+
adr = build_unary_op (loc, ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}
return build_unary_op (loc, ADDR_EXPR, exp, 0);
}
+/* Mark EXP as read, not just set, for set but not used -Wunused
+ warning purposes. */
+
+void
+mark_exp_read (tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ DECL_READ_P (exp) = 1;
+ break;
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ CASE_CONVERT:
+ case ADDR_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 0));
+ break;
+ case COMPOUND_EXPR:
+ case C_MAYBE_CONST_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ break;
+ default:
+ break;
+ }
+}
+
/* Perform the default conversion of arrays and functions to pointers.
Return the result of converting EXP. For any other expression, just
return EXP.
return exp;
}
+struct c_expr
+default_function_array_read_conversion (location_t loc, struct c_expr exp)
+{
+ mark_exp_read (exp.value);
+ return default_function_array_conversion (loc, exp);
+}
/* EXP is an expression of integer type. Apply the integer promotions
to it and return the promoted value. */
enum tree_code code = TREE_CODE (type);
tree promoted_type;
+ mark_exp_read (exp);
+
/* Functions and arrays have been converted during parsing. */
gcc_assert (code != FUNCTION_TYPE);
if (code == ARRAY_TYPE)
return exp;
}
\f
-/* Look up COMPONENT in a structure or union DECL.
+/* Look up COMPONENT in a structure or union TYPE.
If the component name is not found, returns NULL_TREE. Otherwise,
the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
unions, the list steps down the chain to the component. */
static tree
-lookup_field (tree decl, tree component)
+lookup_field (tree type, tree component)
{
- tree type = TREE_TYPE (decl);
tree field;
/* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
- tree anon = lookup_field (field, component);
+ tree anon = lookup_field (TREE_TYPE (field), component);
if (anon)
return tree_cons (NULL_TREE, field, anon);
+
+ /* The Plan 9 compiler permits referring
+ directly to an anonymous struct/union field
+ using a typedef name. */
+ if (flag_plan9_extensions
+ && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+ && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
+ == TYPE_DECL)
+ && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+ == component))
+ break;
}
}
}
else
{
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
if (DECL_NAME (field) == NULL_TREE
&& (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
{
- tree anon = lookup_field (field, component);
+ tree anon = lookup_field (TREE_TYPE (field), component);
if (anon)
return tree_cons (NULL_TREE, field, anon);
+
+ /* The Plan 9 compiler permits referring directly to an
+ anonymous struct/union field using a typedef
+ name. */
+ if (flag_plan9_extensions
+ && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL
+ && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+ == component))
+ break;
}
if (DECL_NAME (field) == component)
if (!objc_is_public (datum, component))
return error_mark_node;
+ /* Detect Objective-C property syntax object.property. */
+ if (c_dialect_objc ()
+ && (ref = objc_maybe_build_component_ref (datum, component)))
+ return ref;
+
/* See if there is a field or component with name COMPONENT. */
if (code == RECORD_TYPE || code == UNION_TYPE)
return error_mark_node;
}
- field = lookup_field (datum, component);
+ field = lookup_field (type, component);
if (!field)
{
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);
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error_at (loc,
- "invalid type argument of %qs (have %qT)", errorstring, type);
+ invalid_indirection_error (loc, type, errstring);
+
return error_mark_node;
}
arrays that are not lvalues (for example, members of structures returned
by functions).
+ For vector types, allow vector[i] but not i[vector], and create
+ *(((type*)&vectortype) + i) for the expression.
+
LOC is the location to use for the returned expression. */
tree
return error_mark_node;
if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE)
+ && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE
+ /* Allow vector[index] but not index[vector]. */
+ && TREE_CODE (TREE_TYPE (array)) != VECTOR_TYPE)
{
tree temp;
if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
{
- error_at (loc, "subscripted value is neither array nor pointer");
+ error_at (loc,
+ "subscripted value is neither array nor pointer nor vector");
+
return error_mark_node;
}
temp = array;
gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+ /* For vector[index], convert the vector to a
+ pointer of the underlying type. */
+ if (TREE_CODE (TREE_TYPE (array)) == VECTOR_TYPE)
+ {
+ tree type = TREE_TYPE (array);
+ tree type1;
+
+ if (TREE_CODE (index) == INTEGER_CST)
+ if (!host_integerp (index, 1)
+ || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1)
+ >= TYPE_VECTOR_SUBPARTS (TREE_TYPE (array))))
+ warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
+
+ c_common_mark_addressable_vec (array);
+ type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+ type = build_pointer_type (type);
+ type1 = build_pointer_type (TREE_TYPE (array));
+ array = build1 (ADDR_EXPR, type1, array);
+ array = convert (type, array);
+ }
+
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
{
tree rval, type;
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");
}
return build_indirect_ref
(loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0),
- "array indexing");
+ RO_ARRAY_INDEXING);
}
}
\f
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;
}
tree tem;
int nargs;
tree *argarray;
-
+
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
return tem;
name = DECL_NAME (function);
+
+ if (flag_tm)
+ tm_malloc_replacement (function);
fundecl = function;
+ /* Atomic functions have type checking/casting already done. They are
+ often rewritten and don't match the original parameter list. */
+ if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9))
+ origtypes = NULL;
}
if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
function = function_to_pointer_conversion (loc, function);
&& !comptypes (fntype, TREE_TYPE (tem)))
{
tree return_type = TREE_TYPE (fntype);
- tree trap = build_function_call (loc, built_in_decls[BUILT_IN_TRAP],
+ tree trap = build_function_call (loc,
+ builtin_decl_explicit (BUILT_IN_TRAP),
NULL_TREE);
int i;
build_constructor (return_type, 0),
false);
else
- rhs = fold_convert_loc (loc, return_type, integer_zero_node);
+ rhs = build_zero_cst (return_type);
return require_complete_type (build2 (COMPOUND_EXPR, return_type,
trap, rhs));
return error_mark_node;
/* Check that the arguments to the function are valid. */
- check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
- TYPE_ARG_TYPES (fntype));
+ check_function_arguments (fntype, nargs, argarray);
if (name != NULL_TREE
&& !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
{
if (require_constant_value)
- result =
+ result =
fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
function, nargs, argarray);
else
}
return require_complete_type (result);
}
+
+/* Build a VEC_PERM_EXPR if V0, V1 and MASK are not error_mark_nodes
+ and have vector types, V0 has the same type as V1, and the number of
+ elements of V0, V1, MASK is the same.
+
+ In case V1 is a NULL_TREE it is assumed that __builtin_shuffle was
+ called with two arguments. In this case implementation passes the
+ first argument twice in order to share the same tree code. This fact
+ could enable the mask-values being twice the vector length. This is
+ an implementation accident and this semantics is not guaranteed to
+ the user. */
+tree
+c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask)
+{
+ tree ret;
+ bool wrap = true;
+ bool maybe_const = false;
+ bool two_arguments = false;
+
+ if (v1 == NULL_TREE)
+ {
+ two_arguments = true;
+ v1 = v0;
+ }
+
+ if (v0 == error_mark_node || v1 == error_mark_node
+ || mask == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_TYPE (mask)) != VECTOR_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (mask))) != INTEGER_TYPE)
+ {
+ error_at (loc, "__builtin_shuffle last argument must "
+ "be an integer vector");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (TREE_TYPE (v0)) != VECTOR_TYPE
+ || TREE_CODE (TREE_TYPE (v1)) != VECTOR_TYPE)
+ {
+ error_at (loc, "__builtin_shuffle arguments must be vectors");
+ return error_mark_node;
+ }
+
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (v0)) != TYPE_MAIN_VARIANT (TREE_TYPE (v1)))
+ {
+ error_at (loc, "__builtin_shuffle argument vectors must be of "
+ "the same type");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (v0))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask))
+ && TYPE_VECTOR_SUBPARTS (TREE_TYPE (v1))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask)))
+ {
+ error_at (loc, "__builtin_shuffle number of elements of the "
+ "argument vector(s) and the mask vector should "
+ "be the same");
+ return error_mark_node;
+ }
+
+ if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))))
+ != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask)))))
+ {
+ error_at (loc, "__builtin_shuffle argument vector(s) inner type "
+ "must have the same size as inner type of the mask");
+ return error_mark_node;
+ }
+
+ /* Avoid C_MAYBE_CONST_EXPRs inside VEC_PERM_EXPR. */
+ v0 = c_fully_fold (v0, false, &maybe_const);
+ wrap &= maybe_const;
+
+ if (two_arguments)
+ v1 = v0 = save_expr (v0);
+ else
+ {
+ v1 = c_fully_fold (v1, false, &maybe_const);
+ wrap &= maybe_const;
+ }
+
+ mask = c_fully_fold (mask, false, &maybe_const);
+ wrap &= maybe_const;
+
+ ret = build3_loc (loc, VEC_PERM_EXPR, TREE_TYPE (v0), v0, v1, mask);
+
+ if (!wrap)
+ ret = c_wrap_maybe_const (ret, true);
+
+ return ret;
+}
\f
/* Convert the argument expressions in the vector VALUES
to the types in the list TYPELIST.
{
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;
if (type == void_type_node)
{
- error ("too many arguments to function %qE", function);
+ if (selector)
+ error_at (input_location,
+ "too many arguments to method %qE", selector);
+ else
+ 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;
}
if (type_generic)
parmval = val;
else
- /* Convert `float' to `double'. */
- parmval = convert (double_type_node, val);
+ {
+ /* Convert `float' to `double'. */
+ if (warn_double_promotion && !c_inhibit_evaluation_warnings)
+ warning (OPT_Wdouble_promotion,
+ "implicit conversion from %qT to %qT when passing "
+ "argument to function",
+ valtype, double_type_node);
+ parmval = convert (double_type_node, val);
+ }
}
else if (excess_precision && !type_generic)
/* A "double" argument with excess precision being passed
parmval = default_conversion (val);
VEC_replace (tree, values, parmnum, parmval);
+ if (parmval == error_mark_node)
+ error_args = true;
if (typetail)
typetail = TREE_CHAIN (typetail);
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 parmnum;
+ return error_args ? -1 : (int) parmnum;
}
\f
/* This is the entry point used by the parser to build unary operators
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 (location, result.value);
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 (loc, 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 (loc, 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
in case restype is a short type. */
op0 = build_binary_op (loc,
- MINUS_EXPR, convert (restype, op0),
- convert (restype, op1), 0);
+ 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_at (loc, "arithmetic on pointer to an incomplete type");
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold_build2_loc (loc, 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);
}
\f
/* Construct and perhaps optimize a tree representation
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);
"wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = c_objc_common_truthvalue_conversion (location, arg);
+ if (int_operands)
+ {
+ arg = c_objc_common_truthvalue_conversion (location, xarg);
+ arg = remove_c_maybe_const_expr (arg);
+ }
+ else
+ arg = c_objc_common_truthvalue_conversion (location, 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))
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_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_loc (location,
- IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
- else
- ret = omit_one_operand_loc (location, TREE_TYPE (arg),
- integer_zero_node, arg);
+ ret = build_real_imag_expr (location, code, arg);
+ if (ret == error_mark_node)
+ return error_mark_node;
if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
eptype = TREE_TYPE (eptype);
goto return_build_unary_op;
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)))
+ /* Complain about anything that is not a true lvalue. In
+ Objective-C, skip this check for property_refs. */
+ if (!objc_is_property_ref (arg)
+ && !lvalue_or_else (location,
+ 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)
{
tree real, imag;
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C does not support %<++%> and %<--%> on complex types");
arg = stabilize_reference (arg);
|| 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_loc (location, sizetype, inc);
+ inc = convert_to_ptrofftype_loc (location, inc);
}
else if (FRACT_MODE_P (TYPE_MODE (argtype)))
{
inc = convert (argtype, inc);
}
+ /* If 'arg' is an Objective-C PROPERTY_REF expression, then we
+ need to ask Objective-C to build the increment or decrement
+ expression for it. */
+ if (objc_is_property_ref (arg))
+ return objc_build_incr_expr_for_property_ref (location, code,
+ arg, inc);
+
/* Report a read-only lvalue. */
if (TYPE_READONLY (argtype))
{
tree op0 = TREE_OPERAND (arg, 0);
if (!c_mark_addressable (op0))
return error_mark_node;
- return build_binary_op (location, PLUS_EXPR,
- (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
- ? array_to_pointer_conversion (location,
- op0)
- : op0),
- TREE_OPERAND (arg, 1), 1);
}
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
- && !lvalue_or_else (arg, lv_addressof))
+ && !lvalue_or_else (location, arg, lv_addressof))
return error_mark_node;
/* Move address operations inside C_MAYBE_CONST_EXPR to simplify
argtype = TREE_TYPE (arg);
/* If the lvalue is const or volatile, merge that into the type
- to which the address will point. Note that you can't get a
- restricted pointer by taking the address of something, so we
- only have to deal with `const' and `volatile' here. */
+ to which the address will point. This is only needed
+ for function types. */
if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
- && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
- argtype = c_build_type_variant (argtype,
- TREE_READONLY (arg),
- TREE_THIS_VOLATILE (arg));
+ && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
+ && TREE_CODE (argtype) == FUNCTION_TYPE)
+ {
+ int orig_quals = TYPE_QUALS (strip_array_types (argtype));
+ int quals = orig_quals;
+
+ if (TREE_READONLY (arg))
+ quals |= TYPE_QUAL_CONST;
+ if (TREE_THIS_VOLATILE (arg))
+ quals |= TYPE_QUAL_VOLATILE;
+
+ argtype = c_build_qualified_type (argtype, quals);
+ }
if (!c_mark_addressable (arg))
return error_mark_node;
if (val && TREE_CODE (val) == INDIRECT_REF
&& TREE_CONSTANT (TREE_OPERAND (val, 0)))
{
- tree op0 = fold_convert_loc (location, sizetype,
- fold_offsetof (arg, val)), op1;
-
- op1 = fold_convert_loc (location, argtype, TREE_OPERAND (val, 0));
- ret = fold_build2_loc (location, POINTER_PLUS_EXPR, argtype, op1, op0);
+ ret = fold_convert_loc (location, argtype, fold_offsetof_1 (arg));
goto return_build_unary_op;
}
}
}
\f
-/* Give an error for storing in something that is 'const'. */
-
-static void
-readonly_error (tree arg, enum lvalue_use use)
-{
- gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
- || use == lv_asm);
- /* Using this macro rather than (for example) arrays of messages
- ensures that all the format strings are checked at compile
- time. */
-#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A) \
- : (use == lv_increment ? (I) \
- : (use == lv_decrement ? (D) : (AS))))
- if (TREE_CODE (arg) == COMPONENT_REF)
- {
- if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- readonly_error (TREE_OPERAND (arg, 0), use);
- else
- error (READONLY_MSG (G_("assignment of read-only member %qD"),
- G_("increment of read-only member %qD"),
- G_("decrement of read-only member %qD"),
- G_("read-only member %qD used as %<asm%> output")),
- TREE_OPERAND (arg, 1));
- }
- else if (TREE_CODE (arg) == VAR_DECL)
- error (READONLY_MSG (G_("assignment of read-only variable %qD"),
- G_("increment of read-only variable %qD"),
- G_("decrement of read-only variable %qD"),
- G_("read-only variable %qD used as %<asm%> output")),
- arg);
- else
- error (READONLY_MSG (G_("assignment of read-only location %qE"),
- G_("increment of read-only location %qE"),
- G_("decrement of read-only location %qE"),
- G_("read-only location %qE used as %<asm%> output")),
- arg);
-}
-
/* Give a warning for storing in something that is read-only in GCC
terms but not const in ISO C terms. */
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. USE says
- how the lvalue is being used and so selects the error message. */
+ how the lvalue is being used and so selects the error message.
+ LOCATION is the location at which any error should be reported. */
static int
-lvalue_or_else (const_tree ref, enum lvalue_use use)
+lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
if (!win)
- lvalue_error (use);
+ lvalue_error (loc, use);
return win;
}
}
}
\f
+/* 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
enum tree_code code1;
enum tree_code code2;
tree result_type = NULL;
- tree ep_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)
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
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE
|| code2 == COMPLEX_TYPE))
{
- ep_result_type = c_common_type (type1, type2);
+ semantic_result_type = c_common_type (type1, type2);
if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
{
op1 = TREE_OPERAND (op1, 0);
|| code2 == COMPLEX_TYPE))
{
result_type = c_common_type (type1, type2);
+ do_warn_double_promotion (result_type, type1, type2,
+ "implicit conversion from %qT to %qT to "
+ "match other result of conditional",
+ colon_loc);
/* If -Wsign-compare, warn here if type1 and type2 have
different signedness. We'll promote the signed to unsigned
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
+ 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)
result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
TREE_TYPE (type1)));
}
+ /* Objective-C pointer comparisons are a bit more lenient. */
+ else if (objc_have_common_type (type1, type2, -3, NULL_TREE))
+ result_type = objc_common_type (type1, type2);
else
{
- if (!objc_ok)
- pedwarn (colon_loc, 0,
- "pointer type mismatch in conditional expression");
- result_type = build_pointer_type (void_type_node);
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+
+ pedwarn (colon_loc, 0,
+ "pointer type mismatch in conditional expression");
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
TYPE_READONLY (type1) || TYPE_READONLY (type2),
TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2));
- if (result_type != type1)
- op1 = convert_and_check (result_type, op1);
- if (result_type != type2)
- op2 = convert_and_check (result_type, op2);
+ op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
+ op2 = ep_convert_and_check (result_type, op2, semantic_result_type);
if (ifexp_bcp && ifexp == truthvalue_true_node)
{
ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2);
else
{
+ if (int_operands)
+ {
+ op1 = remove_c_maybe_const_expr (op1);
+ op2 = remove_c_maybe_const_expr (op2);
+ }
ret = build3 (COND_EXPR, result_type, ifexp, op1, op2);
if (int_operands)
ret = note_integer_operands (ret);
}
- if (ep_result_type)
- ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
+ if (semantic_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
protected_set_expr_location (ret, colon_loc);
return ret;
&& CONVERT_EXPR_P (TREE_OPERAND (expr1, 1)))
; /* (void) a, (void) b, c */
else
- warning_at (loc, OPT_Wunused_value,
+ warning_at (loc, OPT_Wunused_value,
"left-hand operand of comma expression has no effect");
}
}
/* 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. */
+ cast. Both TYPE and OTYPE are pointer types. LOC is the location
+ of the cast. -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)
+handle_warn_cast_qual (location_t loc, tree type, tree otype)
{
tree in_type = type;
tree in_otype = otype;
taken away. */
if (TREE_CODE (in_otype) == FUNCTION_TYPE
&& TREE_CODE (in_type) == FUNCTION_TYPE)
- added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+ added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
else
- discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+ 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");
+ warning_at (loc, OPT_Wcast_qual,
+ "cast adds %q#v qualifier to function type", added);
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");
+ warning_at (loc, OPT_Wcast_qual,
+ "cast discards %q#v qualifier from pointer target type",
+ discarded);
if (added || discarded)
return;
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"));
+ warning_at (loc, OPT_Wcast_qual,
+ "to be safe all intermediate pointers in cast from "
+ "%qT to %qT must be %<const%> qualified",
+ otype, type);
break;
}
if (is_const)
while (TREE_CODE (in_type) == POINTER_TYPE);
}
-/* Build an expression representing a cast to type TYPE of expression EXPR.
+/* 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
{
if (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
- pedwarn (loc, OPT_pedantic,
+ pedwarn (loc, OPT_pedantic,
"ISO C forbids casting nonscalar to the same type");
}
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (TREE_TYPE (field) != error_mark_node
&& comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
TYPE_MAIN_VARIANT (TREE_TYPE (value))))
if (field)
{
tree t;
+ bool maybe_const = true;
pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type");
- t = digest_init (loc, type,
- build_constructor_single (type, field, value),
+ 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;
if (warn_cast_qual
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE)
- handle_warn_cast_qual (type, otype);
+ handle_warn_cast_qual (loc, 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))
+ {
+ 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;
+
+ if (!addr_space_superset (as_to, as_from, &as_common))
+ {
+ 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));
+
+ 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));
+
+ 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. */
if (STRICT_ALIGNMENT
ret = build_c_cast (loc, type, expr);
if (type_expr)
{
+ bool inner_expr_const = true;
+ ret = c_fully_fold (ret, require_constant_value, &inner_expr_const);
ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret);
- C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const;
+ C_MAYBE_CONST_EXPR_NON_CONST (ret) = !(type_expr_const
+ && inner_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)
+ /* C++ does not permits types to be defined in a cast, but it
+ allows references to incomplete types. */
+ if (warn_cxx_compat && type_name->specs->typespec_kind == ctsk_tagdef)
warning_at (loc, OPT_Wc___compat,
"defining a type in a cast is invalid in C++");
tree
build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
- enum tree_code modifycode,
+ enum tree_code modifycode,
location_t rhs_loc, tree rhs, tree rhs_origtype)
{
tree result;
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- if (!lvalue_or_else (lhs, lv_assign))
+ /* For ObjC properties, defer this check. */
+ if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
return error_mark_node;
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
rhs_origtype = NULL_TREE;
}
+ if (c_dialect_objc ())
+ {
+ /* Check if we are modifying an Objective-C property reference;
+ if so, we need to generate setter calls. */
+ result = objc_maybe_build_modify_expr (lhs, newrhs);
+ if (result)
+ return result;
+
+ /* Else, do the check that we postponed for Objective-C. */
+ if (!lvalue_or_else (location, lhs, lv_assign))
+ return error_mark_node;
+ }
+
/* Give an error for storing in something that is 'const'. */
if (TYPE_READONLY (lhstype)
return result;
}
\f
+/* Return whether STRUCT_TYPE has an anonymous field with type TYPE.
+ This is used to implement -fplan9-extensions. */
+
+static bool
+find_anonymous_field_with_type (tree struct_type, tree type)
+{
+ tree field;
+ bool found;
+
+ gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE
+ || TREE_CODE (struct_type) == UNION_TYPE);
+ found = false;
+ for (field = TYPE_FIELDS (struct_type);
+ field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) == NULL
+ && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ {
+ if (found)
+ return false;
+ found = true;
+ }
+ else if (DECL_NAME (field) == NULL
+ && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && find_anonymous_field_with_type (TREE_TYPE (field), type))
+ {
+ if (found)
+ return false;
+ found = true;
+ }
+ }
+ return found;
+}
+
+/* RHS is an expression whose type is pointer to struct. If there is
+ an anonymous field in RHS with type TYPE, then return a pointer to
+ that field in RHS. This is used with -fplan9-extensions. This
+ returns NULL if no conversion could be found. */
+
+static tree
+convert_to_anonymous_field (location_t location, tree type, tree rhs)
+{
+ tree rhs_struct_type, lhs_main_type;
+ tree field, found_field;
+ bool found_sub_field;
+ tree ret;
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs)));
+ rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs));
+ gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE
+ || TREE_CODE (rhs_struct_type) == UNION_TYPE);
+
+ gcc_assert (POINTER_TYPE_P (type));
+ lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+
+ found_field = NULL_TREE;
+ found_sub_field = false;
+ for (field = TYPE_FIELDS (rhs_struct_type);
+ field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) != NULL_TREE
+ || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
+ && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
+ continue;
+ if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ {
+ if (found_field != NULL_TREE)
+ return NULL_TREE;
+ found_field = field;
+ }
+ else if (find_anonymous_field_with_type (TREE_TYPE (field),
+ lhs_main_type))
+ {
+ if (found_field != NULL_TREE)
+ return NULL_TREE;
+ found_field = field;
+ found_sub_field = true;
+ }
+ }
+
+ if (found_field == NULL_TREE)
+ return NULL_TREE;
+
+ ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field),
+ build_fold_indirect_ref (rhs), found_field,
+ NULL_TREE);
+ ret = build_fold_addr_expr_loc (location, ret);
+
+ if (found_sub_field)
+ {
+ ret = convert_to_anonymous_field (location, type, ret);
+ gcc_assert (ret != NULL_TREE);
+ }
+
+ return ret;
+}
+
/* 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
pedwarn (LOCATION, OPT, AS); \
break; \
case ic_init: \
- pedwarn (LOCATION, OPT, IN); \
+ pedwarn_init (LOCATION, OPT, IN); \
break; \
case ic_return: \
pedwarn (LOCATION, OPT, RE); \
} \
} while (0)
+ /* This macro is used to emit diagnostics to ensure that all format
+ strings are complete sentences, visible to gettext and checked at
+ compile time. It is the same as WARN_FOR_ASSIGNMENT but with an
+ extra parameter to enumerate qualifiers. */
+
+#define WARN_FOR_QUALIFIERS(LOCATION, OPT, AR, AS, IN, RE, QUALS) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ if (pedwarn (LOCATION, OPT, AR, parmnum, rname, QUALS)) \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_assign: \
+ pedwarn (LOCATION, OPT, AS, QUALS); \
+ break; \
+ case ic_init: \
+ pedwarn (LOCATION, OPT, IN, QUALS); \
+ break; \
+ case ic_return: \
+ pedwarn (LOCATION, OPT, RE, QUALS); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } while (0)
+
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
rhs = TREE_OPERAND (rhs, 0);
{
tree ret;
bool save = in_late_binary_op;
- if (codel == BOOLEAN_TYPE)
+ if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
in_late_binary_op = true;
ret = convert_and_check (type, orig_rhs);
- if (codel == BOOLEAN_TYPE)
+ if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
in_late_binary_op = save;
return ret;
}
&& 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;
- for (memb = TYPE_FIELDS (type); memb ; memb = TREE_CHAIN (memb))
+ for (memb = TYPE_FIELDS (type); memb ; memb = DECL_CHAIN (memb))
{
tree memb_type = TREE_TYPE (memb);
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 (location, 0,
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE "
- "makes qualified function "
+ "makes %q#v qualified function "
"pointer from unqualified"),
- G_("assignment makes qualified "
+ G_("assignment makes %q#v qualified "
"function pointer from "
"unqualified"),
- G_("initialization makes qualified "
+ G_("initialization makes %q#v qualified "
"function pointer from "
"unqualified"),
- G_("return makes qualified function "
- "pointer from unqualified"));
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
- else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (location, 0,
+ else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- G_("assignment discards qualifiers "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
"from pointer target type"),
- G_("initialization discards qualifiers "
+ G_("initialization discards %qv qualifier "
"from pointer target type"),
- G_("return discards qualifiers from "
- "pointer target type"));
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
memb = marginal_memb;
}
if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C prohibits argument conversion to union type");
rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs);
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);
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
+ /* The Plan 9 compiler permits a pointer to a struct to be
+ automatically converted into a pointer to an anonymous field
+ within the struct. */
+ if (flag_plan9_extensions
+ && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE)
+ && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE)
+ && mvl != mvr)
+ {
+ tree new_rhs = convert_to_anonymous_field (location, type, rhs);
+ if (new_rhs != NULL_TREE)
+ {
+ rhs = new_rhs;
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ ttr = TREE_TYPE (rhstype);
+ mvr = TYPE_MAIN_VARIANT (ttr);
+ }
+ }
+
/* C++ does not allow the implicit conversion void* -> T*. However,
for the purpose of reducing the number of false positives, we
tolerate the special case of
"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. */
if (warn_missing_format_attribute
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 (location, 0,
- G_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- G_("assignment discards qualifiers "
- "from pointer target type"),
- G_("initialization discards qualifiers "
- "from pointer target type"),
- G_("return discards qualifiers from "
- "pointer target type"));
+ WARN_FOR_QUALIFIERS (location, 0,
+ G_("passing argument %d of %qE discards "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
+ "from pointer target type"),
+ G_("initialization discards %qv qualifier "
+ "from pointer target type"),
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
}
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
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 (location, 0,
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE makes "
- "qualified function pointer "
+ "%q#v qualified function pointer "
"from unqualified"),
- G_("assignment makes qualified function "
+ G_("assignment makes %q#v qualified function "
"pointer from unqualified"),
- G_("initialization makes qualified "
+ G_("initialization makes %q#v qualified "
"function pointer from unqualified"),
- G_("return makes qualified function "
- "pointer from unqualified"));
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
}
else
/* 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. */
/* For int foo[] = (int [3]){1}; we need to set array size
now since later on array initializer will be just the
brace enclosed list of the compound literal. */
+ tree etype = strip_array_types (TREE_TYPE (decl));
type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
- TREE_TYPE (decl) = type;
TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl));
layout_type (type);
layout_decl (cldecl, 0);
+ TREE_TYPE (decl)
+ = c_build_qualified_type (type, TYPE_QUALS (etype));
}
}
}
}
/* Issue an error message for a bad initializer component.
- MSGID identifies the message.
+ GMSGID identifies the message.
The component name is taken from the spelling stack. */
void
-error_init (const char *msgid)
+error_init (const char *gmsgid)
{
char *ofwhat;
- error ("%s", _(msgid));
+ /* The gmsgid may be a format string with %< and %>. */
+ error (gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
error ("(near initialization for %qs)", ofwhat);
/* Issue a pedantic warning for a bad initializer component. OPT is
the option OPT_* (from options.h) controlling this warning or 0 if
- it is unconditionally given. MSGID identifies the message. The
+ it is unconditionally given. GMSGID identifies the message. The
component name is taken from the spelling stack. */
void
-pedwarn_init (location_t location, int opt, const char *msgid)
+pedwarn_init (location_t location, int opt, const char *gmsgid)
{
char *ofwhat;
- pedwarn (location, opt, "%s", _(msgid));
+ /* The gmsgid may be a format string with %< and %>. */
+ pedwarn (location, opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
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
+ controls this warning. GMSGID identifies the message. The
component name is taken from the spelling stack. */
static void
-warning_init (int opt, const char *msgid)
+warning_init (int opt, const char *gmsgid)
{
char *ofwhat;
- warning (opt, "%s", _(msgid));
+ /* The gmsgid may be a format string with %< and %>. */
+ warning (opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
warning (opt, "(near initialization for %qs)", ofwhat);
&& 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");
}
/* Skip any nameless bit fields at the beginning. */
while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
- constructor_fields = TREE_CHAIN (constructor_fields);
+ constructor_fields = DECL_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = bitsize_zero_node;
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_cst (NULL_TREE, -1);
+ constructor_max_index = integer_minus_one_node;
/* constructor_max_index needs to be an INTEGER_CST. Attempts
to initialize VLAs will cause a proper error; avoid tree
checking errors as well by setting a safe value. */
if (constructor_max_index
&& TREE_CODE (constructor_max_index) != INTEGER_CST)
- constructor_max_index = build_int_cst (NULL_TREE, -1);
+ constructor_max_index = integer_minus_one_node;
constructor_index
= convert (bitsizetype,
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
+ bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
constructor_index = bitsize_zero_node;
constructor_unfilled_index = constructor_index;
}
IMPLICIT is 1 (or 2 if the push is because of designator list). */
void
-push_init_level (int implicit)
+push_init_level (int implicit, struct obstack * braced_init_obstack)
{
struct constructor_stack *p;
tree value = NULL_TREE;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& constructor_max_index
&& tree_int_cst_lt (constructor_max_index,
constructor_index))
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else
break;
}
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields)
- value = find_init_member (constructor_fields);
+ value = find_init_member (constructor_fields, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- value = find_init_member (constructor_index);
+ value = find_init_member (constructor_index, braced_init_obstack);
}
p = XNEW (struct constructor_stack);
if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == ARRAY_TYPE))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
}
if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
/* Skip any nameless bit fields at the beginning. */
while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
- constructor_fields = TREE_CHAIN (constructor_fields);
+ constructor_fields = DECL_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = bitsize_zero_node;
{
/* Vectors are like simple fixed-size arrays. */
constructor_max_index =
- build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
- constructor_index = convert (bitsizetype, integer_zero_node);
+ bitsize_int (TYPE_VECTOR_SUBPARTS (constructor_type) - 1);
+ constructor_index = bitsize_int (0);
constructor_unfilled_index = constructor_index;
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
/* Detect non-empty initializations of zero-length arrays. */
if (constructor_max_index == NULL_TREE
&& TYPE_SIZE (constructor_type))
- constructor_max_index = build_int_cst (NULL_TREE, -1);
+ constructor_max_index = integer_minus_one_node;
/* constructor_max_index needs to be an INTEGER_CST. Attempts
to initialize VLAs will cause a proper error; avoid tree
checking errors as well by setting a safe value. */
if (constructor_max_index
&& TREE_CODE (constructor_max_index) != INTEGER_CST)
- constructor_max_index = build_int_cst (NULL_TREE, -1);
+ constructor_max_index = integer_minus_one_node;
constructor_index
= convert (bitsizetype,
/* We need to split the char/wchar array into individual
characters, so that we don't have to special case it
everywhere. */
- set_nonincremental_init_from_string (value);
+ set_nonincremental_init_from_string (value, braced_init_obstack);
}
}
else
Otherwise, return a CONSTRUCTOR expression as the value. */
struct c_expr
-pop_init_level (int implicit)
+pop_init_level (int implicit, struct obstack * braced_init_obstack)
{
struct constructor_stack *p;
struct c_expr ret;
/* When we come to an explicit close brace,
pop any inner levels that didn't have explicit braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1), true);
-
+ {
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
+ }
gcc_assert (!constructor_range_stack);
}
/* Now output all pending elements. */
constructor_incremental = 1;
- output_pending_init_elements (1);
+ output_pending_init_elements (1, braced_init_obstack);
p = constructor_stack;
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
Discard the initializer so that we do not die later. */
- if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+ if (DECL_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
}
&& TREE_CODE (constructor_type) == RECORD_TYPE
&& constructor_unfilled_fields)
{
+ bool constructor_zeroinit =
+ (VEC_length (constructor_elt, constructor_elements) == 1
+ && integer_zerop
+ (VEC_index (constructor_elt, constructor_elements, 0)->value));
+
/* Do not warn for flexible array members or zero-length arrays. */
while (constructor_unfilled_fields
&& (!DECL_SIZE (constructor_unfilled_fields)
|| integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
- constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
-
- /* Do not warn if this level of the initializer uses member
- designators; it is likely to be deliberate. */
- if (constructor_unfilled_fields && !constructor_designated)
+ constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields);
+
+ if (constructor_unfilled_fields
+ /* Do not warn if this level of the initializer uses member
+ designators; it is likely to be deliberate. */
+ && !constructor_designated
+ /* Do not warn about initializing with ` = {0}'. */
+ && !constructor_zeroinit)
{
push_member_name (constructor_unfilled_fields);
warning_init (OPT_Wmissing_field_initializers,
ARRAY argument is nonzero for array ranges. Returns zero for success. */
static int
-set_designator (int array)
+set_designator (int array, struct obstack * braced_init_obstack)
{
tree subtype;
enum tree_code subcode;
/* Designator list starts at the level of closest explicit
braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1), true);
+ {
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
+ }
constructor_designated = 1;
return 0;
}
}
constructor_designated = 1;
- push_init_level (2);
+ push_init_level (2, braced_init_obstack);
return 0;
}
NULL_TREE if there is no range designator at this level. */
static void
-push_range_stack (tree range_end)
+push_range_stack (tree range_end, struct obstack * braced_init_obstack)
{
struct constructor_range_stack *p;
- p = GGC_NEW (struct constructor_range_stack);
+ p = (struct constructor_range_stack *)
+ obstack_alloc (braced_init_obstack,
+ sizeof (struct constructor_range_stack));
p->prev = constructor_range_stack;
p->next = 0;
p->fields = constructor_fields;
of indices, running from FIRST through LAST. */
void
-set_init_index (tree first, tree last)
+set_init_index (tree first, tree last,
+ struct obstack * braced_init_obstack)
{
- if (set_designator (1))
+ if (set_designator (1, braced_init_obstack))
return;
designator_erroneous = 1;
designator_depth++;
designator_erroneous = 0;
if (constructor_range_stack || last)
- push_range_stack (last);
+ push_range_stack (last, braced_init_obstack);
}
}
/* Within a struct initializer, specify the next field to be initialized. */
void
-set_init_label (tree fieldname)
+set_init_label (tree fieldname, struct obstack * braced_init_obstack)
{
- tree tail;
+ tree field;
- if (set_designator (0))
+ if (set_designator (0, braced_init_obstack))
return;
designator_erroneous = 1;
return;
}
- for (tail = TYPE_FIELDS (constructor_type); tail;
- tail = TREE_CHAIN (tail))
- {
- if (DECL_NAME (tail) == fieldname)
- break;
- }
+ field = lookup_field (constructor_type, fieldname);
- if (tail == 0)
+ if (field == 0)
error ("unknown field %qE specified in initializer", fieldname);
else
- {
- constructor_fields = tail;
- designator_depth++;
- designator_erroneous = 0;
- if (constructor_range_stack)
- push_range_stack (NULL_TREE);
- }
+ do
+ {
+ constructor_fields = TREE_VALUE (field);
+ designator_depth++;
+ designator_erroneous = 0;
+ if (constructor_range_stack)
+ push_range_stack (NULL_TREE, braced_init_obstack);
+ field = TREE_CHAIN (field);
+ if (field)
+ {
+ if (set_designator (0, braced_init_obstack))
+ return;
+ }
+ }
+ while (field != NULL_TREE);
}
\f
/* Add a new initializer to the tree of pending initializers. PURPOSE
existing initializer. */
static void
-add_pending_init (tree purpose, tree value, tree origtype, bool implicit)
+add_pending_init (tree purpose, tree value, tree origtype, bool implicit,
+ struct obstack * braced_init_obstack)
{
struct init_node *p, **q, *r;
}
}
- r = GGC_NEW (struct init_node);
+ r = (struct init_node *) obstack_alloc (braced_init_obstack,
+ sizeof (struct init_node));
r->purpose = purpose;
r->value = value;
r->origtype = origtype;
/* Build AVL tree from a sorted chain. */
static void
-set_nonincremental_init (void)
+set_nonincremental_init (struct obstack * braced_init_obstack)
{
unsigned HOST_WIDE_INT ix;
tree index, value;
return;
FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
- add_pending_init (index, value, NULL_TREE, false);
+ {
+ add_pending_init (index, value, NULL_TREE, true,
+ braced_init_obstack);
+ }
constructor_elements = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
/* Build AVL tree from a string constant. */
static void
-set_nonincremental_init_from_string (tree str)
+set_nonincremental_init_from_string (tree str,
+ struct obstack * braced_init_obstack)
{
tree value, purpose, type;
HOST_WIDE_INT val[2];
}
value = build_int_cst_wide (type, val[1], val[0]);
- add_pending_init (purpose, value, NULL_TREE, false);
+ add_pending_init (purpose, value, NULL_TREE, true,
+ braced_init_obstack);
}
constructor_incremental = 0;
not initialized yet. */
static tree
-find_init_member (tree field)
+find_init_member (tree field, struct obstack * braced_init_obstack)
{
struct init_node *p;
{
if (constructor_incremental
&& tree_int_cst_lt (field, constructor_unfilled_index))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
p = constructor_pending_elts;
while (p)
&& (!constructor_unfilled_fields
|| tree_int_cst_lt (bitpos,
bit_position (constructor_unfilled_fields))))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
p = constructor_pending_elts;
while (p)
static void
output_init_element (tree value, tree origtype, bool strict_string, tree type,
- tree field, int pending, bool implicit)
+ tree field, int pending, bool implicit,
+ struct obstack * braced_init_obstack)
{
tree semantic_type = NULL_TREE;
constructor_elt *celt;
|| (COMPLETE_TYPE_P (TREE_TYPE (field))
&& integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
&& (TREE_CODE (constructor_type) == ARRAY_TYPE
- || TREE_CHAIN (field)))))
+ || DECL_CHAIN (field)))))
return;
if (semantic_type)
{
if (constructor_incremental
&& tree_int_cst_lt (field, constructor_unfilled_index))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
- add_pending_init (field, value, origtype, implicit);
+ add_pending_init (field, value, origtype, implicit,
+ braced_init_obstack);
return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
if (constructor_incremental)
{
if (!constructor_unfilled_fields)
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
else
{
tree bitpos, unfillpos;
unfillpos = bit_position (constructor_unfilled_fields);
if (tree_int_cst_lt (bitpos, unfillpos))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
}
}
- add_pending_init (field, value, origtype, implicit);
+ add_pending_init (field, value, origtype, implicit,
+ braced_init_obstack);
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
else if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
constructor_unfilled_fields
- = TREE_CHAIN (constructor_unfilled_fields);
+ = DECL_CHAIN (constructor_unfilled_fields);
/* Skip any nameless bit fields. */
while (constructor_unfilled_fields != 0
&& DECL_C_BIT_FIELD (constructor_unfilled_fields)
&& DECL_NAME (constructor_unfilled_fields) == 0)
constructor_unfilled_fields =
- TREE_CHAIN (constructor_unfilled_fields);
+ DECL_CHAIN (constructor_unfilled_fields);
}
else if (TREE_CODE (constructor_type) == UNION_TYPE)
constructor_unfilled_fields = 0;
/* Now output any pending elements which have become next. */
if (pending)
- output_pending_init_elements (0);
+ output_pending_init_elements (0, braced_init_obstack);
}
/* Output any pending elements which have become next.
If ALL is 1, we output space as necessary so that
we can output all the pending elements. */
-
static void
-output_pending_init_elements (int all)
+output_pending_init_elements (int all, struct obstack * braced_init_obstack)
{
struct init_node *elt = constructor_pending_elts;
tree next;
constructor_unfilled_index))
output_init_element (elt->value, elt->origtype, true,
TREE_TYPE (constructor_type),
- constructor_unfilled_index, 0, false);
+ constructor_unfilled_index, 0, false,
+ braced_init_obstack);
else if (tree_int_cst_lt (constructor_unfilled_index,
elt->purpose))
{
constructor_unfilled_fields = elt->purpose;
output_init_element (elt->value, elt->origtype, true,
TREE_TYPE (elt->purpose),
- elt->purpose, 0, false);
+ elt->purpose, 0, false,
+ braced_init_obstack);
}
else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
{
existing initializer. */
void
-process_init_element (struct c_expr value, bool implicit)
+process_init_element (struct c_expr value, bool implicit,
+ struct obstack * braced_init_obstack)
{
tree orig_value = value.value;
int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
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)))
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else
break;
}
if (fieldcode == ARRAY_TYPE
&& !require_constant_value
&& TYPE_SIZE (fieldtype) == NULL_TREE
- && TREE_CHAIN (constructor_fields) == NULL_TREE)
+ && DECL_CHAIN (constructor_fields) == NULL_TREE)
{
error_init ("non-static initialization of a flexible array member");
break;
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_member_name (constructor_fields);
output_init_element (value.value, value.original_type,
strict_string, fieldtype,
- constructor_fields, 1, implicit);
+ constructor_fields, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
it isn't now, so update. */
if (constructor_unfilled_fields == constructor_fields)
{
- constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+ constructor_unfilled_fields = DECL_CHAIN (constructor_fields);
/* Skip any nameless bit fields. */
while (constructor_unfilled_fields != 0
&& DECL_C_BIT_FIELD (constructor_unfilled_fields)
&& DECL_NAME (constructor_unfilled_fields) == 0)
constructor_unfilled_fields =
- TREE_CHAIN (constructor_unfilled_fields);
+ DECL_CHAIN (constructor_unfilled_fields);
}
}
- constructor_fields = TREE_CHAIN (constructor_fields);
+ constructor_fields = DECL_CHAIN (constructor_fields);
/* Skip any nameless bit fields at the beginning. */
while (constructor_fields != 0
&& DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
- constructor_fields = TREE_CHAIN (constructor_fields);
+ constructor_fields = DECL_CHAIN (constructor_fields);
}
else if (TREE_CODE (constructor_type) == UNION_TYPE)
{
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_member_name (constructor_fields);
output_init_element (value.value, value.original_type,
strict_string, fieldtype,
- constructor_fields, 1, implicit);
+ constructor_fields, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
directly output as a constructor. */
{
constructor_bit_index = DECL_SIZE (constructor_fields);
- constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+ constructor_unfilled_fields = DECL_CHAIN (constructor_fields);
}
constructor_fields = 0;
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
|| eltcode == UNION_TYPE || eltcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_array_bounds (tree_low_cst (constructor_index, 1));
output_init_element (value.value, value.original_type,
strict_string, elttype,
- constructor_index, 1, implicit);
+ constructor_index, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
elttype = TYPE_MAIN_VARIANT (constructor_type);
output_init_element (value.value, value.original_type,
strict_string, elttype,
- constructor_index, 1, implicit);
+ constructor_index, 1, implicit,
+ braced_init_obstack);
}
constructor_index
if (value.value)
output_init_element (value.value, value.original_type,
strict_string, constructor_type,
- NULL_TREE, 1, implicit);
+ NULL_TREE, 1, implicit,
+ braced_init_obstack);
constructor_fields = 0;
}
while (constructor_stack != range_stack->stack)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1,
+ braced_init_obstack),
+ true, braced_init_obstack);
}
for (p = range_stack;
!p->range_end || tree_int_cst_equal (p->index, p->range_end);
p = p->prev)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
}
p->index = size_binop_loc (input_location,
p = p->next;
if (!p)
break;
- push_init_level (2);
+ push_init_level (2, braced_init_obstack);
p->stack = constructor_stack;
if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
p->index = p->range_start;
get an error. Gross, but ... */
STRIP_NOPS (output);
- if (!lvalue_or_else (output, lv_asm))
+ if (!lvalue_or_else (loc, output, lv_asm))
output = error_mark_node;
if (output != error_mark_node
mark it addressable. */
if (!allows_reg && !c_mark_addressable (output))
output = error_mark_node;
+ if (!(!allows_reg && allows_mem)
+ && output != error_mark_node
+ && VOID_TYPE_P (TREE_TYPE (output)))
+ {
+ error_at (loc, "invalid use of void expression");
+ output = error_mark_node;
+ }
}
else
output = error_mark_node;
STRIP_NOPS (input);
if (!c_mark_addressable (input))
input = error_mark_node;
- }
+ }
+ else if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
+ {
+ error_at (loc, "invalid use of void expression");
+ input = error_mark_node;
+ }
}
else
input = error_mark_node;
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
{
- pedwarn_c99 (loc, 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;
{
current_function_returns_null = 1;
if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn (loc, 0,
+ pedwarn (loc, 0,
"%<return%> with a value, in function returning void");
- else
+ else
pedwarn (loc, OPT_pedantic, "ISO C forbids "
"%<return%> with expression, in function returning void");
}
npc, NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
tree inner;
+ bool save;
current_function_returns_value = 1;
if (t == error_mark_node)
return NULL_TREE;
+ save = in_late_binary_op;
+ if (TREE_CODE (TREE_TYPE (res)) == BOOLEAN_TYPE
+ || TREE_CODE (TREE_TYPE (res)) == COMPLEX_TYPE)
+ in_late_binary_op = true;
inner = t = convert (TREE_TYPE (res), t);
+ in_late_binary_op = save;
/* Strip any conversions, additions, and subtractions, and see if
we are returning the address of a local variable. Warn if so. */
tree
c_process_expr_stmt (location_t loc, tree expr)
{
+ tree exprv;
+
if (!expr)
return NULL_TREE;
&& warn_unused_value)
emit_side_effect_warnings (loc, expr);
+ exprv = expr;
+ while (TREE_CODE (exprv) == COMPOUND_EXPR)
+ exprv = TREE_OPERAND (exprv, 1);
+ while (CONVERT_EXPR_P (exprv))
+ exprv = TREE_OPERAND (exprv, 0);
+ if (DECL_P (exprv)
+ || handled_component_p (exprv)
+ || TREE_CODE (exprv) == ADDR_EXPR)
+ mark_exp_read (exprv);
+
/* 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))
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. */
do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular,
STATEMENT_LISTs merge, and thus we can lose track of what statement
was really last. */
- if (cur_stmt_list
+ if (building_stmt_list_p ()
&& STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
&& TREE_CODE (stmt) != BIND_EXPR)
{
TREE_OPERAND (stmt, 0) = list;
STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
}
+
+/* Convert scalar to vector for the range of operations. */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+ tree type0 = TREE_TYPE (op0);
+ tree type1 = TREE_TYPE (op1);
+ bool integer_only_op = false;
+ enum stv_conv ret = stv_firstarg;
+
+ gcc_assert (TREE_CODE (type0) == VECTOR_TYPE
+ || TREE_CODE (type1) == VECTOR_TYPE);
+ switch (code)
+ {
+ case RSHIFT_EXPR:
+ case LSHIFT_EXPR:
+ if (TREE_CODE (type0) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ else
+ return stv_firstarg;
+ }
+ break;
+
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ integer_only_op = true;
+ /* ... fall through ... */
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case RDIV_EXPR:
+ if (TREE_CODE (type0) == VECTOR_TYPE)
+ {
+ tree tmp;
+ ret = stv_secondarg;
+ /* Swap TYPE0 with TYPE1 and OP0 with OP1 */
+ tmp = type0; type0 = type1; type1 = tmp;
+ tmp = op0; op0 = op1; op1 = tmp;
+ }
+
+ if (TREE_CODE (type0) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ return ret;
+ }
+ else if (!integer_only_op
+ /* Allow integer --> real conversion if safe. */
+ && (TREE_CODE (type0) == REAL_TYPE
+ || TREE_CODE (type0) == INTEGER_TYPE)
+ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+ {
+ if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+ {
+ error_at (loc, "conversion of scalar to vector "
+ "involves truncation");
+ return stv_error;
+ }
+ return ret;
+ }
+ default:
+ break;
+ }
+
+ return stv_nothing;
+}
\f
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
/* When the computation is in excess precision, the type of the
final EXCESS_PRECISION_EXPR. */
- tree real_result_type = NULL;
+ tree semantic_result_type = NULL;
/* Nonzero means operands have already been type-converted
in whatever way is necessary.
precision. */
bool may_need_excess_precision;
+ /* True means this is a boolean operation that converts both its
+ operands to truth-values. */
+ bool boolean_op = false;
+
if (location == UNKNOWN_LOCATION)
location = input_location;
else
int_const = int_const_or_overflow = false;
- if (convert_p)
+ /* Do not apply default conversion in mixed vector/scalar expression. */
+ if (convert_p
+ && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
+ != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
{
op0 = default_conversion (op0);
op1 = default_conversion (op1);
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+ /* In case when one of the operands of the binary operation is
+ a vector and another is a scalar -- convert scalar to vector. */
+ if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+ {
+ enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+
+ switch (convert_flag)
+ {
+ case stv_error:
+ return error_mark_node;
+ case stv_firstarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op0, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type1), sc);
+ op0 = build_vector_from_val (type1, sc);
+ if (!maybe_const)
+ op0 = c_wrap_maybe_const (op0, true);
+ orig_type0 = type0 = TREE_TYPE (op0);
+ code0 = TREE_CODE (type0);
+ converted = 1;
+ break;
+ }
+ case stv_secondarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op1, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type0), sc);
+ op1 = build_vector_from_val (type0, sc);
+ if (!maybe_const)
+ op1 = c_wrap_maybe_const (op1, true);
+ orig_type1 = type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ converted = 1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
switch (code)
{
case PLUS_EXPR:
but that does not mean the operands should be
converted to ints! */
result_type = integer_type_node;
- op0 = c_common_truthvalue_conversion (location, op0);
- op1 = c_common_truthvalue_conversion (location, op1);
+ if (op0_int_operands)
+ {
+ op0 = c_objc_common_truthvalue_conversion (location, orig_op0);
+ op0 = remove_c_maybe_const_expr (op0);
+ }
+ else
+ op0 = c_objc_common_truthvalue_conversion (location, op0);
+ if (op1_int_operands)
+ {
+ op1 = c_objc_common_truthvalue_conversion (location, orig_op1);
+ op1 = remove_c_maybe_const_expr (op1);
+ }
+ else
+ op1 = c_objc_common_truthvalue_conversion (location, op1);
converted = 1;
+ boolean_op = true;
}
if (code == TRUTH_ANDIF_EXPR)
{
Also set SHORT_SHIFT if shifting rightward. */
case RSHIFT_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+ && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST)
/* Use the type of the value to be shifted. */
result_type = type0;
- /* Convert the shift-count to an integer, regardless of size
- of value being shifted. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ /* Convert the non vector shift-count to an integer, regardless
+ of size of value being shifted. */
+ if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
break;
case LSHIFT_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+ && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+ {
+ result_type = type0;
+ converted = 1;
+ }
+ else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST)
/* Use the type of the value to be shifted. */
result_type = type0;
- /* Convert the shift-count to an integer, regardless of size
- of value being shifted. */
- if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+ /* Convert the non vector shift-count to an integer, regardless
+ of size of value being shifted. */
+ if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
case EQ_EXPR:
case NE_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (GET_MODE_BITSIZE
+ (TYPE_MODE (TREE_TYPE (type0))), 0);
+ result_type = build_opaque_vector_type (intt,
+ TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1))
warning_at (location,
OPT_Wfloat_equal,
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
short_compare = 1;
+ else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
+ {
+ if (TREE_CODE (op0) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
+ {
+ if (code == EQ_EXPR)
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<false%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op0, 0));
+ else
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<true%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op0, 0));
+ }
+ result_type = type0;
+ }
+ else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
+ {
+ if (TREE_CODE (op1) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
+ {
+ if (code == EQ_EXPR)
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<false%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ else
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<true%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ }
+ result_type = type1;
+ }
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
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 (location, type0, type1))
result_type = common_pointer_type (type0, type1);
+ 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");
}
"comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
- result_type = ptr_type_node;
- }
- else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
- {
- if (TREE_CODE (op0) == ADDR_EXPR
- && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
- warning_at (location,
- OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op0, 0));
- result_type = type0;
- }
- else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
- {
- if (TREE_CODE (op1) == ADDR_EXPR
- && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
- warning_at (location,
- OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op1, 0));
- result_type = type1;
+ {
+ 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 && code1 == INTEGER_TYPE)
{
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (GET_MODE_BITSIZE
+ (TYPE_MODE (TREE_TYPE (type0))), 0);
+ result_type = build_opaque_vector_type (intt,
+ TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == FIXED_POINT_TYPE)
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
+ 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);
else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"ordered comparisons of pointers to functions");
+ else if (null_pointer_constant_p (orig_op0)
+ || null_pointer_constant_p (orig_op1))
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with null pointer");
+
+ }
+ 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");
}
{
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,
- "ordered comparison of pointer with integer zero");
+ "ordered comparison of pointer with integer zero");
}
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
{
result_type = type1;
- pedwarn (location, OPT_pedantic,
- "ordered comparison of pointer with integer zero");
+ if (pedantic)
+ pedwarn (location, OPT_pedantic,
+ "ordered comparison of pointer with integer zero");
+ else if (extra_warnings)
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
if (shorten || common || short_compare)
{
result_type = c_common_type (type0, type1);
+ do_warn_double_promotion (result_type, type0, type1,
+ "implicit conversion from %qT to %qT "
+ "to match other operand of binary "
+ "expression",
+ location);
if (result_type == error_mark_node)
return error_mark_node;
}
if (type0 != orig_type0 || type1 != orig_type1)
{
gcc_assert (may_need_excess_precision && common);
- real_result_type = c_common_type (orig_type0, orig_type1);
+ semantic_result_type = c_common_type (orig_type0, orig_type1);
}
if (first_complex)
{
{
case MULT_EXPR:
case TRUNC_DIV_EXPR:
+ op1 = c_save_expr (op1);
imag = build2 (resultcode, real_type, imag, op1);
/* Fall through. */
case PLUS_EXPR:
switch (code)
{
case MULT_EXPR:
+ op0 = c_save_expr (op0);
imag = build2 (resultcode, real_type, op0, imag);
/* Fall through. */
case PLUS_EXPR:
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);
}
warn_for_sign_compare (location, orig_op0_folded,
orig_op1_folded, op0, op1,
result_type, resultcode);
- if (!in_late_binary_op)
+ if (!in_late_binary_op && !int_operands)
{
if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
op0 = c_wrap_maybe_const (op0, !op0_maybe_const);
return error_mark_node;
}
+ if (build_type == NULL_TREE)
+ {
+ build_type = result_type;
+ if ((type0 != orig_type0 || type1 != orig_type1)
+ && !boolean_op)
+ {
+ 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. */
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);
- real_result_type = c_common_type (orig_type0, orig_type1);
- }
- }
-
/* Treat expressions in initializers specially as they can't trap. */
if (int_const_or_overflow)
ret = (require_constant_value
else if (TREE_CODE (ret) != INTEGER_CST && int_operands
&& !in_late_binary_op)
ret = note_integer_operands (ret);
- if (real_result_type)
- ret = build1 (EXCESS_PRECISION_EXPR, real_result_type, ret);
+ if (semantic_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
protected_set_expr_location (ret, location);
return ret;
}
error_at (location, "used union type value where scalar is required");
return error_mark_node;
+ case VOID_TYPE:
+ error_at (location, "void value not ignored as it ought to be");
+ return error_mark_node;
+
case FUNCTION_TYPE:
gcc_unreachable ();
+ case VECTOR_TYPE:
+ error_at (location, "used vector type where scalar is required");
+ return error_mark_node;
+
default:
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? */
- expr = c_common_truthvalue_conversion (location, expr);
+ if (int_operands && TREE_CODE (expr) != INTEGER_CST)
+ {
+ expr = remove_c_maybe_const_expr (expr);
+ expr = build2 (NE_EXPR, integer_type_node, expr,
+ convert (TREE_TYPE (expr), integer_zero_node));
+ expr = note_integer_operands (expr);
+ }
+ else
+ /* ??? Should we also give an error for vectors rather than leaving
+ those to give errors later? */
+ expr = c_common_truthvalue_conversion (location, expr);
if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
{
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
break;
case BIT_AND_EXPR:
r_name = "&";
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ /* const vars may be specified in firstprivate clause. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && TREE_READONLY (t))
+ break;
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
return clauses;
}
+/* Create a transaction node. */
+
+tree
+c_finish_transaction (location_t loc, tree block, int flags)
+{
+ tree stmt = build_stmt (loc, TRANSACTION_EXPR, block);
+ if (flags & TM_STMT_ATTR_OUTER)
+ TRANSACTION_EXPR_OUTER (stmt) = 1;
+ if (flags & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (stmt) = 1;
+ return add_stmt (stmt);
+}
+
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
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