/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file is part of the C front end.
static int require_constant_value;
static int require_constant_elements;
+static bool null_pointer_constant_p (tree);
static tree qualify_type (tree, tree);
static int tagged_types_tu_compatible_p (tree, tree);
static int comp_target_types (tree, tree);
static int function_types_compatible_p (tree, tree);
static int type_lists_compatible_p (tree, tree);
static tree decl_constant_value_for_broken_optimization (tree);
-static tree default_function_array_conversion (tree);
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
static tree valid_compound_expr_initializer (tree, tree);
static void push_string (const char *);
static void push_member_name (tree);
-static void push_array_bounds (int);
static int spelling_length (void);
static char *print_spelling (char *);
static void warning_init (const char *);
static int lvalue_or_else (tree, enum lvalue_use);
static int lvalue_p (tree);
static void record_maybe_used_decl (tree);
+static int comptypes_internal (tree, tree);
\f
+/* Return true if EXP is a null pointer constant, false otherwise. */
+
+static bool
+null_pointer_constant_p (tree expr)
+{
+ /* This should really operate on c_expr structures, but they aren't
+ yet available everywhere required. */
+ tree type = TREE_TYPE (expr);
+ return (TREE_CODE (expr) == INTEGER_CST
+ && !TREE_CONSTANT_OVERFLOW (expr)
+ && integer_zerop (expr)
+ && (INTEGRAL_TYPE_P (type)
+ || (TREE_CODE (type) == POINTER_TYPE
+ && VOID_TYPE_P (TREE_TYPE (type))
+ && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
+}
+\f/* This is a cache to hold if two types are compatible or not. */
+
+struct tagged_tu_seen_cache {
+ const struct tagged_tu_seen_cache * next;
+ tree t1;
+ tree t2;
+ /* The return value of tagged_types_tu_compatible_p if we had seen
+ these two types already. */
+ int val;
+};
+
+static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
+static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *);
+
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
{
/* Preserve unsignedness if not really getting any wider. */
if (TYPE_UNSIGNED (type)
- && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
- return unsigned_type_node;
+ && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+ return unsigned_type_node;
return integer_type_node;
}
return c_build_qualified_type (type,
TYPE_QUALS (type) | TYPE_QUALS (like));
}
+
+/* Return true iff the given tree T is a variable length array. */
+
+bool
+c_vla_type_p (tree t)
+{
+ if (TREE_CODE (t) == ARRAY_TYPE
+ && C_TYPE_VARIABLE_SIZE (t))
+ return true;
+ return false;
+}
\f
/* Return the composite type of two compatible types.
tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
int quals;
tree unqual_elt;
+ tree d1 = TYPE_DOMAIN (t1);
+ tree d2 = TYPE_DOMAIN (t2);
+ bool d1_variable, d2_variable;
+ bool d1_zero, d2_zero;
/* We should not have any type quals on arrays at all. */
gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
-
+
+ d1_zero = d1 == 0 || !TYPE_MAX_VALUE (d1);
+ d2_zero = d2 == 0 || !TYPE_MAX_VALUE (d2);
+
+ d1_variable = (!d1_zero
+ && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
+ || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
+ d2_variable = (!d2_zero
+ && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
+ || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
+ d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
+ d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
+
/* Save space: see if the result is identical to one of the args. */
- if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
+ if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)
+ && (d2_variable || d2_zero || !d1_variable))
return build_type_attribute_variant (t1, attributes);
- if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
+ if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)
+ && (d1_variable || d1_zero || !d2_variable))
return build_type_attribute_variant (t2, attributes);
-
+
if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t2, attributes);
-
+
/* Merge the element types, and have a size if either arg has
one. We may have qualifiers on the element types. To set
up TYPE_MAIN_VARIANT correctly, we need to form the
quals = TYPE_QUALS (strip_array_types (elt));
unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
t1 = build_array_type (unqual_elt,
- TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ TYPE_DOMAIN ((TYPE_DOMAIN (t1)
+ && (d2_variable
+ || d2_zero
+ || !d1_variable))
+ ? t1
+ : t2));
t1 = c_build_qualified_type (t1, quals);
return build_type_attribute_variant (t1, attributes);
}
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ if (attributes != NULL)
+ {
+ /* Try harder not to create a new aggregate type. */
+ if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes))
+ return t1;
+ if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes))
+ return t2;
+ }
+ return build_type_attribute_variant (t1, attributes);
+
case FUNCTION_TYPE:
/* Function types: prefer the one that specified arg types.
If both do, merge the arg types. Also merge the return types. */
return t1;
gcc_assert (TREE_CODE (t1) == POINTER_TYPE
- && TREE_CODE (t2) == POINTER_TYPE);
+ && TREE_CODE (t2) == POINTER_TYPE);
/* Merge the attributes. */
attributes = targetm.merge_type_attributes (t1, t2);
gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
|| code2 == REAL_TYPE || code2 == INTEGER_TYPE);
+ /* When one operand is a decimal float type, the other operand cannot be
+ a generic float type or a complex type. We also disallow vector types
+ here. */
+ if ((DECIMAL_FLOAT_TYPE_P (t1) || DECIMAL_FLOAT_TYPE_P (t2))
+ && !(DECIMAL_FLOAT_TYPE_P (t1) && DECIMAL_FLOAT_TYPE_P (t2)))
+ {
+ if (code1 == VECTOR_TYPE || code2 == VECTOR_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and vector types");
+ return error_mark_node;
+ }
+ if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and complex types");
+ return error_mark_node;
+ }
+ if (code1 == REAL_TYPE && code2 == REAL_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and other float types");
+ return error_mark_node;
+ }
+ }
+
/* If one type is a vector type, return that type. (How the usual
arithmetic conversions apply to the vector types extension is not
precisely specified.) */
if (code2 == REAL_TYPE && code1 != REAL_TYPE)
return t2;
+ /* If both are real and either are decimal floating point types, use
+ the decimal floating point type with the greater precision. */
+
+ if (code1 == REAL_TYPE && code2 == REAL_TYPE)
+ {
+ if (TYPE_MAIN_VARIANT (t1) == dfloat128_type_node
+ || TYPE_MAIN_VARIANT (t2) == dfloat128_type_node)
+ return dfloat128_type_node;
+ else if (TYPE_MAIN_VARIANT (t1) == dfloat64_type_node
+ || TYPE_MAIN_VARIANT (t2) == dfloat64_type_node)
+ return dfloat64_type_node;
+ else if (TYPE_MAIN_VARIANT (t1) == dfloat32_type_node
+ || TYPE_MAIN_VARIANT (t2) == dfloat32_type_node)
+ return dfloat32_type_node;
+ }
+
/* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
return long_long_unsigned_type_node;
else
- return long_long_integer_type_node;
+ return long_long_integer_type_node;
}
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
return t2;
}
\f
-/* Wrapper around c_common_type that is used by c-common.c. ENUMERAL_TYPEs
+/* Wrapper around c_common_type that is used by c-common.c and other
+ front end optimizations that remove promotions. ENUMERAL_TYPEs
are allowed here and are converted to their compatible integer types.
BOOLEAN_TYPEs are allowed here and return either boolean_type_node or
preferably a non-Boolean type as the common type. */
return c_common_type (t1, t2);
}
-\f
+
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. */
int
comptypes (tree type1, tree type2)
{
+ const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
+ int val;
+
+ val = comptypes_internal (type1, type2);
+ free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+
+ return val;
+}
+\f
+/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
+ or various other operations. Return 2 if they are compatible
+ but a warning may be needed if you use them together. This
+ differs from comptypes, in that we don't free the seen types. */
+
+static int
+comptypes_internal (tree type1, tree type2)
+{
tree t1 = type1;
tree t2 = type2;
int attrval, val;
|| TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
- ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
+ ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2)));
break;
case FUNCTION_TYPE:
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
- && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2))))
+ && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2))))
return 0;
/* Sizes must match unless one is missing or variable. */
d2_variable = (!d2_zero
&& (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
+ d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
+ d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
if (d1_variable || d2_variable)
break;
|| !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
val = 0;
- break;
+ break;
}
case ENUMERAL_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
- val = tagged_types_tu_compatible_p (t1, t2);
+ {
+ tree a1 = TYPE_ATTRIBUTES (t1);
+ tree a2 = TYPE_ATTRIBUTES (t2);
+
+ if (! attribute_list_contained (a1, a2)
+ && ! attribute_list_contained (a2, a1))
+ break;
+
+ if (attrval != 2)
+ return tagged_types_tu_compatible_p (t1, t2);
+ val = tagged_types_tu_compatible_p (t1, t2);
+ }
break;
case VECTOR_TYPE:
val = TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
- && comptypes (TREE_TYPE (t1), TREE_TYPE (t2));
+ && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2));
break;
default:
return t1 == t2;
}
-/* The C standard says that two structures in different translation
- units are compatible with each other only if the types of their
- fields are compatible (among other things). So, consider two copies
- of this structure: */
+/* Allocate the seen two types, assuming that they are compatible. */
-struct tagged_tu_seen {
- const struct tagged_tu_seen * next;
- tree t1;
- tree t2;
-};
+static struct tagged_tu_seen_cache *
+alloc_tagged_tu_seen_cache (tree t1, tree t2)
+{
+ struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache);
+ tu->next = tagged_tu_seen_base;
+ tu->t1 = t1;
+ tu->t2 = t2;
+
+ tagged_tu_seen_base = tu;
+
+ /* The C standard says that two structures in different translation
+ units are compatible with each other only if the types of their
+ fields are compatible (among other things). We assume that they
+ are compatible until proven otherwise when building the cache.
+ An example where this can occur is:
+ struct a
+ {
+ struct a *next;
+ };
+ If we are comparing this against a similar struct in another TU,
+ and did not assume they were compatible, we end up with an infinite
+ loop. */
+ tu->val = 1;
+ return tu;
+}
-/* Can they be compatible with each other? We choose to break the
- recursion by allowing those types to be compatible. */
+/* Free the seen types until we get to TU_TIL. */
-static const struct tagged_tu_seen * tagged_tu_seen_base;
+static void
+free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til)
+{
+ const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base;
+ while (tu != tu_til)
+ {
+ struct tagged_tu_seen_cache *tu1 = (struct tagged_tu_seen_cache*)tu;
+ tu = tu1->next;
+ free (tu1);
+ }
+ tagged_tu_seen_base = tu_til;
+}
/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
compatible. If the two types are not the same (which has been
return 1;
{
- const struct tagged_tu_seen * tts_i;
+ const struct tagged_tu_seen_cache * tts_i;
for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next)
if (tts_i->t1 == t1 && tts_i->t2 == t2)
- return 1;
+ return tts_i->val;
}
switch (TREE_CODE (t1))
{
case ENUMERAL_TYPE:
{
+ struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
+ /* Speed up the case where the type values are in the same order. */
+ tree tv1 = TYPE_VALUES (t1);
+ tree tv2 = TYPE_VALUES (t2);
- /* Speed up the case where the type values are in the same order. */
- tree tv1 = TYPE_VALUES (t1);
- tree tv2 = TYPE_VALUES (t2);
-
- if (tv1 == tv2)
- return 1;
+ if (tv1 == tv2)
+ {
+ return 1;
+ }
- for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
- {
- if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
- break;
- if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
- return 0;
- }
+ for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
+ {
+ if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
+ break;
+ if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
+ {
+ tu->val = 0;
+ return 0;
+ }
+ }
- if (tv1 == NULL_TREE && tv2 == NULL_TREE)
- return 1;
- if (tv1 == NULL_TREE || tv2 == NULL_TREE)
- return 0;
+ if (tv1 == NULL_TREE && tv2 == NULL_TREE)
+ {
+ return 1;
+ }
+ if (tv1 == NULL_TREE || tv2 == NULL_TREE)
+ {
+ tu->val = 0;
+ return 0;
+ }
if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
- return 0;
+ {
+ tu->val = 0;
+ return 0;
+ }
for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
{
s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
if (s2 == NULL
|| simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1)
- return 0;
+ {
+ tu->val = 0;
+ return 0;
+ }
}
return 1;
}
case UNION_TYPE:
{
+ struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
- return 0;
+ {
+ tu->val = 0;
+ return 0;
+ }
+
+ /* 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))
+ {
+ int result;
+
+
+ if (DECL_NAME (s1) == NULL
+ || DECL_NAME (s1) != DECL_NAME (s2))
+ break;
+ result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
+ if (result == 0)
+ {
+ tu->val = 0;
+ return 0;
+ }
+ if (result == 2)
+ needs_warning = true;
+
+ if (TREE_CODE (s1) == FIELD_DECL
+ && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+ DECL_FIELD_BIT_OFFSET (s2)) != 1)
+ {
+ tu->val = 0;
+ return 0;
+ }
+ }
+ if (!s1 && !s2)
+ {
+ tu->val = needs_warning ? 2 : 1;
+ return tu->val;
+ }
for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
{
bool ok = false;
- struct tagged_tu_seen tts;
-
- tts.next = tagged_tu_seen_base;
- tts.t1 = t1;
- tts.t2 = t2;
- tagged_tu_seen_base = &tts;
if (DECL_NAME (s1) != NULL)
for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
if (DECL_NAME (s1) == DECL_NAME (s2))
{
int result;
- result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
+ result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
- break;
+ {
+ tu->val = 0;
+ return 0;
+ }
if (result == 2)
needs_warning = true;
ok = true;
break;
}
- tagged_tu_seen_base = tts.next;
if (!ok)
- return 0;
+ {
+ tu->val = 0;
+ return 0;
+ }
}
- return needs_warning ? 2 : 1;
+ tu->val = needs_warning ? 2 : 10;
+ return tu->val;
}
case RECORD_TYPE:
{
- struct tagged_tu_seen tts;
-
- tts.next = tagged_tu_seen_base;
- tts.t1 = t1;
- tts.t2 = t2;
- tagged_tu_seen_base = &tts;
+ struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
s1 && s2;
if (TREE_CODE (s1) != TREE_CODE (s2)
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
- result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
+ result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
break;
if (result == 2)
DECL_FIELD_BIT_OFFSET (s2)) != 1)
break;
}
- tagged_tu_seen_base = tts.next;
if (s1 && s2)
- return 0;
- return needs_warning ? 2 : 1;
+ tu->val = 0;
+ else
+ tu->val = needs_warning ? 2 : 1;
+ return tu->val;
}
default:
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
- val = comptypes (ret1, ret2);
+ val = comptypes_internal (ret1, ret2);
if (val == 0)
return 0;
return 0;
/* If one of these types comes from a non-prototype fn definition,
compare that with the other type's arglist.
- If they don't match, ask for a warning (0, but no error). */
+ 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)))
val = 2;
else if (TREE_CODE (a1) == ERROR_MARK
|| TREE_CODE (a2) == ERROR_MARK)
;
- else if (!(newval = comptypes (mv1, mv2)))
+ else if (!(newval = comptypes_internal (mv1, mv2)))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes (mv3, mv2))
+ if (comptypes_internal (mv3, mv2))
break;
}
if (memb == 0)
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes (mv3, mv1))
+ if (comptypes_internal (mv3, mv1))
break;
}
if (memb == 0)
return ret;
}
-
-/* Perform the default conversion of arrays and functions to pointers.
- Return the result of converting EXP. For any other expression, just
- return EXP. */
-
+/* Convert the array expression EXP to a pointer. */
static tree
-default_function_array_conversion (tree exp)
+array_to_pointer_conversion (tree exp)
{
- tree orig_exp;
+ tree orig_exp = exp;
tree type = TREE_TYPE (exp);
- enum tree_code code = TREE_CODE (type);
- int not_lvalue = 0;
+ tree adr;
+ tree restype = TREE_TYPE (type);
+ tree ptrtype;
- /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
- an lvalue.
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
- Do not use STRIP_NOPS here! It will remove conversions from pointer
- to integer and cause infinite recursion. */
- orig_exp = exp;
- while (TREE_CODE (exp) == NON_LVALUE_EXPR
- || (TREE_CODE (exp) == NOP_EXPR
- && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
- {
- if (TREE_CODE (exp) == NON_LVALUE_EXPR)
- not_lvalue = 1;
- exp = TREE_OPERAND (exp, 0);
- }
+ STRIP_TYPE_NOPS (exp);
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
- if (code == FUNCTION_TYPE)
+ ptrtype = build_pointer_type (restype);
+
+ if (TREE_CODE (exp) == INDIRECT_REF)
+ return convert (ptrtype, TREE_OPERAND (exp, 0));
+
+ if (TREE_CODE (exp) == VAR_DECL)
{
- return build_unary_op (ADDR_EXPR, exp, 0);
+ /* We are making an ADDR_EXPR of ptrtype. This is a valid
+ ADDR_EXPR because it's the best way of representing what
+ happens in C when we take the address of an array and place
+ it in a pointer to the element type. */
+ adr = build1 (ADDR_EXPR, ptrtype, exp);
+ if (!c_mark_addressable (exp))
+ return error_mark_node;
+ TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
+ return adr;
}
- if (code == ARRAY_TYPE)
- {
- tree adr;
- tree restype = TREE_TYPE (type);
- tree ptrtype;
- int constp = 0;
- int volatilep = 0;
- int lvalue_array_p;
- if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
- {
- constp = TREE_READONLY (exp);
- volatilep = TREE_THIS_VOLATILE (exp);
- }
+ /* This way is better for a COMPONENT_REF since it can
+ simplify the offset for a component. */
+ adr = build_unary_op (ADDR_EXPR, exp, 1);
+ return convert (ptrtype, adr);
+}
- if (TYPE_QUALS (type) || constp || volatilep)
- restype
- = c_build_qualified_type (restype,
- TYPE_QUALS (type)
- | (constp * TYPE_QUAL_CONST)
- | (volatilep * TYPE_QUAL_VOLATILE));
+/* Convert the function expression EXP to a pointer. */
+static tree
+function_to_pointer_conversion (tree exp)
+{
+ tree orig_exp = exp;
- if (TREE_CODE (exp) == INDIRECT_REF)
- return convert (build_pointer_type (restype),
- TREE_OPERAND (exp, 0));
+ gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE);
- if (TREE_CODE (exp) == COMPOUND_EXPR)
- {
- tree op1 = default_conversion (TREE_OPERAND (exp, 1));
- return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
- TREE_OPERAND (exp, 0), op1);
- }
+ STRIP_TYPE_NOPS (exp);
- lvalue_array_p = !not_lvalue && lvalue_p (exp);
- if (!flag_isoc99 && !lvalue_array_p)
- {
- /* Before C99, non-lvalue arrays do not decay to pointers.
- Normally, using such an array would be invalid; but it can
- be used correctly inside sizeof or as a statement expression.
- Thus, do not give an error here; an error will result later. */
- return exp;
- }
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp) = 1;
- ptrtype = build_pointer_type (restype);
+ return build_unary_op (ADDR_EXPR, exp, 0);
+}
- if (TREE_CODE (exp) == VAR_DECL)
- {
- /* We are making an ADDR_EXPR of ptrtype. This is a valid
- ADDR_EXPR because it's the best way of representing what
- happens in C when we take the address of an array and place
- it in a pointer to the element type. */
- adr = build1 (ADDR_EXPR, ptrtype, exp);
- if (!c_mark_addressable (exp))
- return error_mark_node;
- TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
- return adr;
- }
- /* This way is better for a COMPONENT_REF since it can
- simplify the offset for a component. */
- adr = build_unary_op (ADDR_EXPR, exp, 1);
- return convert (ptrtype, adr);
+/* Perform the default conversion of arrays and functions to pointers.
+ Return the result of converting EXP. For any other expression, just
+ return EXP after removing NOPs. */
+
+struct c_expr
+default_function_array_conversion (struct c_expr exp)
+{
+ tree orig_exp = exp.value;
+ tree type = TREE_TYPE (exp.value);
+ enum tree_code code = TREE_CODE (type);
+
+ switch (code)
+ {
+ case ARRAY_TYPE:
+ {
+ bool not_lvalue = false;
+ bool lvalue_array_p;
+
+ while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR
+ || TREE_CODE (exp.value) == NOP_EXPR
+ || TREE_CODE (exp.value) == CONVERT_EXPR)
+ && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type)
+ {
+ if (TREE_CODE (exp.value) == NON_LVALUE_EXPR)
+ not_lvalue = true;
+ exp.value = TREE_OPERAND (exp.value, 0);
+ }
+
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp.value) = 1;
+
+ lvalue_array_p = !not_lvalue && lvalue_p (exp.value);
+ if (!flag_isoc99 && !lvalue_array_p)
+ {
+ /* Before C99, non-lvalue arrays do not decay to pointers.
+ Normally, using such an array would be invalid; but it can
+ be used correctly inside sizeof or as a statement expression.
+ Thus, do not give an error here; an error will result later. */
+ return exp;
+ }
+
+ exp.value = array_to_pointer_conversion (exp.value);
+ }
+ break;
+ case FUNCTION_TYPE:
+ exp.value = function_to_pointer_conversion (exp.value);
+ break;
+ default:
+ STRIP_TYPE_NOPS (exp.value);
+ if (TREE_NO_WARNING (orig_exp))
+ TREE_NO_WARNING (exp.value) = 1;
+ break;
}
+
return exp;
}
/* Perform default promotions for C data used in expressions.
- Arrays and functions are converted to pointers;
- enumeral types or short or char, to int.
+ Enumeral types or short or char are converted to int.
In addition, manifest constants symbols are replaced by their values. */
tree
tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (type);
- if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
- return default_function_array_conversion (exp);
+ /* Functions and arrays have been converted during parsing. */
+ gcc_assert (code != FUNCTION_TYPE);
+ if (code == ARRAY_TYPE)
+ return exp;
/* Constants can be used directly unless they're not loadable. */
if (TREE_CODE (exp) == CONST_DECL)
do
{
tree subdatum = TREE_VALUE (field);
+ int quals;
+ tree subtype;
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
- ref = build3 (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+ quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
+ quals |= TYPE_QUALS (TREE_TYPE (datum));
+ subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
+
+ ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
NULL_TREE);
if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
TREE_READONLY (ref) = 1;
return error_mark_node;
}
- /* Subscripting with type char is likely to lose on a machine where
- chars are signed. So warn on any machine, but optionally. Don't
- warn for unsigned char since that type is safe. Don't warn for
- signed char because anyone who uses that must have done so
- deliberately. ??? Existing practice has also been to warn only
- when the char index is syntactically the index, not for
- char[array]. */
- if (warn_char_subscripts && !swapped
- && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning (0, "array subscript has type %<char%>");
+ /* ??? Existing practice has been to warn only when the char
+ index is syntactically the index, not for char[array]. */
+ if (!swapped)
+ warn_array_subscript_with_type_char (index);
/* Apply default promotions *after* noticing character types. */
index = default_conversion (index);
type = TYPE_MAIN_VARIANT (type);
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
- or if the array is. */
+ or if the array is. */
TREE_READONLY (rval)
|= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array)))
| TREE_READONLY (array));
if (TREE_CODE (ref) == CONST_DECL)
{
+ used_types_insert (TREE_TYPE (ref));
ref = DECL_INITIAL (ref);
TREE_CONSTANT (ref) = 1;
TREE_INVARIANT (ref) = 1;
if (context != 0 && context != current_function_decl)
DECL_NONLOCAL (ref) = 1;
}
+ /* C99 6.7.4p3: An inline definition of a function with external
+ linkage ... shall not contain a reference to an identifier with
+ internal linkage. */
+ else if (current_function_decl != 0
+ && DECL_DECLARED_INLINE_P (current_function_decl)
+ && DECL_EXTERNAL (current_function_decl)
+ && VAR_OR_FUNCTION_DECL_P (ref)
+ && (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref))
+ && ! TREE_PUBLIC (ref))
+ pedwarn ("%H%qD is static but used in inline function %qD "
+ "which is not static", &loc, ref, current_function_decl);
return ref;
}
{
ret.value = c_sizeof (TREE_TYPE (expr.value));
ret.original_code = ERROR_MARK;
+ if (c_vla_type_p (TREE_TYPE (expr.value)))
+ {
+ /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */
+ ret.value = build2 (COMPOUND_EXPR, TREE_TYPE (ret.value), expr.value, ret.value);
+ }
pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
}
return ret;
type = groktypename (t);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
- pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ pop_maybe_used (type != error_mark_node
+ ? C_TYPE_VARIABLE_SIZE (type) : false);
return ret;
}
return tem;
name = DECL_NAME (function);
-
- /* Differs from default_conversion by not setting TREE_ADDRESSABLE
- (because calling an inline function does not mean the function
- needs to be separately compiled). */
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
fundecl = function;
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
}
- else
- function = default_conversion (function);
+ if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
+ function = function_to_pointer_conversion (function);
/* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
expressions, like those used for ObjC messenger dispatches. */
expression if necessary. This has the nice side-effect to prevent
the tree-inliner from generating invalid assignment trees which may
blow up in the RTL expander later. */
- if (TREE_CODE (function) == NOP_EXPR
+ if ((TREE_CODE (function) == NOP_EXPR
+ || TREE_CODE (function) == CONVERT_EXPR)
&& TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
&& !comptypes (fntype, TREE_TYPE (tem)))
if (AGGREGATE_TYPE_P (return_type))
rhs = build_compound_literal (return_type,
- build_constructor (return_type,
- NULL_TREE));
+ build_constructor (return_type, 0));
else
- rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
+ rhs = fold_convert (return_type, integer_zero_node);
return build2 (COMPOUND_EXPR, return_type, trap, rhs);
}
/* Check that the arguments to the function are valid. */
- check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
-
- result = build3 (CALL_EXPR, TREE_TYPE (fntype),
- function, coerced_params, NULL_TREE);
- TREE_SIDE_EFFECTS (result) = 1;
+ check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
+ TYPE_ARG_TYPES (fntype));
if (require_constant_value)
{
- result = fold_initializer (result);
+ result = fold_build3_initializer (CALL_EXPR, TREE_TYPE (fntype),
+ function, coerced_params, NULL_TREE);
if (TREE_CONSTANT (result)
&& (name == NULL_TREE
pedwarn_init ("initializer element is not constant");
}
else
- result = fold (result);
+ result = fold_build3 (CALL_EXPR, TREE_TYPE (fntype),
+ function, coerced_params, NULL_TREE);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
STRIP_TYPE_NOPS (val);
- val = default_function_array_conversion (val);
-
val = require_complete_type (val);
if (type != 0)
{
/* Optionally warn about conversions that
differ from the default conversions. */
- if (warn_conversion || warn_traditional)
+ if (warn_traditional_conversion || warn_traditional)
{
unsigned int formal_prec = TYPE_PRECISION (type);
{
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
- if (formal_prec == TYPE_PRECISION (float_type_node))
+ if (formal_prec == TYPE_PRECISION (float_type_node)
+ && type != dfloat32_type_node)
warning (0, "passing argument %d of %qE as %<float%> "
"rather than %<double%> due to prototype",
argnum, rname);
+
+ /* Warn if mismatch between argument and prototype
+ for decimal float types. Warn of conversions with
+ binary float types and of precision narrowing due to
+ prototype. */
+ else if (type != TREE_TYPE (val)
+ && (type == dfloat32_type_node
+ || type == dfloat64_type_node
+ || type == dfloat128_type_node
+ || TREE_TYPE (val) == dfloat32_type_node
+ || TREE_TYPE (val) == dfloat64_type_node
+ || TREE_TYPE (val) == dfloat128_type_node)
+ && (formal_prec
+ <= TYPE_PRECISION (TREE_TYPE (val))
+ || (type == dfloat128_type_node
+ && (TREE_TYPE (val)
+ != dfloat64_type_node
+ && (TREE_TYPE (val)
+ != dfloat32_type_node)))
+ || (type == dfloat64_type_node
+ && (TREE_TYPE (val)
+ != dfloat32_type_node))))
+ warning (0, "passing argument %d of %qE as %qT "
+ "rather than %qT due to prototype",
+ argnum, rname, type, TREE_TYPE (val));
+
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
- -Wconversion, not with -Wtraditional. */
- else if (warn_conversion && INTEGRAL_TYPE_P (type)
+ -Wtraditional-conversion, not with -Wtraditional. */
+ else if (warn_traditional_conversion && INTEGRAL_TYPE_P (type)
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
{
tree would_have_been = default_conversion (val);
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warning (0, "passing argument %d of %qE with different "
- "width due to prototype", argnum, rname);
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
+ "with different width due to prototype",
+ argnum, rname);
else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
;
/* Don't complain if the formal parameter type
&& TYPE_UNSIGNED (TREE_TYPE (val)))
;
else if (TYPE_UNSIGNED (type))
- warning (0, "passing argument %d of %qE as unsigned "
- "due to prototype", argnum, rname);
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
+ "as unsigned due to prototype",
+ argnum, rname);
else
- warning (0, "passing argument %d of %qE as signed "
- "due to prototype", argnum, rname);
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
+ "as signed due to prototype", argnum, rname);
}
}
result = tree_cons (NULL_TREE, parmval, result);
}
else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (val))
- < TYPE_PRECISION (double_type_node)))
+ && (TYPE_PRECISION (TREE_TYPE (val))
+ < TYPE_PRECISION (double_type_node))
+ && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
/* Convert `float' to `double'. */
result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
- else if ((invalid_func_diag =
- targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+ else if ((invalid_func_diag =
+ targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
{
error (invalid_func_diag);
- return error_mark_node;
+ return error_mark_node;
}
else
/* Convert `short' and `char' to full-size `int'. */
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (0, "suggest parentheses around + or - inside shift");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code1 == TRUTH_ANDIF_EXPR
|| code2 == TRUTH_ANDIF_EXPR)
- warning (0, "suggest parentheses around && within ||");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (0, "suggest parentheses around arithmetic in operand of |");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (0, "suggest parentheses around comparison in operand of |");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (0, "suggest parentheses around arithmetic in operand of ^");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (0, "suggest parentheses around comparison in operand of ^");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of ^");
}
if (code == BIT_AND_EXPR)
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (0, "suggest parentheses around + or - in operand of &");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (0, "suggest parentheses around comparison in operand of &");
+ warning (OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
if (TREE_CODE_CLASS (code) == tcc_comparison
&& (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison))
- warning (0, "comparisons like X<=Y<=Z do not have their mathematical meaning");
+ warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
+ "have their mathematical meaning");
+
+ }
+ /* Warn about comparisons against string literals, with the exception
+ of testing for equality or inequality of a string literal with NULL. */
+ if (code == EQ_EXPR || code == NE_EXPR)
+ {
+ if ((code1 == STRING_CST && !integer_zerop (arg2.value))
+ || (code2 == STRING_CST && !integer_zerop (arg1.value)))
+ warning (OPT_Wstring_literal_comparison,
+ "comparison with string literal");
}
+ else if (TREE_CODE_CLASS (code) == tcc_comparison
+ && (code1 == STRING_CST || code2 == STRING_CST))
+ warning (OPT_Wstring_literal_comparison,
+ "comparison with string literal");
- unsigned_conversion_warning (result.value, arg1.value);
- unsigned_conversion_warning (result.value, arg2.value);
overflow_warning (result.value);
return result;
different mode in place.)
So first try to find a common term here 'by hand'; we want to cover
at least the cases that occur in legal static initializers. */
- con0 = TREE_CODE (op0) == NOP_EXPR ? TREE_OPERAND (op0, 0) : op0;
- con1 = TREE_CODE (op1) == NOP_EXPR ? TREE_OPERAND (op1, 0) : op1;
+ if ((TREE_CODE (op0) == NOP_EXPR || TREE_CODE (op0) == CONVERT_EXPR)
+ && (TYPE_PRECISION (TREE_TYPE (op0))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))))
+ con0 = TREE_OPERAND (op0, 0);
+ else
+ con0 = op0;
+ if ((TREE_CODE (op1) == NOP_EXPR || TREE_CODE (op1) == CONVERT_EXPR)
+ && (TYPE_PRECISION (TREE_TYPE (op1))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))))
+ con1 = TREE_OPERAND (op1, 0);
+ else
+ con1 = op1;
if (TREE_CODE (con0) == PLUS_EXPR)
{
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold (build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)));
+ return fold_build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
}
\f
/* Construct and perhaps optimize a tree representation
enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
tree val;
int noconvert = flag;
+ const char *invalid_op_diag;
if (typecode == ERROR_MARK)
return error_mark_node;
if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
typecode = INTEGER_TYPE;
+ if ((invalid_op_diag
+ = targetm.invalid_unary_op (code, TREE_TYPE (xarg))))
+ {
+ error (invalid_op_diag);
+ return error_mark_node;
+ }
+
switch (code)
{
case CONVERT_EXPR:
break;
case TRUTH_NOT_EXPR:
- /* ??? Why do most validation here but that for non-lvalue arrays
- in c_objc_common_truthvalue_conversion? */
if (typecode != INTEGER_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
- && typecode != COMPLEX_TYPE
- /* These will convert to a pointer. */
- && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
+ && typecode != COMPLEX_TYPE)
{
error ("wrong type argument to unary exclamation mark");
return error_mark_node;
arg = c_objc_common_truthvalue_conversion (arg);
return invert_truthvalue (arg);
- case NOP_EXPR:
- break;
-
case REALPART_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_REALPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ return fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
return arg;
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_IMAGPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ return fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
return convert (TREE_TYPE (arg), integer_zero_node);
&& typecode != INTEGER_TYPE && typecode != REAL_TYPE)
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- error ("wrong type argument to increment");
- else
- error ("wrong type argument to decrement");
+ error ("wrong type argument to increment");
+ else
+ error ("wrong type argument to decrement");
return error_mark_node;
}
else if ((pedantic || warn_pointer_arith)
&& (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
- {
+ {
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
pedwarn ("wrong type argument to increment");
else
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
- readonly_error (arg,
- ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? lv_increment : lv_decrement));
+ {
+ readonly_error (arg,
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment : lv_decrement));
+ return error_mark_node;
+ }
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
/* For &x[y], return x+y */
if (TREE_CODE (arg) == ARRAY_REF)
{
- if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
+ tree op0 = TREE_OPERAND (arg, 0);
+ if (!c_mark_addressable (op0))
return error_mark_node;
- return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
+ return build_binary_op (PLUS_EXPR,
+ (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
+ ? array_to_pointer_conversion (op0)
+ : op0),
TREE_OPERAND (arg, 1), 1);
}
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
+ 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. */
if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
when we have proper support for integer constant expressions. */
val = get_base_address (arg);
if (val && TREE_CODE (val) == INDIRECT_REF
- && integer_zerop (TREE_OPERAND (val, 0)))
- return fold_convert (argtype, fold_offsetof (arg));
+ && TREE_CONSTANT (TREE_OPERAND (val, 0)))
+ {
+ tree op0 = fold_convert (argtype, fold_offsetof (arg, val)), op1;
- val = build1 (ADDR_EXPR, argtype, arg);
+ op1 = fold_convert (argtype, TREE_OPERAND (val, 0));
+ return fold_build2 (PLUS_EXPR, argtype, op0, op1);
+ }
- if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
- TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
+ val = build1 (ADDR_EXPR, argtype, arg);
return val;
default:
- break;
+ gcc_unreachable ();
}
if (argtype == 0)
argtype = TREE_TYPE (arg);
- val = build1 (code, argtype, arg);
- return require_constant_value ? fold_initializer (val) : fold (val);
+ return require_constant_value ? fold_build1_initializer (code, argtype, arg)
+ : fold_build1 (code, argtype, arg);
}
/* Return nonzero if REF is an lvalue valid for this language.
static void
readonly_error (tree arg, enum lvalue_use use)
{
- gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement);
+ 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) (use == lv_assign \
- ? (A) \
- : (use == lv_increment ? (I) : (D)))
+#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 (N_("assignment of read-only member %qD"),
- N_("increment of read-only member %qD"),
- N_("decrement of read-only member %qD")),
+ 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 (N_("assignment of read-only variable %qD"),
- N_("increment of read-only variable %qD"),
- N_("decrement of read-only variable %qD")),
+ 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 (N_("assignment of read-only location"),
- N_("increment of read-only location"),
- N_("decrement of read-only location")));
+ error (READONLY_MSG (G_("assignment of read-only location"),
+ G_("increment of read-only location"),
+ G_("decrement of read-only location"),
+ G_("read-only location used as %<asm%> output")));
}
result_type = TYPE_MAIN_VARIANT (type1);
}
else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE)
- && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
- || code2 == COMPLEX_TYPE))
+ || code1 == COMPLEX_TYPE)
+ && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
+ || code2 == COMPLEX_TYPE))
{
result_type = c_common_type (type1, type2);
{
if (comp_target_types (type1, type2))
result_type = common_pointer_type (type1, type2);
- else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
- && TREE_CODE (orig_op1) != NOP_EXPR)
+ else if (null_pointer_constant_p (orig_op1))
result_type = qualify_type (type2, type1);
- else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
- && TREE_CODE (orig_op2) != NOP_EXPR)
+ else if (null_pointer_constant_p (orig_op2))
result_type = qualify_type (type1, type2);
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
- if (!integer_zerop (op2))
+ if (!null_pointer_constant_p (orig_op2))
pedwarn ("pointer/integer type mismatch in conditional expression");
else
{
}
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- if (!integer_zerop (op1))
+ if (!null_pointer_constant_p (orig_op1))
pedwarn ("pointer/integer type mismatch in conditional expression");
else
{
tree
build_compound_expr (tree expr1, tree expr2)
{
- /* Convert arrays and functions to pointers. */
- expr2 = default_function_array_conversion (expr2);
-
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
- statement: with -Wextra or -Wunused, we should warn if it doesn't have
+ statement: with -Wextra or -Wunused, we should warn if it doesn't have
any side-effects, unless it was explicitly cast to (void). */
if (warn_unused_value)
{
if (VOID_TYPE_P (TREE_TYPE (expr1))
- && TREE_CODE (expr1) == CONVERT_EXPR)
+ && (TREE_CODE (expr1) == NOP_EXPR
+ || TREE_CODE (expr1) == CONVERT_EXPR))
; /* (void) a, b */
else if (VOID_TYPE_P (TREE_TYPE (expr1))
&& TREE_CODE (expr1) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR)
+ && (TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR
+ || TREE_CODE (TREE_OPERAND (expr1, 1)) == NOP_EXPR))
; /* (void) a, (void) b, c */
else
warning (0, "left-hand operand of comma expression has no effect");
else if (warn_unused_value)
warn_if_unused_value (expr1, input_location);
+ if (expr2 == error_mark_node)
+ return error_mark_node;
+
return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
}
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
- value = default_function_array_conversion (value);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
if (pedantic)
pedwarn ("ISO C forbids casts to union type");
t = digest_init (type,
- build_constructor (type,
- build_tree_list (field, value)),
+ build_constructor_single (type, field, value),
true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
TREE_INVARIANT (t) = TREE_INVARIANT (value);
{
tree otype, ovalue;
- /* If casting to void, avoid the error that would come
- from default_conversion in the case of a non-lvalue array. */
if (type == void_type_node)
return build1 (CONVERT_EXPR, type, value);
- /* Convert functions and arrays to pointers,
- but don't convert any other types. */
- value = default_function_array_conversion (value);
otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */
}
/* Warn about possible alignment problems. */
- if (STRICT_ALIGNMENT && warn_cast_align
+ if (STRICT_ALIGNMENT
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
|| TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
&& TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning (0, "cast increases required alignment of target type");
+ warning (OPT_Wcast_align,
+ "cast increases required alignment of target type");
- if (warn_pointer_to_int_cast
- && TREE_CODE (type) == INTEGER_TYPE
+ if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
- && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
- && !TREE_CONSTANT (value))
- warning (0, "cast from pointer to integer of different size");
-
- if (warn_bad_function_cast
- && TREE_CODE (value) == CALL_EXPR
+ && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
+ /* Unlike conversion of integers to pointers, where the
+ warning is disabled for converting constants because
+ of cases such as SIG_*, warn about converting constant
+ pointers to integers. In some cases it may cause unwanted
+ sign extension, and a warning is appropriate. */
+ warning (OPT_Wpointer_to_int_cast,
+ "cast from pointer to integer of different size");
+
+ if (TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning (0, "cast from function call of type %qT to non-matching "
- "type %qT", otype, type);
+ warning (OPT_Wbad_function_cast, "cast from function call of type %qT "
+ "to non-matching type %qT", otype, type);
- if (warn_int_to_pointer_cast
- && TREE_CODE (type) == POINTER_TYPE
+ if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
/* Don't warn about converting any constant. */
&& !TREE_CONSTANT (value))
- warning (0, "cast to pointer from integer of different size");
+ warning (OPT_Wint_to_pointer_cast, "cast to pointer from integer "
+ "of different size");
- if (TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && TREE_CODE (expr) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (expr, 0))
- && flag_strict_aliasing && warn_strict_aliasing
- && !VOID_TYPE_P (TREE_TYPE (type)))
- {
- /* Casting the address of a decl to non void pointer. Warn
- if the cast breaks type based aliasing. */
- if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
- warning (0, "type-punning to incomplete type might break strict-aliasing rules");
- else
- {
- HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
- HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
-
- if (!alias_sets_conflict_p (set1, set2))
- warning (0, "dereferencing type-punned pointer will break strict-aliasing rules");
- else if (warn_strict_aliasing > 1
- && !alias_sets_might_conflict_p (set1, set2))
- warning (0, "dereferencing type-punned pointer might break strict-aliasing rules");
- }
- }
+ strict_aliasing_warning (otype, type, expr);
/* If pedantic, warn for conversions between function and object
pointer types, except for converting a null pointer constant
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
- && !(integer_zerop (value) && TREE_TYPE (otype) == void_type_node
- && TREE_CODE (expr) != NOP_EXPR))
+ && !null_pointer_constant_p (value))
pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
ovalue = value;
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
{
- if (EXPR_P (ovalue))
- /* If OVALUE had overflow set, then so will VALUE, so it
- is safe to overwrite. */
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
- else
- TREE_OVERFLOW (value) = 0;
-
- if (CONSTANT_CLASS_P (ovalue))
- /* Similarly, constant_overflow cannot have become
- cleared. */
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ if (CONSTANT_CLASS_P (ovalue)
+ && (TREE_OVERFLOW (ovalue) || TREE_CONSTANT_OVERFLOW (ovalue)))
+ {
+ /* Avoid clobbering a shared constant. */
+ value = copy_node (value);
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ }
+ else if (TREE_OVERFLOW (value) || TREE_CONSTANT_OVERFLOW (value))
+ /* Reset VALUE's overflow flags, ensuring constant sharing. */
+ value = build_int_cst_wide (TREE_TYPE (value),
+ TREE_INT_CST_LOW (value),
+ TREE_INT_CST_HIGH (value));
}
}
return build_c_cast (type, expr);
}
-
\f
/* Build an assignment expression of lvalue LHS from value RHS.
MODIFYCODE is the code for a binary operator that we use
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
+ if (!lvalue_or_else (lhs, lv_assign))
+ return error_mark_node;
+
STRIP_TYPE_NOPS (rhs);
newrhs = rhs;
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- if (!lvalue_or_else (lhs, lv_assign))
- return error_mark_node;
-
/* Give an error for storing in something that is 'const'. */
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
- readonly_error (lhs, lv_assign);
+ {
+ readonly_error (lhs, lv_assign);
+ return error_mark_node;
+ }
/* If storing into a structure or union member,
it has probably been given type `int'.
STRIP_TYPE_NOPS (rhs);
- if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
- rhs = default_conversion (rhs);
- else if (optimize && TREE_CODE (rhs) == VAR_DECL)
+ if (optimize && TREE_CODE (rhs) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
rhs = decl_constant_value_for_broken_optimization (rhs);
rhstype = TREE_TYPE (rhs);
}
/* Some types can interconvert without explicit casts. */
else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
- && vector_types_convertible_p (type, TREE_TYPE (rhs)))
+ && vector_types_convertible_p (type, TREE_TYPE (rhs)))
return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */
else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
&& (errtype == ic_argpass || errtype == ic_argpass_nonproto))
{
- tree memb_types;
- tree marginal_memb_type = 0;
+ tree memb, marginal_memb = NULL_TREE;
- for (memb_types = TYPE_FIELDS (type); memb_types;
- memb_types = TREE_CHAIN (memb_types))
+ for (memb = TYPE_FIELDS (type); memb ; memb = TREE_CHAIN (memb))
{
- tree memb_type = TREE_TYPE (memb_types);
+ tree memb_type = TREE_TYPE (memb);
if (comptypes (TYPE_MAIN_VARIANT (memb_type),
TYPE_MAIN_VARIANT (rhstype)))
break;
/* Keep looking for a better type, but remember this one. */
- if (!marginal_memb_type)
- marginal_memb_type = memb_type;
+ if (!marginal_memb)
+ marginal_memb = memb;
}
}
/* Can convert integer zero to any pointer type. */
- if (integer_zerop (rhs)
- || (TREE_CODE (rhs) == NOP_EXPR
- && integer_zerop (TREE_OPERAND (rhs, 0))))
+ if (null_pointer_constant_p (rhs))
{
rhs = null_pointer_node;
break;
}
}
- if (memb_types || marginal_memb_type)
+ if (memb || marginal_memb)
{
- if (!memb_types)
+ if (!memb)
{
/* We have only a marginally acceptable member type;
it needs a warning. */
- tree ttl = TREE_TYPE (marginal_memb_type);
+ tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb));
tree ttr = TREE_TYPE (rhstype);
/* Const and volatile mean something different for function
function where an ordinary one is wanted, but not
vice-versa. */
if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE "
"makes qualified function "
"pointer from unqualified"),
- N_("assignment makes qualified "
+ G_("assignment makes qualified "
"function pointer from "
"unqualified"),
- N_("initialization makes qualified "
+ G_("initialization makes qualified "
"function pointer from "
"unqualified"),
- N_("return makes qualified function "
+ G_("return makes qualified function "
"pointer from unqualified"));
}
else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
- N_("assignment discards qualifiers "
+ G_("assignment discards qualifiers "
"from pointer target type"),
- N_("initialization discards qualifiers "
+ G_("initialization discards qualifiers "
"from pointer target type"),
- N_("return discards qualifiers from "
+ G_("return discards qualifiers from "
"pointer target type"));
+
+ memb = marginal_memb;
}
- if (pedantic && !DECL_IN_SYSTEM_HEADER (fundecl))
+ if (pedantic && (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)))
pedwarn ("ISO C prohibits argument conversion to union type");
- return build1 (NOP_EXPR, type, rhs);
+ return build_constructor_single (type, memb, rhs);
}
}
mvr = TYPE_MAIN_VARIANT (mvr);
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = (targetm.vector_opaque_p (type)
- || targetm.vector_opaque_p (rhstype))
- && TREE_CODE (ttl) == VECTOR_TYPE
- && TREE_CODE (ttr) == VECTOR_TYPE;
+ || targetm.vector_opaque_p (rhstype))
+ && TREE_CODE (ttl) == VECTOR_TYPE
+ && TREE_CODE (ttr) == VECTOR_TYPE;
+
+ /* 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
+
+ int *p = NULL;
+
+ where NULL is typically defined in C to be '(void *) 0'. */
+ if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl))
+ warning (OPT_Wc___compat, "request for implicit conversion from "
+ "%qT to %qT not permitted in C++", rhstype, type);
+
+ /* Check if the right-hand side has a format attribute but the
+ left-hand side doesn't. */
+ if (warn_missing_format_attribute
+ && check_missing_format_attribute (type, rhstype))
+ {
+ switch (errtype)
+ {
+ case ic_argpass:
+ case ic_argpass_nonproto:
+ warning (OPT_Wmissing_format_attribute,
+ "argument %d of %qE might be "
+ "a candidate for a format attribute",
+ parmnum, rname);
+ break;
+ case ic_assign:
+ warning (OPT_Wmissing_format_attribute,
+ "assignment left-hand side might be "
+ "a candidate for a format attribute");
+ break;
+ case ic_init:
+ warning (OPT_Wmissing_format_attribute,
+ "initialization left-hand side might be "
+ "a candidate for a format attribute");
+ break;
+ case ic_return:
+ warning (OPT_Wmissing_format_attribute,
+ "return type might be "
+ "a candidate for a format attribute");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
||
(VOID_TYPE_P (ttr)
- /* Check TREE_CODE to catch cases like (void *) (char *) 0
- which are not ANSI null ptr constants. */
- && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
+ && !null_pointer_constant_p (rhs)
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- WARN_FOR_ASSIGNMENT (N_("ISO C forbids passing argument %d of "
+ WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
"%qE between function pointer "
"and %<void *%>"),
- N_("ISO C forbids assignment between "
+ G_("ISO C forbids assignment between "
"function pointer and %<void *%>"),
- N_("ISO C forbids initialization between "
+ G_("ISO C forbids initialization between "
"function pointer and %<void *%>"),
- N_("ISO C forbids return between function "
+ G_("ISO C forbids return between function "
"pointer and %<void *%>"));
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
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 (N_("passing argument %d of %qE discards "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
- N_("assignment discards qualifiers "
+ G_("assignment discards qualifiers "
"from pointer target type"),
- N_("initialization discards qualifiers "
+ G_("initialization discards qualifiers "
"from pointer target type"),
- N_("return discards qualifiers from "
+ G_("return discards qualifiers from "
"pointer target type"));
}
/* If this is not a case of ignoring a mismatch in signedness,
;
/* If there is a mismatch, do warn. */
else if (warn_pointer_sign)
- WARN_FOR_ASSIGNMENT (N_("pointer targets in passing argument "
+ WARN_FOR_ASSIGNMENT (G_("pointer targets in passing argument "
"%d of %qE differ in signedness"),
- N_("pointer targets in assignment "
+ G_("pointer targets in assignment "
"differ in signedness"),
- N_("pointer targets in initialization "
+ G_("pointer targets in initialization "
"differ in signedness"),
- N_("pointer targets in return differ "
+ G_("pointer targets in return differ "
"in signedness"));
}
else if (TREE_CODE (ttl) == FUNCTION_TYPE
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 (N_("passing argument %d of %qE makes "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
"qualified function pointer "
"from unqualified"),
- N_("assignment makes qualified function "
+ G_("assignment makes qualified function "
"pointer from unqualified"),
- N_("initialization makes qualified "
+ G_("initialization makes qualified "
"function pointer from unqualified"),
- N_("return makes qualified function "
+ G_("return makes qualified function "
"pointer from unqualified"));
}
}
else
/* Avoid warning about the volatile ObjC EH puts on decls. */
if (!objc_ok)
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE from "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE from "
"incompatible pointer type"),
- N_("assignment from incompatible pointer type"),
- N_("initialization from incompatible "
+ G_("assignment from incompatible pointer type"),
+ G_("initialization from incompatible "
"pointer type"),
- N_("return from incompatible pointer type"));
+ G_("return from incompatible pointer type"));
return convert (type, rhs);
}
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
- if (!(TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
- &&
- !(TREE_CODE (rhs) == NOP_EXPR
- && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
- && integer_zerop (TREE_OPERAND (rhs, 0))))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes "
+ if (!null_pointer_constant_p (rhs))
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
"pointer from integer without a cast"),
- N_("assignment makes pointer from integer "
+ G_("assignment makes pointer from integer "
"without a cast"),
- N_("initialization makes pointer from "
+ G_("initialization makes pointer from "
"integer without a cast"),
- N_("return makes pointer from integer "
+ G_("return makes pointer from integer "
"without a cast"));
return convert (type, rhs);
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE makes integer "
+ WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes integer "
"from pointer without a cast"),
- N_("assignment makes integer from pointer "
+ G_("assignment makes integer from pointer "
"without a cast"),
- N_("initialization makes integer from pointer "
+ G_("initialization makes integer from pointer "
"without a cast"),
- N_("return makes integer from pointer "
+ G_("return makes integer from pointer "
"without a cast"));
return convert (type, rhs);
}
}
/* Convert VALUE for assignment into inlined parameter PARM. ARGNUM
- is used for error and waring reporting and indicates which argument
+ is used for error and warning reporting and indicates which argument
is being processed. */
tree
{
tree ret, type;
- /* If FN was prototyped, the value has been converted already
- in convert_arguments. */
- if (!value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
+ /* If FN was prototyped at the call site, the value has been converted
+ already in convert_arguments.
+ However, we might see a prototype now that was not in place when
+ the function call was seen, so check that the VALUE actually matches
+ PARM before taking an early exit. */
+ if (!value
+ || (TYPE_ARG_TYPES (TREE_TYPE (fn))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (value)))))
return value;
type = TREE_TYPE (parm);
/* Store the expression if valid; else report error. */
- if (warn_traditional && !in_system_header
+ if (!in_system_header
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
- warning (0, "traditional C rejects automatic aggregate initialization");
+ warning (OPT_Wtraditional, "traditional C rejects automatic "
+ "aggregate initialization");
DECL_INITIAL (decl) = value;
if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
- tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+ tree cldecl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
- if (TYPE_DOMAIN (TREE_TYPE (decl)))
+ if (TYPE_DOMAIN (TREE_TYPE (cldecl)))
{
/* 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. */
- TYPE_DOMAIN (type) = TYPE_DOMAIN (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 (decl, 0);
+ layout_decl (cldecl, 0);
}
}
}
int kind;
union
{
- int i;
+ unsigned HOST_WIDE_INT i;
const char *s;
} u;
};
/* Push an array bounds on the stack. Printed as [BOUNDS]. */
static void
-push_array_bounds (int bounds)
+push_array_bounds (unsigned HOST_WIDE_INT bounds)
{
PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i);
}
for (p = spelling_base; p < spelling; p++)
if (p->kind == SPELLING_BOUNDS)
{
- sprintf (d, "[%d]", p->u.i);
+ sprintf (d, "[" HOST_WIDE_INT_PRINT_UNSIGNED "]", p->u.i);
d += strlen (d);
}
else
tree inside_init = init;
if (type == error_mark_node
+ || !init
|| init == error_mark_node
|| TREE_TYPE (init) == error_mark_node)
return error_mark_node;
if (TREE_CODE (inside_init) == CONSTRUCTOR)
{
- tree link;
+ unsigned HOST_WIDE_INT ix;
+ tree value;
+ bool constant_p = true;
/* Iterate through elements and check if all constructor
elements are *_CSTs. */
- for (link = CONSTRUCTOR_ELTS (inside_init);
- link;
- link = TREE_CHAIN (link))
- if (! CONSTANT_CLASS_P (TREE_VALUE (link)))
- break;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value)
+ if (!CONSTANT_CLASS_P (value))
+ {
+ constant_p = false;
+ break;
+ }
- if (link == NULL)
- return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+ if (constant_p)
+ return build_vector_from_ctor (type,
+ CONSTRUCTOR_ELTS (inside_init));
}
}
|| (code == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
- TREE_TYPE (type)))
- || (code == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE
- && comptypes (TREE_TYPE (inside_init),
TREE_TYPE (type)))))
{
if (code == POINTER_TYPE)
{
- inside_init = default_function_array_conversion (inside_init);
-
if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE)
{
- error_init ("invalid use of non-lvalue array");
- return error_mark_node;
+ if (TREE_CODE (inside_init) == STRING_CST
+ || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+ inside_init = array_to_pointer_conversion (inside_init);
+ else
+ {
+ error_init ("invalid use of non-lvalue array");
+ return error_mark_node;
+ }
}
- }
+ }
if (code == VECTOR_TYPE)
/* Although the types are compatible, we may require a
conversion. */
inside_init = convert (type, inside_init);
- if (require_constant && !flag_isoc99
+ if (require_constant
+ && (code == VECTOR_TYPE || !flag_isoc99)
&& TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
/* As an extension, allow initializing objects with static storage
duration with compound literals (which are then treated just as
- the brace enclosed list they contain). */
+ the brace enclosed list they contain). Also allow this for
+ vectors, as we can only assign them with compound literals. */
tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
inside_init = DECL_INITIAL (decl);
}
inside_init = error_mark_node;
}
+ /* Added to enable additional -Wmissing-format-attribute warnings. */
+ if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
+ inside_init = convert_for_assignment (type, inside_init, ic_init, NULL_TREE,
+ NULL_TREE, 0);
return inside_init;
}
|| code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
|| code == VECTOR_TYPE)
{
- /* Note that convert_for_assignment calls default_conversion
- for arrays and functions. We must not call it in the
- case where inside_init is a null pointer constant. */
+ if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
+ && (TREE_CODE (init) == STRING_CST
+ || TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
+ init = array_to_pointer_conversion (init);
inside_init
= convert_for_assignment (type, init, ic_init,
NULL_TREE, NULL_TREE, 0);
/* If we are saving up the elements rather than allocating them,
this is the list of elements so far (in reverse order,
most recent first). */
-static tree constructor_elements;
+static VEC(constructor_elt,gc) *constructor_elements;
/* 1 if constructor should be incrementally stored into a constructor chain,
0 if all the elements should be kept in AVL tree. */
static int designator_depth;
/* Nonzero if there were diagnosed errors in this designator list. */
-static int designator_errorneous;
+static int designator_erroneous;
\f
/* This stack has a level for each implicit or explicit level of
tree unfilled_index;
tree unfilled_fields;
tree bit_index;
- tree elements;
+ VEC(constructor_elt,gc) *elements;
struct init_node *pending_elts;
int offset;
int depth;
tree decl;
struct constructor_stack *constructor_stack;
struct constructor_range_stack *constructor_range_stack;
- tree elements;
+ VEC(constructor_elt,gc) *elements;
struct spelling *spelling;
struct spelling *spelling_base;
int spelling_size;
start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level)
{
const char *locus;
- struct initializer_stack *p = xmalloc (sizeof (struct initializer_stack));
+ struct initializer_stack *p = XNEW (struct initializer_stack);
p->decl = constructor_decl;
p->require_constant_value = require_constant_value;
constructor_incremental = 1;
constructor_designated = 0;
designator_depth = 0;
- designator_errorneous = 0;
+ designator_erroneous = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
/* 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, bitsize_zero_node);
+ constructor_index = bitsize_zero_node;
constructor_unfilled_index = constructor_index;
}
else
tree value = NULL_TREE;
/* If we've exhausted any levels that didn't have braces,
- pop them now. */
- while (constructor_stack->implicit)
+ pop them now. If implicit == 1, this will have been done in
+ process_init_element; do not repeat it here because in the case
+ of excess initializers for an empty aggregate this leads to an
+ infinite cycle of popping a level and immediately recreating
+ it. */
+ if (implicit != 1)
{
- if ((TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
- && constructor_fields == 0)
- process_init_element (pop_init_level (1));
- 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));
- else
- break;
+ while (constructor_stack->implicit)
+ {
+ if ((TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == UNION_TYPE)
+ && constructor_fields == 0)
+ process_init_element (pop_init_level (1));
+ 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));
+ else
+ break;
+ }
}
/* Unless this is an explicit brace, we need to preserve previous
p->range_stack = constructor_range_stack;
constructor_range_stack = 0;
designator_depth = 0;
- designator_errorneous = 0;
+ designator_erroneous = 0;
}
/* Don't die if an entire brace-pair level is superfluous
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
constructor_type = TREE_TYPE (constructor_type);
- push_array_bounds (tree_low_cst (constructor_index, 0));
+ push_array_bounds (tree_low_cst (constructor_index, 1));
constructor_depth++;
}
constructor_constant = TREE_CONSTANT (value);
constructor_simple = TREE_STATIC (value);
constructor_elements = CONSTRUCTOR_ELTS (value);
- if (constructor_elements
+ if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == ARRAY_TYPE))
set_nonincremental_init ();
else
{
gcc_assert (!TYPE_SIZE (constructor_type));
-
+
if (constructor_depth > 2)
error_init ("initialization of flexible array member in a nested context");
else if (pedantic)
{
/* A nonincremental scalar initializer--just return
the element, after verifying there is just one. */
- if (constructor_elements == 0)
+ if (VEC_empty (constructor_elt,constructor_elements))
{
if (!constructor_erroneous)
error_init ("empty scalar initializer");
ret.value = error_mark_node;
}
- else if (TREE_CHAIN (constructor_elements) != 0)
+ else if (VEC_length (constructor_elt,constructor_elements) != 1)
{
error_init ("extra elements in scalar initializer");
- ret.value = TREE_VALUE (constructor_elements);
+ ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
}
else
- ret.value = TREE_VALUE (constructor_elements);
+ ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
}
else
{
else
{
ret.value = build_constructor (constructor_type,
- nreverse (constructor_elements));
+ constructor_elements);
if (constructor_constant)
TREE_CONSTANT (ret.value) = TREE_INVARIANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
constructor_stack = p->next;
free (p);
- if (ret.value == 0)
- {
- if (constructor_stack == 0)
- {
- ret.value = error_mark_node;
- return ret;
- }
- return ret;
- }
+ if (ret.value == 0 && constructor_stack == 0)
+ ret.value = error_mark_node;
return ret;
}
/* If there were errors in this designator list already, bail out
silently. */
- if (designator_errorneous)
+ if (designator_erroneous)
return 1;
if (!designator_depth)
if (set_designator (1))
return;
- designator_errorneous = 1;
+ designator_erroneous = 1;
if (!INTEGRAL_TYPE_P (TREE_TYPE (first))
|| (last && !INTEGRAL_TYPE_P (TREE_TYPE (last))))
}
designator_depth++;
- designator_errorneous = 0;
+ designator_erroneous = 0;
if (constructor_range_stack || last)
push_range_stack (last);
}
if (set_designator (0))
return;
- designator_errorneous = 1;
+ designator_erroneous = 1;
if (TREE_CODE (constructor_type) != RECORD_TYPE
&& TREE_CODE (constructor_type) != UNION_TYPE)
{
constructor_fields = tail;
designator_depth++;
- designator_errorneous = 0;
+ designator_erroneous = 0;
if (constructor_range_stack)
push_range_stack (NULL_TREE);
}
{
if (TREE_SIDE_EFFECTS (p->value))
warning_init ("initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init ("initialized field overwritten");
p->value = value;
return;
}
{
if (TREE_SIDE_EFFECTS (p->value))
warning_init ("initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init ("initialized field overwritten");
p->value = value;
return;
}
static void
set_nonincremental_init (void)
{
- tree chain;
+ unsigned HOST_WIDE_INT ix;
+ tree index, value;
if (TREE_CODE (constructor_type) != RECORD_TYPE
&& TREE_CODE (constructor_type) != ARRAY_TYPE)
return;
- for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
- add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+ FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
+ add_pending_init (index, value);
constructor_elements = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
else if (bitpos == HOST_BITS_PER_WIDE_INT)
{
if (val[1] < 0)
- val[0] = -1;
+ val[0] = -1;
}
else if (val[0] & (((HOST_WIDE_INT) 1)
<< (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
}
else if (TREE_CODE (constructor_type) == UNION_TYPE)
{
- if (constructor_elements
- && TREE_PURPOSE (constructor_elements) == field)
- return TREE_VALUE (constructor_elements);
+ if (!VEC_empty (constructor_elt, constructor_elements)
+ && (VEC_last (constructor_elt, constructor_elements)->index
+ == field))
+ return VEC_last (constructor_elt, constructor_elements)->value;
}
return 0;
}
output_init_element (tree value, bool strict_string, tree type, tree field,
int pending)
{
+ constructor_elt *celt;
+
if (type == error_mark_node || value == error_mark_node)
{
constructor_erroneous = 1;
return;
}
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- && !(TREE_CODE (value) == STRING_CST
- && TREE_CODE (type) == ARRAY_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (type)))
- && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
- TYPE_MAIN_VARIANT (type))))
- value = default_conversion (value);
+ if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+ && (TREE_CODE (value) == STRING_CST
+ || TREE_CODE (value) == COMPOUND_LITERAL_EXPR)
+ && !(TREE_CODE (value) == STRING_CST
+ && TREE_CODE (type) == ARRAY_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+ && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
+ TYPE_MAIN_VARIANT (type)))
+ value = array_to_pointer_conversion (value);
if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
&& require_constant_value && !flag_isoc99 && pending)
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
- && constructor_elements)
+ && !VEC_empty (constructor_elt, constructor_elements))
{
- if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+ if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
+ constructor_elements)->value))
warning_init ("initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init ("initialized field overwritten");
/* We can have just one union field set. */
constructor_elements = 0;
/* Otherwise, output this element either to
constructor_elements or to the assembler file. */
- if (field && TREE_CODE (field) == INTEGER_CST)
- field = copy_node (field);
- constructor_elements
- = tree_cons (field, value, constructor_elements);
+ celt = VEC_safe_push (constructor_elt, gc, constructor_elements, NULL);
+ celt->index = field;
+ celt->value = value;
/* Advance the variable that indicates sequential elements output. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
bool strict_string = value.original_code == STRING_CST;
designator_depth = 0;
- designator_errorneous = 0;
+ designator_erroneous = 0;
/* Handle superfluous braces around string cst as in
char x[] = {"foo"}; */
&& integer_zerop (constructor_unfilled_index))
{
if (constructor_stack->replacement_value.value)
- error_init ("excess elements in char array initializer");
+ error_init ("excess elements in char array initializer");
constructor_stack->replacement_value = value;
return;
}
{
/* For a record, keep track of end position of last field. */
if (DECL_SIZE (constructor_fields))
- constructor_bit_index
+ constructor_bit_index
= size_binop (PLUS_EXPR,
- bit_position (constructor_fields),
- DECL_SIZE (constructor_fields));
+ bit_position (constructor_fields),
+ DECL_SIZE (constructor_fields));
/* If the current field was the first one not yet written out,
it isn't now, so update. */
again on the assumption that this must be conditional on
__STDC__ anyway (and we've already complained about the
member-designator already). */
- if (warn_traditional && !in_system_header && !constructor_designated
+ if (!in_system_header && !constructor_designated
&& !(value.value && (integer_zerop (value.value)
|| real_zerop (value.value))))
- warning (0, "traditional C rejects initialization of unions");
+ warning (OPT_Wtraditional, "traditional C rejects initialization "
+ "of unions");
/* Accept a string constant to initialize a subarray. */
if (value.value != 0
/* Now output the actual element. */
if (value.value)
{
- push_array_bounds (tree_low_cst (constructor_index, 0));
+ push_array_bounds (tree_low_cst (constructor_index, 1));
output_init_element (value.value, strict_string,
elttype, constructor_index, 1);
RESTORE_SPELLING_DEPTH (constructor_depth);
{
tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
- /* Do a basic check of initializer size. Note that vectors
- always have a fixed size derived from their type. */
+ /* Do a basic check of initializer size. Note that vectors
+ always have a fixed size derived from their type. */
if (tree_int_cst_lt (constructor_max_index, constructor_index))
{
pedwarn_init ("excess elements in vector initializer");
if (!lvalue_or_else (output, lv_asm))
output = error_mark_node;
+ if (output != error_mark_node
+ && (TREE_READONLY (output)
+ || TYPE_READONLY (TREE_TYPE (output))
+ || ((TREE_CODE (TREE_TYPE (output)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (output)) == UNION_TYPE)
+ && C_TYPE_FIELDS_READONLY (TREE_TYPE (output)))))
+ readonly_error (output, lv_asm);
+
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
oconstraints[i] = constraint;
output = error_mark_node;
}
else
- output = error_mark_node;
+ output = error_mark_node;
TREE_VALUE (tail) = output;
}
- /* Perform default conversions on array and function inputs.
- Don't do this for other types as it would screw up operands
- expected to be in memory. */
for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
{
tree input;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
input = TREE_VALUE (tail);
- input = default_function_array_conversion (input);
-
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
oconstraints, &allows_mem, &allows_reg))
{
args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
- /* Simple asm statements are treated as volatile. */
- if (simple)
- {
- ASM_VOLATILE_P (args) = 1;
- ASM_INPUT_P (args) = 1;
- }
+ /* asm statements without outputs, including simple ones, are treated
+ as volatile. */
+ ASM_INPUT_P (args) = simple;
+ ASM_VOLATILE_P (args) = (noutputs == 0);
return args;
}
tree
c_finish_return (tree retval)
{
- tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
+ tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt;
+ bool no_warning = false;
if (TREE_THIS_VOLATILE (current_function_decl))
warning (0, "function declared %<noreturn%> has a %<return%> statement");
current_function_returns_null = 1;
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
- pedwarn_c99 ("%<return%> with no value, in "
- "function returning non-void");
+ {
+ pedwarn_c99 ("%<return%> with no value, in "
+ "function returning non-void");
+ no_warning = true;
+ }
}
else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
{
inner = TREE_OPERAND (inner, 0);
while (REFERENCE_CLASS_P (inner)
- && TREE_CODE (inner) != INDIRECT_REF)
+ && TREE_CODE (inner) != INDIRECT_REF)
inner = TREE_OPERAND (inner, 0);
if (DECL_P (inner)
retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t);
}
- return add_stmt (build_stmt (RETURN_EXPR, retval));
+ ret_stmt = build_stmt (RETURN_EXPR, retval);
+ TREE_NO_WARNING (ret_stmt) |= no_warning;
+ return add_stmt (ret_stmt);
}
\f
struct c_switch {
tree
c_start_case (tree exp)
{
- enum tree_code code;
- tree type, orig_type = error_mark_node;
+ tree orig_type = error_mark_node;
struct c_switch *cs;
if (exp != error_mark_node)
{
- code = TREE_CODE (TREE_TYPE (exp));
orig_type = TREE_TYPE (exp);
- if (!INTEGRAL_TYPE_P (orig_type)
- && code != ERROR_MARK)
+ if (!INTEGRAL_TYPE_P (orig_type))
{
- error ("switch quantity not an integer");
+ if (orig_type != error_mark_node)
+ {
+ error ("switch quantity not an integer");
+ orig_type = error_mark_node;
+ }
exp = integer_zero_node;
- orig_type = error_mark_node;
}
else
{
- type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ tree type = TYPE_MAIN_VARIANT (orig_type);
- if (warn_traditional && !in_system_header
+ if (!in_system_header
&& (type == long_integer_type_node
|| type == long_unsigned_type_node))
- warning (0, "%<long%> switch expression not converted to "
- "%<int%> in ISO C");
+ warning (OPT_Wtraditional, "%<long%> switch expression not "
+ "converted to %<int%> in ISO C");
exp = default_conversion (exp);
- type = TREE_TYPE (exp);
}
}
found:
if (COND_EXPR_ELSE (inner_if))
- warning (0, "%Hsuggest explicit braces to avoid ambiguous %<else%>",
+ warning (OPT_Wparentheses,
+ "%Hsuggest explicit braces to avoid ambiguous %<else%>",
&if_locus);
}
- /* Diagnose ";" via the special empty statement node that we create. */
- if (extra_warnings)
- {
- if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
- {
- if (!else_block)
- warning (0, "%Hempty body in an if-statement",
- EXPR_LOCUS (then_block));
- then_block = alloc_stmt_list ();
- }
- if (else_block
- && TREE_CODE (else_block) == NOP_EXPR
- && !TREE_TYPE (else_block))
- {
- warning (0, "%Hempty body in an else-statement",
- EXPR_LOCUS (else_block));
- else_block = alloc_stmt_list ();
- }
- }
+ empty_body_warning (then_block, else_block);
- stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+ stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
SET_EXPR_LOCATION (stmt, if_locus);
add_stmt (stmt);
}
else
{
tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-
+
/* If we have an exit condition, then we build an IF with gotos either
- out of the loop, or to the top of it. If there's no exit condition,
- then we just build a jump back to the top. */
+ out of the loop, or to the top of it. If there's no exit condition,
+ then we just build a jump back to the top. */
exit = build_and_jump (&LABEL_EXPR_LABEL (top));
-
+
if (cond && !integer_nonzerop (cond))
- {
- /* Canonicalize the loop condition to the end. This means
- generating a branch to the loop condition. Reuse the
- continue label, if possible. */
- if (cond_is_first)
- {
- if (incr || !clab)
- {
- entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
- t = build_and_jump (&LABEL_EXPR_LABEL (entry));
- }
- else
- t = build1 (GOTO_EXPR, void_type_node, clab);
+ {
+ /* Canonicalize the loop condition to the end. This means
+ generating a branch to the loop condition. Reuse the
+ continue label, if possible. */
+ if (cond_is_first)
+ {
+ if (incr || !clab)
+ {
+ entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+ t = build_and_jump (&LABEL_EXPR_LABEL (entry));
+ }
+ else
+ t = build1 (GOTO_EXPR, void_type_node, clab);
SET_EXPR_LOCATION (t, start_locus);
- add_stmt (t);
- }
-
+ add_stmt (t);
+ }
+
t = build_and_jump (&blab);
- exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
- exit = fold (exit);
+ exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t);
if (cond_is_first)
- SET_EXPR_LOCATION (exit, start_locus);
+ SET_EXPR_LOCATION (exit, start_locus);
else
- SET_EXPR_LOCATION (exit, input_location);
- }
-
+ SET_EXPR_LOCATION (exit, input_location);
+ }
+
add_stmt (top);
}
-
+
if (body)
add_stmt (body);
if (clab)
if (!skip)
*label_p = label = create_artificial_label ();
}
- else if (TREE_CODE (label) != LABEL_DECL)
+ else if (TREE_CODE (label) == LABEL_DECL)
+ ;
+ else switch (TREE_INT_CST_LOW (label))
{
+ case 0:
if (is_break)
error ("break statement not within loop or switch");
else
- error ("continue statement not within a loop");
+ error ("continue statement not within a loop");
return NULL_TREE;
+
+ case 1:
+ gcc_assert (is_break);
+ error ("break statement used with OpenMP for loop");
+ return NULL_TREE;
+
+ default:
+ gcc_unreachable ();
}
if (skip)
if (!expr)
return NULL_TREE;
- /* Do default conversion if safe and possibly important,
- in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
- && (flag_isoc99 || lvalue_p (expr)))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
- expr = default_conversion (expr);
-
if (warn_sequence_point)
verify_sequence_points (expr);
if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
- if (EXPR_P (expr))
+ if (CAN_HAVE_LOCATION_P (expr))
SET_EXPR_LOCATION (expr, input_location);
return expr;
if (last == error_mark_node
|| (last == BIND_EXPR_BODY (body)
&& BIND_EXPR_VARS (body) == NULL))
- return last;
+ {
+ /* Do not warn if the return value of a statement expression is
+ unused. */
+ if (CAN_HAVE_LOCATION_P (last))
+ TREE_NO_WARNING (last) = 1;
+ return last;
+ }
/* Extract the type of said expression. */
type = TREE_TYPE (last);
struct c_label_list *glist;
gcc_assert (scope > 0);
+
+ /* At file_scope, we don't have to do any processing. */
+ if (label_context_stack_vm == NULL)
+ return;
+
if (c_switch_stack && !c_switch_stack->blocked_vm)
c_switch_stack->blocked_vm = scope;
for (glist = label_context_stack_vm->labels_used;
tree type0, type1;
enum tree_code code0, code1;
tree op0, op1;
+ const char *invalid_op_diag;
/* Expression code to give to the expression when it is built.
Normally this is CODE, which is what the caller asked for,
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
+ if ((invalid_op_diag
+ = targetm.invalid_binary_op (code, type0, type1)))
+ {
+ error (invalid_op_diag);
+ return error_mark_node;
+ }
+
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
switch (code)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
+ enum tree_code tcode0 = code0, tcode1 = code1;
+
if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
- code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+ tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
- code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+ tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
- if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+ if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
/* Although it would be tempting to shorten always here, that
{
/* op0 != orig_op0 detects the case of something
whose value is 0 but which isn't a valid null ptr const. */
- if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
+ if (pedantic && !null_pointer_constant_p (orig_op0)
&& TREE_CODE (tt1) == FUNCTION_TYPE)
pedwarn ("ISO C forbids comparison of %<void *%>"
" with function pointer");
}
else if (VOID_TYPE_P (tt1))
{
- if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
+ if (pedantic && !null_pointer_constant_p (orig_op1)
&& TREE_CODE (tt0) == FUNCTION_TYPE)
pedwarn ("ISO C forbids comparison of %<void *%>"
" with function pointer");
if (result_type == NULL_TREE)
result_type = ptr_type_node;
}
- else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
- && integer_zerop (op1))
- result_type = type0;
- else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
- result_type = type1;
+ else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
+ {
+ if (TREE_CODE (op0) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (op0, 0))
+ && (TREE_CODE (TREE_OPERAND (op0, 0)) == PARM_DECL
+ || TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
+ || !DECL_WEAK (TREE_OPERAND (op0, 0))))
+ warning (OPT_Walways_true, "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_P (TREE_OPERAND (op1, 0))
+ && (TREE_CODE (TREE_OPERAND (op1, 0)) == PARM_DECL
+ || TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL
+ || !DECL_WEAK (TREE_OPERAND (op1, 0))))
+ warning (OPT_Walways_true, "the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ result_type = type1;
+ }
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
pedwarn ("comparison of distinct pointer types lacks a cast");
}
}
- else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
- && integer_zerop (op1))
+ else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
{
result_type = type0;
if (pedantic || extra_warnings)
pedwarn ("ordered comparison of pointer with integer zero");
}
- else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
+ else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
{
result_type = type1;
if (pedantic)
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
+ || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
+ TREE_TYPE (type1))))
+ {
+ binary_op_error (code);
+ return error_mark_node;
+ }
+
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
|| code0 == VECTOR_TYPE)
&&
if (shorten && none_complex)
{
int unsigned0, unsigned1;
- tree arg0 = get_narrower (op0, &unsigned0);
- tree arg1 = get_narrower (op1, &unsigned1);
- /* UNS is 1 if the operation to be done is an unsigned one. */
- int uns = TYPE_UNSIGNED (result_type);
+ tree arg0, arg1;
+ int uns;
tree type;
+ /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents
+ excessive narrowing when we call get_narrower below. For
+ example, suppose that OP0 is of unsigned int extended
+ from signed char and that RESULT_TYPE is long long int.
+ If we explicitly cast OP0 to RESULT_TYPE, OP0 would look
+ like
+
+ (long long int) (unsigned int) signed_char
+
+ which get_narrower would narrow down to
+
+ (unsigned int) signed char
+
+ If we do not cast OP0 first, get_narrower would return
+ signed_char, which is inconsistent with the case of the
+ explicit cast. */
+ op0 = convert (result_type, op0);
+ op1 = convert (result_type, op1);
+
+ arg0 = get_narrower (op0, &unsigned0);
+ arg1 = get_narrower (op1, &unsigned1);
+
+ /* UNS is 1 if the operation to be done is an unsigned one. */
+ uns = TYPE_UNSIGNED (result_type);
+
final_type = result_type;
/* Handle the case that OP0 (or OP1) does not *contain* a conversion
&& (unsigned0 || !uns))
result_type
= c_common_signed_or_unsigned_type
- (unsigned0, c_common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
all the values of the unsigned type. */
if (!TYPE_UNSIGNED (result_type))
/* OK */;
- /* Do not warn if both operands are the same signedness. */
- else if (op0_signed == op1_signed)
- /* OK */;
+ /* Do not warn if both operands are the same signedness. */
+ else if (op0_signed == op1_signed)
+ /* OK */;
else
{
tree sop, uop;
if (!converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = convert_and_check (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = convert_and_check (result_type, op1);
/* This can happen if one operand has a vector type, and the other
has a different type. */
build_type = result_type;
{
- tree result = build2 (resultcode, build_type, op0, op1);
-
/* Treat expressions in initializers specially as they can't trap. */
- result = require_constant_value ? fold_initializer (result)
- : fold (result);
+ tree result = require_constant_value ? fold_build2_initializer (resultcode,
+ build_type,
+ op0, op1)
+ : fold_build2 (resultcode, build_type,
+ op0, op1);
if (final_type != 0)
result = convert (final_type, result);
/* Convert EXPR to be a truth-value, validating its type for this
- purpose. Passes EXPR to default_function_array_conversion. */
+ purpose. */
tree
c_objc_common_truthvalue_conversion (tree expr)
{
- expr = default_function_array_conversion (expr);
switch (TREE_CODE (TREE_TYPE (expr)))
{
case ARRAY_TYPE:
error ("used union type value where scalar is required");
return error_mark_node;
+ case FUNCTION_TYPE:
+ gcc_unreachable ();
+
default:
break;
}
leaving those to give errors later? */
return c_common_truthvalue_conversion (expr);
}
+\f
+
+/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as
+ required. */
+
+tree
+c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED,
+ bool *ti ATTRIBUTE_UNUSED, bool *se)
+{
+ if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR)
+ {
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (expr);
+ /* Executing a compound literal inside a function reinitializes
+ it. */
+ if (!TREE_STATIC (decl))
+ *se = true;
+ return decl;
+ }
+ else
+ return expr;
+}
+\f
+/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */
+
+tree
+c_begin_omp_parallel (void)
+{
+ tree block;
+
+ keep_next_level ();
+ block = c_begin_compound_stmt (true);
+
+ return block;
+}
+
+tree
+c_finish_omp_parallel (tree clauses, tree block)
+{
+ tree stmt;
+
+ block = c_end_compound_stmt (block, true);
+
+ stmt = make_node (OMP_PARALLEL);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_PARALLEL_CLAUSES (stmt) = clauses;
+ OMP_PARALLEL_BODY (stmt) = block;
+
+ return add_stmt (stmt);
+}
+
+/* For all elements of CLAUSES, validate them vs OpenMP constraints.
+ Remove any elements from the list that are invalid. */
+
+tree
+c_finish_omp_clauses (tree clauses)
+{
+ bitmap_head generic_head, firstprivate_head, lastprivate_head;
+ tree c, t, *pc = &clauses;
+ const char *name;
+
+ bitmap_obstack_initialize (NULL);
+ bitmap_initialize (&generic_head, &bitmap_default_obstack);
+ bitmap_initialize (&firstprivate_head, &bitmap_default_obstack);
+ bitmap_initialize (&lastprivate_head, &bitmap_default_obstack);
+
+ for (pc = &clauses, c = clauses; c ; c = *pc)
+ {
+ bool remove = false;
+ bool need_complete = false;
+ bool need_implicitly_determined = false;
+
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_SHARED:
+ name = "shared";
+ need_implicitly_determined = true;
+ goto check_dup_generic;
+
+ case OMP_CLAUSE_PRIVATE:
+ name = "private";
+ need_complete = true;
+ need_implicitly_determined = true;
+ goto check_dup_generic;
+
+ case OMP_CLAUSE_REDUCTION:
+ name = "reduction";
+ need_implicitly_determined = true;
+ t = OMP_CLAUSE_DECL (c);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (t))
+ || POINTER_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%qE has invalid type for %<reduction%>", t);
+ remove = true;
+ }
+ else if (FLOAT_TYPE_P (TREE_TYPE (t)))
+ {
+ enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
+ const char *r_name = NULL;
+
+ switch (r_code)
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MINUS_EXPR:
+ break;
+ case BIT_AND_EXPR:
+ r_name = "&";
+ break;
+ case BIT_XOR_EXPR:
+ r_name = "^";
+ break;
+ case BIT_IOR_EXPR:
+ r_name = "|";
+ break;
+ case TRUTH_ANDIF_EXPR:
+ r_name = "&&";
+ break;
+ case TRUTH_ORIF_EXPR:
+ r_name = "||";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (r_name)
+ {
+ error ("%qE has invalid type for %<reduction(%s)%>",
+ t, r_name);
+ remove = true;
+ }
+ }
+ goto check_dup_generic;
+
+ case OMP_CLAUSE_COPYPRIVATE:
+ name = "copyprivate";
+ goto check_dup_generic;
+
+ case OMP_CLAUSE_COPYIN:
+ name = "copyin";
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
+ {
+ error ("%qE must be %<threadprivate%> for %<copyin%>", t);
+ remove = true;
+ }
+ goto check_dup_generic;
+
+ check_dup_generic:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error ("%qE is not a variable in clause %qs", t, name);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+ || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+ || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+ {
+ error ("%qE appears more than once in data clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&generic_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_FIRSTPRIVATE:
+ name = "firstprivate";
+ t = OMP_CLAUSE_DECL (c);
+ need_complete = true;
+ need_implicitly_determined = true;
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error ("%qE is not a variable in clause %<firstprivate%>", t);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+ || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+ {
+ error ("%qE appears more than once in data clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&firstprivate_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_LASTPRIVATE:
+ name = "lastprivate";
+ t = OMP_CLAUSE_DECL (c);
+ need_complete = true;
+ need_implicitly_determined = true;
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ error ("%qE is not a variable in clause %<lastprivate%>", t);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+ || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+ {
+ error ("%qE appears more than once in data clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&lastprivate_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_IF:
+ case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_SCHEDULE:
+ case OMP_CLAUSE_NOWAIT:
+ case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_DEFAULT:
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!remove)
+ {
+ t = OMP_CLAUSE_DECL (c);
+
+ if (need_complete)
+ {
+ t = require_complete_type (t);
+ if (t == error_mark_node)
+ remove = true;
+ }
+
+ if (need_implicitly_determined)
+ {
+ const char *share_name = NULL;
+
+ if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+ share_name = "threadprivate";
+ else switch (c_omp_predetermined_sharing (t))
+ {
+ case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+ break;
+ case OMP_CLAUSE_DEFAULT_SHARED:
+ share_name = "shared";
+ break;
+ case OMP_CLAUSE_DEFAULT_PRIVATE:
+ share_name = "private";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (share_name)
+ {
+ error ("%qE is predetermined %qs for %qs",
+ t, share_name, name);
+ remove = true;
+ }
+ }
+ }
+
+ if (remove)
+ *pc = OMP_CLAUSE_CHAIN (c);
+ else
+ pc = &OMP_CLAUSE_CHAIN (c);
+ }
+
+ bitmap_obstack_release (NULL);
+ return clauses;
+}