/* 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 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "rtl.h"
#include "tree.h"
+#include "langhooks.h"
#include "c-tree.h"
#include "tm_p.h"
#include "flags.h"
static int missing_braces_mentioned;
static tree qualify_type (tree, tree);
-static int same_translation_unit_p (tree, tree);
static int tagged_types_tu_compatible_p (tree, tree, int);
static int comp_target_types (tree, tree, int);
static int function_types_compatible_p (tree, tree, int);
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
-static tree unary_complex_lvalue (enum tree_code, tree, int);
-static void pedantic_lvalue_warning (enum tree_code);
static tree internal_build_compound_expr (tree, int);
static tree convert_for_assignment (tree, tree, const char *, tree, tree,
int);
if (c_promoting_integer_type_p (type))
{
/* Preserve unsignedness if not really getting any wider. */
- if (TREE_UNSIGNED (type)
+ if (TYPE_UNSIGNED (type)
&& (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
return unsigned_type_node;
return integer_type_node;
TYPE_QUALS (type) | TYPE_QUALS (like));
}
\f
-/* Return the common type of two types.
- We assume that comptypes has already been done and returned 1;
- if that isn't so, this may crash. In particular, we assume that qualifiers
- match.
+/* Return the composite type of two compatible types.
- This is the type for the result of most arithmetic operations
- if the operands have the given two types. */
+ We assume that comptypes has already been done and returned
+ nonzero; if that isn't so, this may crash. In particular, we
+ assume that qualifiers match. */
tree
-common_type (tree t1, tree t2)
+composite_type (tree t1, tree t2)
{
enum tree_code code1;
enum tree_code code2;
if (t2 == error_mark_node)
return t1;
- /* Merge the attributes. */
- attributes = (*targetm.merge_type_attributes) (t1, t2);
-
- /* Treat an enum type as the unsigned integer type of the same width. */
-
- if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
- if (TREE_CODE (t2) == ENUMERAL_TYPE)
- t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
-
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
- /* If one type is complex, form the common type of the non-complex
- components, then make that complex. Use T1 or T2 if it is the
- required type. */
- if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
- {
- tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
- tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
- tree subtype = common_type (subtype1, subtype2);
-
- if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
- return build_type_attribute_variant (t1, attributes);
- else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
- return build_type_attribute_variant (t2, attributes);
- else
- return build_type_attribute_variant (build_complex_type (subtype),
- attributes);
- }
-
- switch (code1)
- {
- case INTEGER_TYPE:
- case REAL_TYPE:
- /* If only one is real, use it as the result. */
-
- if (code1 == REAL_TYPE && code2 != REAL_TYPE)
- return build_type_attribute_variant (t1, attributes);
-
- if (code2 == REAL_TYPE && code1 != REAL_TYPE)
- return build_type_attribute_variant (t2, attributes);
-
- /* Both real or both integers; use the one with greater precision. */
-
- if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
- return build_type_attribute_variant (t1, attributes);
- else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
- return build_type_attribute_variant (t2, attributes);
-
- /* Same precision. Prefer longs to ints even when same size. */
-
- if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
- || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
- return build_type_attribute_variant (long_unsigned_type_node,
- attributes);
-
- if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
- || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
- {
- /* But preserve unsignedness from the other type,
- since long cannot hold all the values of an unsigned int. */
- if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
- t1 = long_unsigned_type_node;
- else
- t1 = long_integer_type_node;
- return build_type_attribute_variant (t1, attributes);
- }
+ /* Merge the attributes. */
+ attributes = targetm.merge_type_attributes (t1, t2);
- /* Likewise, prefer long double to double even if same size. */
- if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
- || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
- return build_type_attribute_variant (long_double_type_node,
- attributes);
+ /* If one is an enumerated type and the other is the compatible
+ integer type, the composite type might be either of the two
+ (DR#013 question 3). For consistency, use the enumerated type as
+ the composite type. */
- /* Otherwise prefer the unsigned one. */
+ if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE)
+ return t1;
+ if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE)
+ return t2;
- if (TREE_UNSIGNED (t1))
- return build_type_attribute_variant (t1, attributes);
- else
- return build_type_attribute_variant (t2, attributes);
+ if (code1 != code2)
+ abort ();
+ switch (code1)
+ {
case POINTER_TYPE:
- /* For two pointers, do this recursively on the target type,
- and combine the qualifiers of the two types' targets. */
- /* This code was turned off; I don't know why.
- But ANSI C specifies doing this with the qualifiers.
- So I turned it on again. */
+ /* For two pointers, do this recursively on the target type. */
{
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
- tree target = common_type (TYPE_MAIN_VARIANT (pointed_to_1),
- TYPE_MAIN_VARIANT (pointed_to_2));
- t1 = build_pointer_type (c_build_qualified_type
- (target,
- TYPE_QUALS (pointed_to_1) |
- TYPE_QUALS (pointed_to_2)));
+ tree target = composite_type (pointed_to_1, pointed_to_2);
+ t1 = build_pointer_type (target);
return build_type_attribute_variant (t1, attributes);
}
case ARRAY_TYPE:
{
- tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+ tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
/* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
return build_type_attribute_variant (t1, attributes);
/* Function types: prefer the one that specified arg types.
If both do, merge the arg types. Also merge the return types. */
{
- tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+ tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
tree p1 = TYPE_ARG_TYPES (t1);
tree p2 = TYPE_ARG_TYPES (t2);
int len;
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
-
- pushlevel (0);
- declare_parm_level ();
+ /* Tell global_bindings_p to return false so that variable_size
+ doesn't abort on VLAs in parameter types. */
+ c_override_global_bindings_to_false = true;
len = list_length (p1);
newargs = 0;
tree memb;
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2),
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2),
COMPARE_STRICT))
{
TREE_VALUE (n) = TREE_VALUE (p2);
tree memb;
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1),
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1),
COMPARE_STRICT))
{
TREE_VALUE (n) = TREE_VALUE (p1);
goto parm_done;
}
}
- TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2));
+ TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
parm_done: ;
}
- poplevel (0, 0, 0);
-
+ c_override_global_bindings_to_false = false;
t1 = build_function_type (valtype, newargs);
/* ... falls through ... */
}
}
}
+
+/* Return the type of a conditional expression between pointers to
+ possibly differently qualified versions of compatible types.
+
+ We assume that comp_target_types has already been done and returned
+ nonzero; if that isn't so, this may crash. */
+
+static tree
+common_pointer_type (tree t1, tree t2)
+{
+ tree attributes;
+ tree pointed_to_1;
+ tree pointed_to_2;
+ tree target;
+
+ /* Save time if the two types are the same. */
+
+ if (t1 == t2) return t1;
+
+ /* If one type is nonsense, use the other. */
+ if (t1 == error_mark_node)
+ return t2;
+ if (t2 == error_mark_node)
+ return t1;
+
+ if (TREE_CODE (t1) != POINTER_TYPE || TREE_CODE (t2) != POINTER_TYPE)
+ abort ();
+
+ /* Merge the attributes. */
+ attributes = targetm.merge_type_attributes (t1, t2);
+
+ /* Find the composite type of the target types, and combine the
+ qualifiers of the two types' targets. */
+ pointed_to_1 = TREE_TYPE (t1);
+ pointed_to_2 = TREE_TYPE (t2);
+ target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
+ TYPE_MAIN_VARIANT (pointed_to_2));
+ t1 = build_pointer_type (c_build_qualified_type
+ (target,
+ TYPE_QUALS (pointed_to_1) |
+ TYPE_QUALS (pointed_to_2)));
+ return build_type_attribute_variant (t1, attributes);
+}
+
+/* Return the common type for two arithmetic types under the usual
+ arithmetic conversions. The default conversions have already been
+ applied, and enumerated types converted to their compatible integer
+ types. The resulting type is unqualified and has no attributes.
+
+ This is the type for the result of most arithmetic operations
+ if the operands have the given two types. */
+
+tree
+common_type (tree t1, tree t2)
+{
+ enum tree_code code1;
+ enum tree_code code2;
+
+ /* If one type is nonsense, use the other. */
+ if (t1 == error_mark_node)
+ return t2;
+ if (t2 == error_mark_node)
+ return t1;
+
+ if (TYPE_QUALS (t1) != TYPE_UNQUALIFIED)
+ t1 = TYPE_MAIN_VARIANT (t1);
+
+ if (TYPE_QUALS (t2) != TYPE_UNQUALIFIED)
+ t2 = TYPE_MAIN_VARIANT (t2);
+
+ if (TYPE_ATTRIBUTES (t1) != NULL_TREE)
+ t1 = build_type_attribute_variant (t1, NULL_TREE);
+
+ if (TYPE_ATTRIBUTES (t2) != NULL_TREE)
+ t2 = build_type_attribute_variant (t2, NULL_TREE);
+
+ /* Save time if the two types are the same. */
+
+ if (t1 == t2) return t1;
+
+ code1 = TREE_CODE (t1);
+ code2 = TREE_CODE (t2);
+
+ if (code1 != VECTOR_TYPE && code1 != COMPLEX_TYPE
+ && code1 != REAL_TYPE && code1 != INTEGER_TYPE)
+ abort ();
+
+ if (code2 != VECTOR_TYPE && code2 != COMPLEX_TYPE
+ && code2 != REAL_TYPE && code2 != INTEGER_TYPE)
+ abort ();
+
+ /* 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 (code1 == VECTOR_TYPE)
+ return t1;
+
+ if (code2 == VECTOR_TYPE)
+ return t2;
+
+ /* If one type is complex, form the common type of the non-complex
+ components, then make that complex. Use T1 or T2 if it is the
+ required type. */
+ if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+ {
+ tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+ tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+ tree subtype = common_type (subtype1, subtype2);
+
+ if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+ return t1;
+ else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+ return t2;
+ else
+ return build_complex_type (subtype);
+ }
+
+ /* If only one is real, use it as the result. */
+
+ if (code1 == REAL_TYPE && code2 != REAL_TYPE)
+ return t1;
+
+ if (code2 == REAL_TYPE && code1 != REAL_TYPE)
+ return t2;
+
+ /* Both real or both integers; use the one with greater precision. */
+
+ if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+ return t1;
+ else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+ return t2;
+
+ /* Same precision. Prefer long longs to longs to ints when the
+ same precision, following the C99 rules on integer type rank
+ (which are equivalent to the C90 rules for C90 types). */
+
+ if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node)
+ return long_long_unsigned_type_node;
+
+ if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node)
+ {
+ if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
+ return long_long_unsigned_type_node;
+ else
+ return long_long_integer_type_node;
+ }
+
+ if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
+ return long_unsigned_type_node;
+
+ if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
+ {
+ /* But preserve unsignedness from the other type,
+ since long cannot hold all the values of an unsigned int. */
+ if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
+ return long_unsigned_type_node;
+ else
+ return long_integer_type_node;
+ }
+
+ /* Likewise, prefer long double to double even if same size. */
+ if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
+ return long_double_type_node;
+
+ /* Otherwise prefer the unsigned one. */
+
+ if (TYPE_UNSIGNED (t1))
+ return t1;
+ else
+ return t2;
+}
\f
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
/* If either type is the internal version of sizetype, return the
language version. */
if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
- && TYPE_DOMAIN (t1) != 0)
- t1 = TYPE_DOMAIN (t1);
+ && TYPE_ORIG_SIZE_TYPE (t1))
+ t1 = TYPE_ORIG_SIZE_TYPE (t1);
if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
- && TYPE_DOMAIN (t2) != 0)
- t2 = TYPE_DOMAIN (t2);
+ && TYPE_ORIG_SIZE_TYPE (t2))
+ t2 = TYPE_ORIG_SIZE_TYPE (t2);
- /* Treat an enum type as the integer type of the same width and
- signedness. */
- if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = c_common_type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
- if (TREE_CODE (t2) == ENUMERAL_TYPE)
- t2 = c_common_type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2));
+ /* Enumerated types are compatible with integer types, but this is
+ not transitive: two enumerated types in the same translation unit
+ are compatible with each other only if they are the same type. */
+
+ if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
+ t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
+ else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE)
+ t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
if (t1 == t2)
return 1;
/* Different classes of types can't be compatible. */
- if (TREE_CODE (t1) != TREE_CODE (t2)) return 0;
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
/* Qualifiers must match. */
return 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- if (! (attrval = (*targetm.comp_type_attributes) (t1, t2)))
+ if (! (attrval = targetm.comp_type_attributes (t1, t2)))
return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
break;
case VECTOR_TYPE:
- /* The target might allow certain vector types to be compatible. */
- val = (*targetm.vector_opaque_p) (t1)
- || (*targetm.vector_opaque_p) (t2);
+ val = TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
+ && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), 0);
break;
default:
\f
/* Subroutines of `comptypes'. */
-/* Determine whether two types derive from the same translation unit.
- If the CONTEXT chain ends in a null, that type's context is still
- being parsed, so if two types have context chains ending in null,
+/* Determine whether two trees derive from the same translation unit.
+ If the CONTEXT chain ends in a null, that tree's context is still
+ being parsed, so if two trees have context chains ending in null,
they're in the same translation unit. */
-static int
+int
same_translation_unit_p (tree t1, tree t2)
{
while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
{
case 'd': t1 = DECL_CONTEXT (t1); break;
case 't': t1 = TYPE_CONTEXT (t1); break;
- case 'b': t1 = BLOCK_SUPERCONTEXT (t1); break;
+ case 'x': t1 = BLOCK_SUPERCONTEXT (t1); break; /* assume block */
default: abort ();
}
while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t2)))
{
- case 'd': t2 = DECL_CONTEXT (t1); break;
+ case 'd': t2 = DECL_CONTEXT (t2); break;
case 't': t2 = TYPE_CONTEXT (t2); break;
- case 'b': t2 = BLOCK_SUPERCONTEXT (t2); break;
+ case 'x': t2 = BLOCK_SUPERCONTEXT (t2); break; /* assume block */
default: abort ();
}
{
tree s1, s2;
bool needs_warning = false;
-
+
/* We have to verify that the tags of the types are the same. This
is harder than it looks because this may be a typedef, so we have
to go look at the original type. It may even be a typedef of a
- typedef... */
- while (TYPE_NAME (t1) && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL)
+ typedef...
+ In the case of compiler-created builtin structs the TYPE_DECL
+ may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */
+ while (TYPE_NAME (t1)
+ && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (t1)))
t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1));
- while (TYPE_NAME (t2) && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL)
+ while (TYPE_NAME (t2)
+ && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (t2)))
t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
/* C90 didn't have the requirement that the two tags be the same. */
if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2))
return 0;
-
+
/* C90 didn't say what happened if one or both of the types were
incomplete; we choose to follow C99 rules here, which is that they
are compatible. */
if (TYPE_SIZE (t1) == NULL
|| TYPE_SIZE (t2) == NULL)
return 1;
-
+
{
const struct tagged_tu_seen * 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;
}
-
+
switch (TREE_CODE (t1))
{
case ENUMERAL_TYPE:
{
+
+ /* 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;
+
+ 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;
+ }
+
+ if (tv1 == NULL_TREE && tv2 == NULL_TREE)
+ return 1;
+ if (tv1 == NULL_TREE || tv2 == NULL_TREE)
+ return 0;
+
if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
return 0;
-
+
for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
{
s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
tts.t1 = t1;
tts.t2 = t2;
tagged_tu_seen_base = &tts;
-
+
if (DECL_NAME (s1) != NULL)
for (s2 = TYPE_VALUES (t2); s2; s2 = TREE_CHAIN (s2))
if (DECL_NAME (s1) == DECL_NAME (s2))
break;
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)
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;
-
- for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
+
+ for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
s1 && s2;
s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
{
break;
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)
decl_constant_value (tree decl)
{
if (/* Don't change a variable array bound or initial value to a constant
- in a place where a variable is invalid. */
+ in a place where a variable is invalid. Note that DECL_INITIAL
+ isn't valid for a PARM_DECL. */
current_function_decl != 0
+ && TREE_CODE (decl) != PARM_DECL
&& ! TREE_THIS_VOLATILE (decl)
&& TREE_READONLY (decl)
&& DECL_INITIAL (decl) != 0
adr = build1 (ADDR_EXPR, ptrtype, exp);
if (!c_mark_addressable (exp))
return error_mark_node;
- TREE_CONSTANT (adr) = staticp (exp);
TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
return adr;
}
TYPE_PRECISION (integer_type_node)),
((TYPE_PRECISION (type)
>= TYPE_PRECISION (integer_type_node))
- && TREE_UNSIGNED (type)));
+ && TYPE_UNSIGNED (type)));
return convert (type, exp);
}
if (c_promoting_integer_type_p (type))
{
/* Preserve unsignedness if not really getting any wider. */
- if (TREE_UNSIGNED (type)
+ if (TYPE_UNSIGNED (type)
&& TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
return convert (unsigned_type_node, exp);
tree field = NULL;
tree ref;
+ if (!objc_is_public (datum, component))
+ return error_mark_node;
+
/* If DATUM is a COMPOUND_EXPR, move our reference inside it.
- If pedantic ensure that the arguments are not lvalues; otherwise,
+ Ensure that the arguments are not lvalues; otherwise,
if the component is an array, it would wrongly decay to a pointer in
C89 mode.
We cannot do this with a COND_EXPR, because in a conditional expression
{
tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
return build (COMPOUND_EXPR, TREE_TYPE (value),
- TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
+ TREE_OPERAND (datum, 0), non_lvalue (value));
}
default:
break;
|| TREE_TYPE (index) == error_mark_node)
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
- && TREE_CODE (array) != INDIRECT_REF)
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
{
tree rval, type;
would get a crash in store_bit_field/extract_bit_field when trying
to access a non-existent part of the register. */
if (TREE_CODE (index) == INTEGER_CST
- && TYPE_VALUES (TREE_TYPE (array))
- && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array))))
+ && TYPE_DOMAIN (TREE_TYPE (array))
+ && ! int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
{
if (!c_mark_addressable (array))
return error_mark_node;
tree foo = array;
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
- if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
+ if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
pedwarn ("ISO C forbids subscripting `register' array");
else if (! flag_isoc99 && ! lvalue_p (foo))
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
{
ref = DECL_INITIAL (ref);
TREE_CONSTANT (ref) = 1;
+ TREE_INVARIANT (ref) = 1;
}
else if (current_function_decl != 0
&& !DECL_FILE_SCOPE_P (current_function_decl)
executions of the program must execute the code. */
warning ("function called through a non-compatible type");
+ /* We can, however, treat "undefined" any way we please.
+ Call abort to encourage the user to fix the program. */
+ inform ("if this code is reached, the program will abort");
+
if (VOID_TYPE_P (return_type))
return trap;
else
;
else if (formal_prec != TYPE_PRECISION (type1))
warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1);
- else if (TREE_UNSIGNED (type) == TREE_UNSIGNED (type1))
+ else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
;
/* Don't complain if the formal parameter type
is an enum, because we can't tell now whether
pass it as signed or unsigned; the value
certainly is the same either way. */
else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type)
- && TREE_UNSIGNED (TREE_TYPE (val)))
+ && TYPE_UNSIGNED (TREE_TYPE (val)))
;
- else if (TREE_UNSIGNED (type))
+ else if (TYPE_UNSIGNED (type))
warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1);
else
warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1);
C_SET_EXP_ORIGINAL_CODE (result, code);
else
{
- int flag = TREE_CONSTANT (result);
/* We used to use NOP_EXPR rather than NON_LVALUE_EXPR
so that convert_for_assignment wouldn't strip it.
That way, we got warnings for things like p = (1 - 1).
But it turns out we should not get those warnings. */
result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result);
C_SET_EXP_ORIGINAL_CODE (result, code);
- TREE_CONSTANT (result) = flag;
}
return result;
static tree
pointer_diff (tree op0, tree op1)
{
- tree result, folded;
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (TREE_TYPE (op0));
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
-
- result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
-
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
- return folded;
+ return fold (build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)));
}
\f
/* Construct and perhaps optimize a tree representation
error ("wrong type argument to unary exclamation mark");
return error_mark_node;
}
- arg = c_common_truthvalue_conversion (arg);
+ arg = lang_hooks.truthvalue_conversion (arg);
return invert_truthvalue (arg);
case NOP_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
- /* Handle complex lvalues (when permitted)
- by reduction to simpler cases. */
-
- val = unary_complex_lvalue (code, arg, 0);
- if (val != 0)
- return val;
/* Increment or decrement the real part of the value,
and don't change the imaginary part. */
inc = convert (argtype, inc);
- /* Handle incrementing a cast-expression. */
-
- while (1)
- switch (TREE_CODE (arg))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
- pedantic_lvalue_warning (CONVERT_EXPR);
- /* If the real type has the same machine representation
- as the type it is cast to, we can make better output
- by adding directly to the inside of the cast. */
- if ((TREE_CODE (TREE_TYPE (arg))
- == TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))))
- && (TYPE_MODE (TREE_TYPE (arg))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg, 0)))))
- arg = TREE_OPERAND (arg, 0);
- else
- {
- tree incremented, modify, value;
- if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
- value = boolean_increment (code, arg);
- else
- {
- arg = stabilize_reference (arg);
- if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
- value = arg;
- else
- value = save_expr (arg);
- incremented = build (((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? PLUS_EXPR : MINUS_EXPR),
- argtype, value, inc);
- TREE_SIDE_EFFECTS (incremented) = 1;
- modify = build_modify_expr (arg, NOP_EXPR, incremented);
- value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
- }
- TREE_USED (value) = 1;
- return value;
- }
- break;
-
- default:
- goto give_up;
- }
- give_up:
-
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
- readonly_warning (arg,
- ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"));
+ readonly_error (arg,
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
TREE_SIDE_EFFECTS (val) = 1;
val = convert (result_type, val);
if (TREE_CODE (val) != code)
- TREE_NO_UNUSED_WARNING (val) = 1;
+ TREE_NO_WARNING (val) = 1;
return val;
}
TREE_OPERAND (arg, 1), 1);
}
- /* Handle complex lvalues (when permitted)
- by reduction to simpler cases. */
- val = unary_complex_lvalue (code, arg, flag);
- if (val != 0)
- return val;
-
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
else
addr = build1 (code, argtype, arg);
- /* Address of a static or external variable or
- file-scope function counts as a constant. */
- if (staticp (arg)
- && ! (TREE_CODE (arg) == FUNCTION_DECL
- && !DECL_FILE_SCOPE_P (arg)))
- TREE_CONSTANT (addr) = 1;
return addr;
}
/* Return nonzero if REF is an lvalue valid for this language.
Lvalues can be assigned, unless their type has TYPE_READONLY.
- Lvalues can have their address taken, unless they have DECL_REGISTER. */
+ Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
int
lvalue_p (tree ref)
return win;
}
-/* Apply unary lvalue-demanding operator CODE to the expression ARG
- for certain kinds of expressions which are not really lvalues
- but which we can accept as lvalues. If FLAG is nonzero, then
- non-lvalues are OK since we may be converting a non-lvalue array to
- a pointer in C99.
-
- If ARG is not a kind of expression we can handle, return zero. */
-
-static tree
-unary_complex_lvalue (enum tree_code code, tree arg, int flag)
-{
- /* Handle (a, b) used as an "lvalue". */
- if (TREE_CODE (arg) == COMPOUND_EXPR)
- {
- tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
-
- /* If this returns a function type, it isn't really being used as
- an lvalue, so don't issue a warning about it. */
- if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
- pedantic_lvalue_warning (COMPOUND_EXPR);
-
- return build (COMPOUND_EXPR, TREE_TYPE (real_result),
- TREE_OPERAND (arg, 0), real_result);
- }
-
- /* Handle (a ? b : c) used as an "lvalue". */
- if (TREE_CODE (arg) == COND_EXPR)
- {
- if (!flag)
- pedantic_lvalue_warning (COND_EXPR);
- if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
- pedantic_lvalue_warning (COMPOUND_EXPR);
-
- return (build_conditional_expr
- (TREE_OPERAND (arg, 0),
- build_unary_op (code, TREE_OPERAND (arg, 1), flag),
- build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
- }
-
- return 0;
-}
-
-/* If pedantic, warn about improper lvalue. CODE is either COND_EXPR
- COMPOUND_EXPR, or CONVERT_EXPR (for casts). */
-
-static void
-pedantic_lvalue_warning (enum tree_code code)
-{
- switch (code)
- {
- case COND_EXPR:
- pedwarn ("use of conditional expressions as lvalues is deprecated");
- break;
- case COMPOUND_EXPR:
- pedwarn ("use of compound expressions as lvalues is deprecated");
- break;
- default:
- pedwarn ("use of cast expressions as lvalues is deprecated");
- break;
- }
-}
\f
/* Warn about storing in something that is `const'. */
void
-readonly_warning (tree arg, const char *msgid)
+readonly_error (tree arg, const char *msgid)
{
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- readonly_warning (TREE_OPERAND (arg, 0), msgid);
+ readonly_error (TREE_OPERAND (arg, 0), msgid);
else
- pedwarn ("%s of read-only member `%s'", _(msgid),
- IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
+ error ("%s of read-only member `%s'", _(msgid),
+ IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
}
else if (TREE_CODE (arg) == VAR_DECL)
- pedwarn ("%s of read-only variable `%s'", _(msgid),
- IDENTIFIER_POINTER (DECL_NAME (arg)));
+ error ("%s of read-only variable `%s'", _(msgid),
+ IDENTIFIER_POINTER (DECL_NAME (arg)));
else
- pedwarn ("%s of read-only location", _(msgid));
+ error ("%s of read-only location", _(msgid));
}
\f
/* Mark EXP saying that we need to be able to take the
case CONST_DECL:
case PARM_DECL:
case RESULT_DECL:
- if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+ if (C_DECL_REGISTER (x)
&& DECL_NONLOCAL (x))
{
- if (TREE_PUBLIC (x))
+ if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
{
error ("global register variable `%s' used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
pedwarn ("register variable `%s' used in nested function",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
- else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x))
+ else if (C_DECL_REGISTER (x))
{
- if (TREE_PUBLIC (x))
+ if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
{
error ("address of global register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
return false;
}
- /* If we are making this addressable due to its having
- volatile components, give a different error message. Also
- handle the case of an unnamed parameter by not trying
- to give the name. */
-
- else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
- {
- error ("cannot put object with volatile field into register");
- return false;
- }
-
pedwarn ("address of register variable `%s' requested",
IDENTIFIER_POINTER (DECL_NAME (x)));
}
tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
- ifexp = c_common_truthvalue_conversion (default_conversion (ifexp));
+ ifexp = lang_hooks.truthvalue_conversion (default_conversion (ifexp));
/* Promote both alternatives. */
type2 = TREE_TYPE (op2);
code2 = TREE_CODE (type2);
+ /* C90 does not permit non-lvalue arrays in conditional expressions.
+ In C99 they will be pointers by now. */
+ if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE)
+ {
+ error ("non-lvalue array in conditional expression");
+ return error_mark_node;
+ }
+
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
will be considered, but default promotions won't. */
if (warn_sign_compare && !skip_evaluation)
{
- int unsigned_op1 = TREE_UNSIGNED (TREE_TYPE (orig_op1));
- int unsigned_op2 = TREE_UNSIGNED (TREE_TYPE (orig_op2));
+ int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+ int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2));
if (unsigned_op1 ^ unsigned_op2)
{
/* Do not warn if the result type is signed, since the
signed type will only be chosen if it can represent
all the values of the unsigned type. */
- if (! TREE_UNSIGNED (result_type))
+ if (! TYPE_UNSIGNED (result_type))
/* OK */;
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
if (comp_target_types (type1, type2, 1))
- result_type = common_type (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)
result_type = qualify_type (type2, type1);
op2 = convert_and_check (result_type, op2);
if (TREE_CODE (ifexp) == INTEGER_CST)
- return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
+ return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
}
build_tree_list (field, value)),
0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
+ TREE_INVARIANT (t) = TREE_INVARIANT (value);
return t;
}
error ("cast to union type from type not present in union");
if the cast breaks type based aliasing. */
if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
warning ("type-punning to incomplete type might break strict-aliasing rules");
- else if (!alias_sets_conflict_p
- (get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))),
- get_alias_set (TREE_TYPE (type))))
- warning ("dereferencing type-punned pointer will 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 ("dereferencing type-punned pointer will break strict-aliasing rules");
+ else if (warn_strict_aliasing > 1
+ && !alias_sets_might_conflict_p (set1, set2))
+ warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+ }
}
+ /* If pedantic, warn for conversions between function and object
+ pointer types, except for converting a null pointer constant
+ to function pointer type. */
+ if (pedantic
+ && TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
+ pedwarn ("ISO C forbids conversion of function pointer to object pointer type");
+
+ if (pedantic
+ && TREE_CODE (type) == POINTER_TYPE
+ && 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))
+ pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
+
ovalue = value;
/* Replace a nonvolatile const static variable with its value. */
if (optimize && TREE_CODE (value) == VAR_DECL)
if (TREE_CODE (value) == INTEGER_CST)
{
TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+
+ if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
+ TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
}
}
- /* Pedantically, don't let (void *) (FOO *) 0 be a null pointer constant. */
- if (pedantic && TREE_CODE (value) == INTEGER_CST
+ /* Don't let (void *) (FOO *) 0 be a null pointer constant. */
+ if (TREE_CODE (value) == INTEGER_CST
&& TREE_CODE (expr) == INTEGER_CST
&& TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
value = non_lvalue (value);
- /* If pedantic, don't let a cast be an lvalue. */
- if (value == expr && pedantic)
+ /* Don't let a cast be an lvalue. */
+ if (value == expr)
value = non_lvalue (value);
return value;
newrhs = rhs;
- /* Handle control structure constructs used as "lvalues". */
-
- switch (TREE_CODE (lhs))
- {
- /* Handle (a, b) used as an "lvalue". */
- case COMPOUND_EXPR:
- pedantic_lvalue_warning (COMPOUND_EXPR);
- newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), modifycode, rhs);
- if (TREE_CODE (newrhs) == ERROR_MARK)
- return error_mark_node;
- return build (COMPOUND_EXPR, lhstype,
- TREE_OPERAND (lhs, 0), newrhs);
-
- /* Handle (a ? b : c) used as an "lvalue". */
- case COND_EXPR:
- pedantic_lvalue_warning (COND_EXPR);
- rhs = save_expr (rhs);
- {
- /* Produce (a ? (b = rhs) : (c = rhs))
- except that the RHS goes through a save-expr
- so the code to compute it is only emitted once. */
- tree cond
- = build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (TREE_OPERAND (lhs, 1),
- modifycode, rhs),
- build_modify_expr (TREE_OPERAND (lhs, 2),
- modifycode, rhs));
- if (TREE_CODE (cond) == ERROR_MARK)
- return cond;
- /* Make sure the code to compute the rhs comes out
- before the split. */
- return build (COMPOUND_EXPR, TREE_TYPE (lhs),
- /* But cast it to void to avoid an "unused" error. */
- convert (void_type_node, rhs), cond);
- }
- default:
- break;
- }
-
/* If a binary op has been requested, combine the old LHS value with the RHS
producing the value we should actually store into the LHS. */
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- /* Handle a cast used as an "lvalue".
- We have already performed any binary operator using the value as cast.
- Now convert the result to the cast type of the lhs,
- and then true type of the lhs and store it there;
- then convert result back to the cast type to be the value
- of the assignment. */
-
- switch (TREE_CODE (lhs))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
- newrhs = default_function_array_conversion (newrhs);
- {
- tree inner_lhs = TREE_OPERAND (lhs, 0);
- tree result;
- result = build_modify_expr (inner_lhs, NOP_EXPR,
- convert (TREE_TYPE (inner_lhs),
- convert (lhstype, newrhs)));
- if (TREE_CODE (result) == ERROR_MARK)
- return result;
- pedantic_lvalue_warning (CONVERT_EXPR);
- return convert (TREE_TYPE (lhs), result);
- }
-
- default:
- break;
- }
-
- /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
- Reject anything strange now. */
-
if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
return error_mark_node;
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
- readonly_warning (lhs, "assignment");
+ readonly_error (lhs, "assignment");
/* If storing into a structure or union member,
it has probably been given type `int'.
return rhs;
}
/* Some types can interconvert without explicit casts. */
- else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
- && ((*targetm.vector_opaque_p) (type)
- || (*targetm.vector_opaque_p) (rhstype)))
+ else if (codel == VECTOR_TYPE
+ && 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
int target_cmp = 0; /* Cache comp_target_types () result. */
/* Opaque pointers are treated like void pointers. */
- is_opaque_pointer = ((*targetm.vector_opaque_p) (type)
- || (*targetm.vector_opaque_p) (rhstype))
+ is_opaque_pointer = (targetm.vector_opaque_p (type)
+ || targetm.vector_opaque_p (rhstype))
&& TREE_CODE (ttl) == VECTOR_TYPE
&& TREE_CODE (ttr) == VECTOR_TYPE;
vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
below and handle as a constructor. */
if (code == VECTOR_TYPE
- && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT)
+ && vector_types_convertible_p (TREE_TYPE (inside_init), type)
&& TREE_CONSTANT (inside_init))
{
if (TREE_CODE (inside_init) == VECTOR_CST
- && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+ && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
TYPE_MAIN_VARIANT (type),
COMPARE_STRICT))
return inside_init;
|| (code == VECTOR_TYPE
&& comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT))
|| (code == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)
+ && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
+ TREE_TYPE (type), COMPARE_STRICT))
+ || (code == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE
+ && comptypes (TREE_TYPE (inside_init),
TREE_TYPE (type), COMPARE_STRICT))))
{
if (code == POINTER_TYPE)
/* Handle scalar types, including conversions. */
if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
- || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE)
+ || 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
/* Pop back to the data of the outer initializer (if any). */
free (spelling_base);
-
+
constructor_decl = p->decl;
constructor_asmspec = p->asmspec;
require_constant_value = p->require_constant_value;
if (type == 0)
type = TREE_TYPE (constructor_decl);
- if ((*targetm.vector_opaque_p) (type))
+ if (targetm.vector_opaque_p (type))
error ("opaque vector types cannot be initialized");
p->type = constructor_type;
abort ();
}
+ /* Now output all pending elements. */
+ constructor_incremental = 1;
+ output_pending_init_elements (1);
+
p = constructor_stack;
/* Error for initializing a flexible array member, or a zero-length
}
}
- /* Now output all pending elements. */
- constructor_incremental = 1;
- output_pending_init_elements (1);
-
/* Pad out the end of the structure. */
if (p->replacement_value)
/* If this closes a superfluous brace pair,
constructor = build_constructor (constructor_type,
nreverse (constructor_elements));
if (constructor_constant)
- TREE_CONSTANT (constructor) = 1;
+ TREE_CONSTANT (constructor) = TREE_INVARIANT (constructor) = 1;
if (constructor_constant && constructor_simple)
TREE_STATIC (constructor) = 1;
}
}
}
- if (!TREE_UNSIGNED (type))
+ if (!TYPE_UNSIGNED (type))
{
bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
if (bitpos < HOST_BITS_PER_WIDE_INT)
constructor_range_stack = 0;
}
\f
-/* Build a simple asm-statement, from one string literal. */
+/* Build a complete asm-statement, whose components are a CV_QUALIFIER
+ (guaranteed to be 'volatile' or null) and ARGS (represented using
+ an ASM_STMT node). */
tree
-simple_asm_stmt (tree expr)
+build_asm_stmt (tree cv_qualifier, tree args)
{
- STRIP_NOPS (expr);
-
- if (TREE_CODE (expr) == ADDR_EXPR)
- expr = TREE_OPERAND (expr, 0);
-
- if (TREE_CODE (expr) == STRING_CST)
- {
- tree stmt;
-
- /* Simple asm statements are treated as volatile. */
- stmt = add_stmt (build_stmt (ASM_STMT, ridpointers[(int) RID_VOLATILE],
- expr, NULL_TREE, NULL_TREE, NULL_TREE));
- ASM_INPUT_P (stmt) = 1;
- return stmt;
- }
-
- error ("argument of `asm' is not a constant string");
- return NULL_TREE;
+ if (!ASM_VOLATILE_P (args) && cv_qualifier)
+ ASM_VOLATILE_P (args) = 1;
+ return add_stmt (args);
}
-/* Build an asm-statement, whose components are a CV_QUALIFIER, a
- STRING, some OUTPUTS, some INPUTS, and some CLOBBERS. */
-
+/* Build an asm-expr, whose components are a STRING, some OUTPUTS,
+ some INPUTS, and some CLOBBERS. The latter three may be NULL.
+ SIMPLE indicates whether there was anything at all after the
+ string in the asm expression -- asm("blah") and asm("blah" : )
+ are subtly different. We use a ASM_STMT node to represent this. */
tree
-build_asm_stmt (tree cv_qualifier, tree string, tree outputs, tree inputs,
- tree clobbers)
+build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
+ bool simple)
{
tree tail;
+ tree args;
+ int i;
+ const char *constraint;
+ bool allows_mem, allows_reg, is_inout;
+ int ninputs;
+ int noutputs;
- if (TREE_CODE (string) != STRING_CST)
- {
- error ("asm template is not a string constant");
- return NULL_TREE;
- }
-
- if (cv_qualifier != NULL_TREE
- && cv_qualifier != ridpointers[(int) RID_VOLATILE])
- {
- warning ("%s qualifier ignored on asm",
- IDENTIFIER_POINTER (cv_qualifier));
- cv_qualifier = NULL_TREE;
- }
+ ninputs = list_length (inputs);
+ noutputs = list_length (outputs);
- /* We can remove output conversions that change the type,
- but not the mode. */
- for (tail = outputs; tail; tail = TREE_CHAIN (tail))
+ /* Remove output conversions that change the type but not the mode. */
+ for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
{
tree output = TREE_VALUE (tail);
-
STRIP_NOPS (output);
TREE_VALUE (tail) = output;
+ lvalue_or_else (output, "invalid lvalue in asm statement");
- /* Allow conversions as LHS here. build_modify_expr as called below
- will do the right thing with them. */
- while (TREE_CODE (output) == NOP_EXPR
- || TREE_CODE (output) == CONVERT_EXPR
- || TREE_CODE (output) == FLOAT_EXPR
- || TREE_CODE (output) == FIX_TRUNC_EXPR
- || TREE_CODE (output) == FIX_FLOOR_EXPR
- || TREE_CODE (output) == FIX_ROUND_EXPR
- || TREE_CODE (output) == FIX_CEIL_EXPR)
- output = TREE_OPERAND (output, 0);
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
- lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement");
- }
+ if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
+ &allows_mem, &allows_reg, &is_inout))
+ {
+ /* By marking this operand as erroneous, we will not try
+ to process this operand again in expand_asm_operands. */
+ TREE_VALUE (tail) = error_mark_node;
+ continue;
+ }
- /* Remove output conversions that change the type but not the mode. */
- for (tail = outputs; tail; tail = TREE_CHAIN (tail))
- {
- tree output = TREE_VALUE (tail);
- STRIP_NOPS (output);
- TREE_VALUE (tail) = output;
+ /* If the operand is a DECL that is going to end up in
+ memory, assume it is addressable. This is a bit more
+ conservative than it would ideally be; the exact test is
+ buried deep in expand_asm_operands and depends on the
+ DECL_RTL for the OPERAND -- which we don't have at this
+ point. */
+ if (!allows_reg && DECL_P (output))
+ c_mark_addressable (output);
}
/* Perform default conversions on array and function inputs.
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
- return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
- outputs, inputs, clobbers));
+ args = build_stmt (ASM_STMT, string, outputs, inputs, clobbers);
+
+ /* Simple asm statements are treated as volatile. */
+ if (simple)
+ {
+ ASM_VOLATILE_P (args) = 1;
+ ASM_INPUT_P (args) = 1;
+ }
+ return args;
}
/* Expand an ASM statement with operands, handling output operands
|| ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (type)))
- readonly_warning (o[i], "modification by `asm'");
+ readonly_error (o[i], "modification by `asm'");
}
}
while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
inner = TREE_OPERAND (inner, 0);
- if (TREE_CODE (inner) == VAR_DECL
+ if (DECL_P (inner)
&& ! DECL_EXTERNAL (inner)
&& ! TREE_STATIC (inner)
&& DECL_CONTEXT (inner) == current_function_decl)
{
struct c_switch *cs = switch_stack;
+ /* Emit warnings as needed. */
+ c_do_switch_warnings (cs->cases, cs->switch_stmt);
+
/* Rechain the next statements to the SWITCH_STMT. */
last_tree = cs->switch_stmt;
undefined if the quotient can't be represented in the
computation mode. We shorten only if unsigned or if
dividing by something we know != -1. */
- shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
+ shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
|| (TREE_CODE (op1) == INTEGER_CST
&& ! integer_all_onesp (op1)));
common = 1;
on some targets, since the modulo instruction is undefined if the
quotient can't be represented in the computation mode. We shorten
only if unsigned or if dividing by something we know != -1. */
- shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
+ shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
|| (TREE_CODE (op1) == INTEGER_CST
&& ! integer_all_onesp (op1)));
common = 1;
but that does not mean the operands should be
converted to ints! */
result_type = integer_type_node;
- op0 = c_common_truthvalue_conversion (op0);
- op1 = c_common_truthvalue_conversion (op1);
+ op0 = lang_hooks.truthvalue_conversion (op0);
+ op1 = lang_hooks.truthvalue_conversion (op1);
converted = 1;
}
break;
but don't convert the args to int! */
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE
- || code0 == VECTOR_TYPE)
+ || code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE
- || code1 == VECTOR_TYPE))
+ || code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
if (comp_target_types (type0, type1, 1))
- result_type = common_type (type0, type1);
+ result_type = common_pointer_type (type0, type1);
else if (VOID_TYPE_P (tt0))
{
/* op0 != orig_op0 detects the case of something
{
if (comp_target_types (type0, type1, 1))
{
- result_type = common_type (type0, type1);
+ result_type = common_pointer_type (type0, type1);
if (pedantic
&& TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
{
if (comp_target_types (type0, type1, 1))
{
- result_type = common_type (type0, type1);
+ result_type = common_pointer_type (type0, type1);
if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
!= !COMPLETE_TYPE_P (TREE_TYPE (type1)))
pedwarn ("comparison of complete and incomplete pointers");
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
+ case LTGT_EXPR:
build_type = integer_type_node;
if (code0 != REAL_TYPE || code1 != REAL_TYPE)
{
break;
}
+ if (code0 == ERROR_MARK || code1 == ERROR_MARK)
+ return error_mark_node;
+
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
|| code0 == VECTOR_TYPE)
&&
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 = TREE_UNSIGNED (result_type);
+ int uns = TYPE_UNSIGNED (result_type);
tree type;
final_type = result_type;
if ((TYPE_PRECISION (TREE_TYPE (op0))
== TYPE_PRECISION (TREE_TYPE (arg0)))
&& TREE_TYPE (op0) != final_type)
- unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
+ unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
if ((TYPE_PRECISION (TREE_TYPE (op1))
== TYPE_PRECISION (TREE_TYPE (arg1)))
&& TREE_TYPE (op1) != final_type)
- unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
+ unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
/* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
final_type = result_type;
if (arg0 == op0 && final_type == TREE_TYPE (op0))
- unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
+ unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
/* We can shorten only if the shift count is less than the
number of bits in the smaller type size. */
&& compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
/* We cannot drop an unsigned shift after sign-extension. */
- && (!TREE_UNSIGNED (final_type) || unsigned_arg))
+ && (!TYPE_UNSIGNED (final_type) || unsigned_arg))
{
/* Do an unsigned shift if the operand was zero-extended. */
result_type
if (warn_sign_compare && skip_evaluation == 0)
{
- int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
- int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+ int op0_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op1));
int unsignedp0, unsignedp1;
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
Do not warn if the comparison is being done in a signed type,
since the signed type will only be chosen if it can represent
all the values of the unsigned type. */
- if (! TREE_UNSIGNED (result_type))
+ if (! TYPE_UNSIGNED (result_type))
/* OK */;
/* Do not warn if both operands are the same signedness. */
else if (op0_signed == op1_signed)
{
tree result = build (resultcode, build_type, op0, op1);
- tree folded;
/* Treat expressions in initializers specially as they can't trap. */
- folded = initializer_stack ? fold_initializer (result)
+ result = initializer_stack ? fold_initializer (result)
: fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+
if (final_type != 0)
- return convert (final_type, folded);
- return folded;
+ result = convert (final_type, result);
+ return result;
}
}
+/* Build the result of __builtin_offsetof. TYPE is the first argument to
+ offsetof, i.e. a type. LIST is a tree_list that encodes component and
+ array references; PURPOSE is set for the former and VALUE is set for
+ the later. */
+
+tree
+build_offsetof (tree type, tree list)
+{
+ tree t;
+
+ /* Build "*(type *)0". */
+ t = convert (build_pointer_type (type), null_pointer_node);
+ t = build_indirect_ref (t, "");
+
+ /* Build COMPONENT and ARRAY_REF expressions as needed. */
+ for (list = nreverse (list); list ; list = TREE_CHAIN (list))
+ if (TREE_PURPOSE (list))
+ t = build_component_ref (t, TREE_PURPOSE (list));
+ else
+ t = build_array_ref (t, TREE_VALUE (list));
+
+ /* Finalize the offsetof expression. For now all we need to do is take
+ the address of the expression we created, and cast that to an integer
+ type; this mirrors the traditional macro implementation of offsetof. */
+ t = build_unary_op (ADDR_EXPR, t, 0);
+ return convert (size_type_node, t);
+}