/* 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.
/* This file is part of the C front end.
It contains routines to build C expressions given their operands,
including computing the types of the result, C-specific error checks,
- and some optimization.
-
- There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
- and to process initializations in declarations (since they work
- like a strange sort of assignment). */
+ and some optimization. */
#include "config.h"
#include "system.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
+#include "langhooks.h"
#include "c-tree.h"
#include "tm_p.h"
#include "flags.h"
#include "intl.h"
#include "ggc.h"
#include "target.h"
+#include "tree-iterator.h"
+#include "tree-gimple.h"
+
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
+static int require_constant_value;
+static int require_constant_elements;
+
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 tagged_types_tu_compatible_p (tree, tree);
static int comp_target_types (tree, tree, int);
-static int function_types_compatible_p (tree, tree, int);
-static int type_lists_compatible_p (tree, tree, int);
+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 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);
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
+static int lvalue_or_else (tree, const char *);
\f
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
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),
- COMPARE_STRICT))
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
{
TREE_VALUE (n) = TREE_VALUE (p2);
if (pedantic)
tree memb;
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1),
- COMPARE_STRICT))
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
{
TREE_VALUE (n) = TREE_VALUE (p1);
if (pedantic)
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
but a warning may be needed if you use them together. */
int
-comptypes (tree type1, tree type2, int flags)
+comptypes (tree type1, tree type2)
{
tree t1 = type1;
tree t2 = type2;
/* 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. */
+ /* Qualifiers must match. C99 6.7.3p9 */
if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
return 0;
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. */
if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0)
break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
- ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2), flags));
+ ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
break;
case FUNCTION_TYPE:
- val = function_types_compatible_p (t1, t2, flags);
+ val = function_types_compatible_p (t1, t2);
break;
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
- && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
- flags)))
+ && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2))))
return 0;
/* Sizes must match unless one is missing or variable. */
case ENUMERAL_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
- val = tagged_types_tu_compatible_p (t1, t2, flags);
+ val = tagged_types_tu_compatible_p (t1, t2);
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));
break;
default:
return val;
val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
- TYPE_MAIN_VARIANT (TREE_TYPE (ttr)), COMPARE_STRICT);
+ TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
if (val == 2 && pedantic)
pedwarn ("types are not quite compatible");
\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 ();
}
rules. */
static int
-tagged_types_tu_compatible_p (tree t1, tree t2, int flags)
+tagged_types_tu_compatible_p (tree t1, tree t2)
{
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))
+ 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), flags);
+ result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
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))
{
if (TREE_CODE (s1) != TREE_CODE (s2)
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
- result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2), flags);
+ result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
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)
Otherwise, the argument types must match. */
static int
-function_types_compatible_p (tree f1, tree f2, int flags)
+function_types_compatible_p (tree f1, tree f2)
{
tree args1, args2;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
- val = comptypes (ret1, ret2, flags);
+ val = comptypes (ret1, ret2);
if (val == 0)
return 0;
compare that with the other type's arglist.
If they don't match, ask for a warning (but no error). */
if (TYPE_ACTUAL_ARG_TYPES (f1)
- && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
- flags))
+ && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
val = 2;
return val;
}
if (!self_promoting_args_p (args1))
return 0;
if (TYPE_ACTUAL_ARG_TYPES (f2)
- && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
- flags))
+ && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2)))
val = 2;
return val;
}
/* Both types have argument lists: compare them and propagate results. */
- val1 = type_lists_compatible_p (args1, args2, flags);
+ val1 = type_lists_compatible_p (args1, args2);
return val1 != 1 ? val1 : val;
}
or 2 for compatible with warning. */
static int
-type_lists_compatible_p (tree args1, tree args2, int flags)
+type_lists_compatible_p (tree args1, tree args2)
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
|| TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
;
else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
- TYPE_MAIN_VARIANT (TREE_VALUE (args2)),
- flags)))
+ TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
tree memb;
for (memb = TYPE_FIELDS (TREE_VALUE (args1));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2),
- flags))
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
break;
if (memb == 0)
return 0;
tree memb;
for (memb = TYPE_FIELDS (TREE_VALUE (args2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1),
- flags))
+ if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
break;
if (memb == 0)
return 0;
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
| (volatilep * TYPE_QUAL_VOLATILE));
if (TREE_CODE (exp) == INDIRECT_REF)
- return convert (TYPE_POINTER_TO (restype),
+ return convert (build_pointer_type (restype),
TREE_OPERAND (exp, 0));
if (TREE_CODE (exp) == COMPOUND_EXPR)
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)
tree fntype, fundecl = 0;
tree coerced_params;
tree name = NULL_TREE, result;
+ tree tem;
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
/* fntype now gets the type of function pointed to. */
fntype = TREE_TYPE (fntype);
+ /* Check that the function is called through a compatible prototype.
+ If it is not, replace the call by a trap, wrapped up in a compound
+ expression if necessary. This has the nice side-effect to prevent
+ the tree-inliner from generating invalid assignment trees which may
+ blow up in the RTL expander later.
+
+ ??? This doesn't work for Objective-C because objc_comptypes
+ refuses to compare function prototypes, yet the compiler appears
+ to build calls that are flagged as invalid by C's comptypes. */
+ if (! c_dialect_objc ()
+ && TREE_CODE (function) == NOP_EXPR
+ && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
+ && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
+ && ! comptypes (fntype, TREE_TYPE (tem)))
+ {
+ tree return_type = TREE_TYPE (fntype);
+ tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
+ NULL_TREE);
+
+ /* This situation leads to run-time undefined behavior. We can't,
+ therefore, simply error unless we can prove that all possible
+ executions of the program must execute the code. */
+ 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
+ {
+ tree rhs;
+
+ if (AGGREGATE_TYPE_P (return_type))
+ rhs = build_compound_literal (return_type,
+ build_constructor (return_type,
+ NULL_TREE));
+ else
+ rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
+
+ return build (COMPOUND_EXPR, return_type, trap, rhs);
+ }
+ }
+
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
result = build (CALL_EXPR, TREE_TYPE (fntype),
function, coerced_params, NULL_TREE);
TREE_SIDE_EFFECTS (result) = 1;
- result = fold (result);
+
+ if (require_constant_value)
+ {
+ result = fold_initializer (result);
+
+ if (TREE_CONSTANT (result)
+ && (name == NULL_TREE
+ || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
+ pedwarn_init ("initializer element is not constant");
+ }
+ else
+ result = fold (result);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
;
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;
}
\f
-
-/* Return true if `t' is known to be non-negative. */
-
-int
-c_tree_expr_nonnegative_p (tree t)
-{
- if (TREE_CODE (t) == STMT_EXPR)
- {
- t = COMPOUND_BODY (STMT_EXPR_STMT (t));
-
- /* Find the last statement in the chain, ignoring the final
- * scope statement */
- while (TREE_CHAIN (t) != NULL_TREE
- && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
- t = TREE_CHAIN (t);
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
- }
- return tree_expr_nonnegative_p (t);
-}
-
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
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;
}
if (argtype == 0)
argtype = TREE_TYPE (arg);
- return fold (build1 (code, argtype, arg));
+ val = build1 (code, argtype, arg);
+ return require_constant_value ? fold_initializer (val) : fold (val);
}
/* 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 nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. */
-int
+static int
lvalue_or_else (tree ref, const char *msgid)
{
int win = lvalue_p (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:
- if (pedantic)
- pedwarn ("ISO C forbids use of compound expressions as lvalues");
- 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
involving such literals) and it is non-negative. */
- else if ((unsigned_op2 && c_tree_expr_nonnegative_p (op1))
- || (unsigned_op1 && c_tree_expr_nonnegative_p (op2)))
+ else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
+ || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
warning ("signed and unsigned type in conditional 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));
}
&& ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
warning ("left-hand operand of comma expression has no effect");
-
- /* When pedantic, a compound expression can be neither an lvalue
- nor an integer constant expression. */
- if (! pedantic)
- return rest;
}
/* With -Wunused, we should also warn if the left-hand operand does have
`foo() + bar(), baz()' the result of the `+' operator is not used,
so we should issue a warning. */
else if (warn_unused_value)
- warn_if_unused_value (TREE_VALUE (list));
+ warn_if_unused_value (TREE_VALUE (list), input_location);
return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
}
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
- TYPE_MAIN_VARIANT (TREE_TYPE (value)), COMPARE_STRICT))
+ TYPE_MAIN_VARIANT (TREE_TYPE (value))))
break;
if (field)
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'.
This code doesn't fully support references, it's just for the
special case of va_start and va_copy. */
if (codel == REFERENCE_TYPE
- && comptypes (TREE_TYPE (type), TREE_TYPE (rhs), COMPARE_STRICT) == 1)
+ && comptypes (TREE_TYPE (type), TREE_TYPE (rhs)) == 1)
{
if (!lvalue_p (rhs))
{
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
tree memb_type = TREE_TYPE (memb_types);
if (comptypes (TYPE_MAIN_VARIANT (memb_type),
- TYPE_MAIN_VARIANT (rhstype), COMPARE_STRICT))
+ TYPE_MAIN_VARIANT (rhstype)))
break;
if (TREE_CODE (memb_type) != POINTER_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;
&& TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
&& TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
&& integer_zerop (TREE_OPERAND (rhs, 0))))
- {
warn_for_assignment ("%s makes pointer from integer without a cast",
errtype, funname, parmnum);
- return convert (type, rhs);
- }
- return null_pointer_node;
+
+ return convert (type, rhs);
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
return error_mark_node;
}
-/* Convert VALUE for assignment into inlined parameter PARM. */
+/* Convert VALUE for assignment into inlined parameter PARM. ARGNUM
+ is used for error and waring reporting and indicates which argument
+ is being processed. */
tree
-c_convert_parm_for_inlining (tree parm, tree value, tree fn)
+c_convert_parm_for_inlining (tree parm, tree value, tree fn, int argnum)
{
tree ret, type;
type = TREE_TYPE (parm);
ret = convert_for_assignment (type, value,
(char *) 0 /* arg passing */, fn,
- DECL_NAME (fn), 0);
+ DECL_NAME (fn), argnum);
if (targetm.calls.promote_prototypes (TREE_TYPE (fn))
&& INTEGRAL_TYPE_P (type)
&& (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
&& ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
{
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
- TYPE_MAIN_VARIANT (type), COMPARE_STRICT))
+ TYPE_MAIN_VARIANT (type)))
return inside_init;
if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
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)),
- TYPE_MAIN_VARIANT (type),
- COMPARE_STRICT))
+ && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+ TYPE_MAIN_VARIANT (type)))
return inside_init;
else
return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
if (inside_init && TREE_TYPE (inside_init) != 0
&& (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
- TYPE_MAIN_VARIANT (type), COMPARE_STRICT)
+ TYPE_MAIN_VARIANT (type))
|| (code == ARRAY_TYPE
- && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT))
+ && comptypes (TREE_TYPE (inside_init), type))
|| (code == VECTOR_TYPE
- && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT))
+ && comptypes (TREE_TYPE (inside_init), type))
|| (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))))
+ 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)
{
/* 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
/* 0 if implicitly pushing constructor levels is allowed. */
int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */
-static int require_constant_value;
-static int require_constant_elements;
-
/* DECL node for which an initializer is being read.
0 means we are reading a constructor expression
such as (struct foo) {...}. */
abort ();
/* 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)
&& TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
&& !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
- TYPE_MAIN_VARIANT (type), COMPARE_STRICT)))
+ TYPE_MAIN_VARIANT (type))))
value = default_conversion (value);
if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
retry:
- /* Look thru the whole pending tree.
+ /* Look through the whole pending tree.
If we find an element that should be output now,
output it. Otherwise, set NEXT to the element
that comes first among those still pending. */
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_EXPR 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_EXPR 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_EXPR, 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'");
}
}
emit_queue ();
}
\f
-/* Expand a C `return' statement.
- RETVAL is the expression for what to return,
- or a null pointer for `return;' with no value. */
+/* Generate a C `return' statement. RETVAL is the expression for what
+ to return, or a null pointer for `return;' with no value. */
-tree
-c_expand_return (tree retval)
+void
+c_finish_return (tree retval)
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
current_function_returns_value = 1;
if (t == error_mark_node)
- return NULL_TREE;
+ return;
inner = t = convert (TREE_TYPE (res), t);
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)
retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
}
- return add_stmt (build_return_stmt (retval));
+ add_stmt (build_stmt (RETURN_EXPR, retval));
}
\f
struct c_switch {
if (switch_stack)
{
- bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
-
label = c_add_case_label (switch_stack->cases,
SWITCH_COND (switch_stack->switch_stmt),
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
- else if (switch_was_empty_p)
- {
- /* Attach the first case label to the SWITCH_BODY. */
- SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
- TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
- }
}
else if (low_value)
error ("case label not within a switch statement");
/* Finish the switch statement. */
void
-c_finish_case (void)
+c_finish_case (tree body)
{
struct c_switch *cs = switch_stack;
- /* Rechain the next statements to the SWITCH_STMT. */
- last_tree = cs->switch_stmt;
+ SWITCH_BODY (cs->switch_stmt) = body;
+
+ /* Emit warnings as needed. */
+ c_do_switch_warnings (cs->cases, cs->switch_stmt);
/* Pop the stack. */
switch_stack = switch_stack->next;
splay_tree_delete (cs->cases);
free (cs);
}
+\f
+/* Keep a stack of if statements. We record the number of compound
+ statements seen up to the if keyword, as well as the line number
+ and file of the if. If a potentially ambiguous else is seen, that
+ fact is recorded; the warning is issued when we can be sure that
+ the enclosing if statement does not have an else branch. */
+typedef struct
+{
+ tree if_stmt;
+ location_t empty_locus;
+ int compstmt_count;
+ int stmt_count;
+ unsigned int needs_warning : 1;
+ unsigned int saw_else : 1;
+} if_elt;
+
+static if_elt *if_stack;
+
+/* Amount of space in the if statement stack. */
+static int if_stack_space = 0;
+
+/* Stack pointer. */
+static int if_stack_pointer = 0;
+
+/* Begin an if-statement. */
+
+void
+c_begin_if_stmt (void)
+{
+ tree r;
+ if_elt *elt;
+
+ /* Make sure there is enough space on the stack. */
+ if (if_stack_space == 0)
+ {
+ if_stack_space = 10;
+ if_stack = xmalloc (10 * sizeof (if_elt));
+ }
+ else if (if_stack_space == if_stack_pointer)
+ {
+ if_stack_space += 10;
+ if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
+ }
+
+ r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE));
+
+ /* Record this if statement. */
+ elt = &if_stack[if_stack_pointer++];
+ memset (elt, 0, sizeof (*elt));
+ elt->if_stmt = r;
+}
+
+/* Record the start of an if-then, and record the start of it
+ for ambiguous else detection.
+
+ COND is the condition for the if-then statement.
+
+ IF_STMT is the statement node that has already been created for
+ this if-then statement. It is created before parsing the
+ condition to keep line number information accurate. */
+
+void
+c_finish_if_cond (tree cond, int compstmt_count, int stmt_count)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ elt->compstmt_count = compstmt_count;
+ elt->stmt_count = stmt_count;
+ COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+/* Called after the then-clause for an if-statement is processed. */
+
+void
+c_finish_then (tree then_stmt)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ COND_EXPR_THEN (elt->if_stmt) = then_stmt;
+ elt->empty_locus = input_location;
+}
+
+/* Called between the then-clause and the else-clause
+ of an if-then-else. */
+
+void
+c_begin_else (int stmt_count)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+
+ /* An ambiguous else warning must be generated for the enclosing if
+ statement, unless we see an else branch for that one, too. */
+ if (warn_parentheses
+ && if_stack_pointer > 1
+ && (elt[0].compstmt_count == elt[-1].compstmt_count))
+ elt[-1].needs_warning = 1;
+
+ /* Even if a nested if statement had an else branch, it can't be
+ ambiguous if this one also has an else. So don't warn in that
+ case. Also don't warn for any if statements nested in this else. */
+ elt->needs_warning = 0;
+ elt->compstmt_count--;
+ elt->saw_else = 1;
+ elt->stmt_count = stmt_count;
+}
+
+/* Called after the else-clause for an if-statement is processed. */
+
+void
+c_finish_else (tree else_stmt)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ COND_EXPR_ELSE (elt->if_stmt) = else_stmt;
+ elt->empty_locus = input_location;
+}
+
+/* Record the end of an if-then. Optionally warn if a nested
+ if statement had an ambiguous else clause. */
+
+void
+c_finish_if_stmt (int stmt_count)
+{
+ if_elt *elt = &if_stack[--if_stack_pointer];
+
+ if (COND_EXPR_ELSE (elt->if_stmt) == NULL)
+ COND_EXPR_ELSE (elt->if_stmt) = build_empty_stmt ();
+
+ if (elt->needs_warning)
+ warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+ EXPR_LOCUS (elt->if_stmt));
+
+ if (extra_warnings && stmt_count == elt->stmt_count)
+ {
+ if (elt->saw_else)
+ warning ("%Hempty body in an else-statement", &elt->empty_locus);
+ else
+ warning ("%Hempty body in an if-statement", &elt->empty_locus);
+ }
+}
+\f
+/* Begin a while statement. Returns a newly created WHILE_STMT if
+ appropriate. */
+
+tree
+c_begin_while_stmt (void)
+{
+ tree r;
+ r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
+ return r;
+}
+
+void
+c_finish_while_stmt_cond (tree cond, tree while_stmt)
+{
+ WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
+}
+
+void
+c_finish_while_stmt (tree body, tree while_stmt)
+{
+ WHILE_BODY (while_stmt) = body;
+}
+\f
+/* Create a for statement. */
+
+tree
+c_begin_for_stmt (void)
+{
+ tree r;
+ r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE));
+ FOR_INIT_STMT (r) = push_stmt_list ();
+ return r;
+}
+
+void
+c_finish_for_stmt_init (tree for_stmt)
+{
+ FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
+}
+
+void
+c_finish_for_stmt_cond (tree cond, tree for_stmt)
+{
+ if (cond)
+ FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+void
+c_finish_for_stmt_incr (tree expr, tree for_stmt)
+{
+ FOR_EXPR (for_stmt) = expr;
+}
+
+void
+c_finish_for_stmt (tree body, tree for_stmt)
+{
+ FOR_BODY (for_stmt) = body;
+}
+\f
+/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr. */
+
+static void
+emit_side_effect_warnings (tree expr)
+{
+ if (!TREE_SIDE_EFFECTS (expr))
+ {
+ if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
+ warning ("%Hstatement with no effect",
+ EXPR_LOCUS (expr) ? EXPR_LOCUS (expr) : &input_location);
+ }
+ else if (warn_unused_value)
+ warn_if_unused_value (expr, input_location);
+}
+
+/* Emit an expression as a statement. */
+
+void
+c_finish_expr_stmt (tree expr)
+{
+ if (!expr)
+ return;
+
+ /* 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 (TREE_TYPE (expr) != error_mark_node
+ && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
+ && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
+ error ("expression statement has incomplete type");
+
+ /* If we're not processing a statement expression, warn about unused values.
+ Warnings for statement expressions will be emitted later, once we figure
+ out which is the result. */
+ if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+ && (extra_warnings || warn_unused_value))
+ emit_side_effect_warnings (expr);
+
+ /* If the expression is not of a type to which we cannot assign a line
+ number, wrap the thing in a no-op NOP_EXPR. */
+ if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+ expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+
+ add_stmt (expr);
+}
+
+/* Do the opposite and emit a statement as an expression. To begin,
+ create a new binding level and return it. */
+
+tree
+c_begin_stmt_expr (void)
+{
+ tree ret;
+
+ /* We must force a BLOCK for this level so that, if it is not expanded
+ later, there is a way to turn off the entire subtree of blocks that
+ are contained in it. */
+ keep_next_level ();
+ ret = c_begin_compound_stmt (true);
+
+ /* Mark the current statement list as belonging to a statement list. */
+ STATEMENT_LIST_STMT_EXPR (ret) = 1;
+
+ return ret;
+}
+tree
+c_finish_stmt_expr (tree body)
+{
+ tree last, type, tmp, val;
+ tree *last_p;
+
+ body = c_end_compound_stmt (body, true);
+
+ /* Locate the last statement in BODY. See c_end_compound_stmt
+ about always returning a BIND_EXPR. */
+ last_p = &BIND_EXPR_BODY (body);
+ last = BIND_EXPR_BODY (body);
+
+ continue_searching:
+ if (TREE_CODE (last) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i;
+
+ /* This can happen with degenerate cases like ({ }). No value. */
+ if (!TREE_SIDE_EFFECTS (last))
+ return body;
+
+ /* If we're supposed to generate side effects warnings, process
+ all of the statements except the last. */
+ if (extra_warnings || warn_unused_value)
+ {
+ for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
+ emit_side_effect_warnings (tsi_stmt (i));
+ }
+ else
+ i = tsi_last (last);
+ last_p = tsi_stmt_ptr (i);
+ last = *last_p;
+ }
+
+ /* If the end of the list is exception related, then the list was split
+ by a call to push_cleanup. Continue searching. */
+ if (TREE_CODE (last) == TRY_FINALLY_EXPR
+ || TREE_CODE (last) == TRY_CATCH_EXPR)
+ {
+ last_p = &TREE_OPERAND (last, 0);
+ last = *last_p;
+ goto continue_searching;
+ }
+
+ /* In the case that the BIND_EXPR is not necessary, return the
+ expression out from inside it. */
+ if (last == BIND_EXPR_BODY (body) && BIND_EXPR_VARS (body) == NULL)
+ return last;
+
+ /* Extract the type of said expression. */
+ type = TREE_TYPE (last);
+
+ /* If we're not returning a value at all, then the BIND_EXPR that
+ we already have is a fine expression to return. */
+ if (!type || VOID_TYPE_P (type))
+ return body;
+
+ /* Now that we've located the expression containing the value, it seems
+ silly to make voidify_wrapper_expr repeat the process. Create a
+ temporary of the appropriate type and stick it in a TARGET_EXPR. */
+ tmp = create_tmp_var_raw (type, NULL);
+
+ /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids
+ tree_expr_nonnegative_p giving up immediately. */
+ val = last;
+ if (TREE_CODE (val) == NOP_EXPR
+ && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
+ val = TREE_OPERAND (val, 0);
+
+ *last_p = build (MODIFY_EXPR, void_type_node, tmp, val);
+ SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
+
+ return build (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
+}
+\f
+/* Begin and end compound statements. This is as simple as pushing
+ and popping new statement lists from the tree. */
+
+tree
+c_begin_compound_stmt (bool do_scope)
+{
+ tree stmt = push_stmt_list ();
+ if (do_scope)
+ {
+ push_scope ();
+ clear_last_expr ();
+ }
+ return stmt;
+}
+
+tree
+c_end_compound_stmt (tree stmt, bool do_scope)
+{
+ tree block = NULL;
+
+ if (do_scope)
+ {
+ if (c_dialect_objc ())
+ objc_clear_super_receiver ();
+ block = pop_scope ();
+ }
+
+ stmt = pop_stmt_list (stmt);
+ stmt = c_build_bind_expr (block, stmt);
+
+ /* If this compound statement is nested immediately inside a statement
+ expression, then force a BIND_EXPR to be created. Otherwise we'll
+ do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular,
+ STATEMENT_LISTs merge, and thus we can lose track of what statement
+ was really last. */
+ if (cur_stmt_list
+ && STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+ && TREE_CODE (stmt) != BIND_EXPR)
+ {
+ stmt = build (BIND_EXPR, void_type_node, NULL, stmt, NULL);
+ TREE_SIDE_EFFECTS (stmt) = 1;
+ }
+
+ return stmt;
+}
+
+/* Queue a cleanup. CLEANUP is an expression/statement to be executed
+ when the current scope is exited. EH_ONLY is true when this is not
+ meant to apply to normal control flow transfer. */
+
+void
+push_cleanup (tree decl ATTRIBUTE_UNUSED, tree cleanup, bool eh_only)
+{
+ enum tree_code code;
+ tree stmt, list;
+ bool stmt_expr;
+
+ code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
+ stmt = build_stmt (code, NULL, cleanup);
+ add_stmt (stmt);
+ stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list);
+ list = push_stmt_list ();
+ TREE_OPERAND (stmt, 0) = list;
+ STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
+}
+\f
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
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)
constant expression involving such literals or a
conditional expression involving such literals)
and it is non-negative. */
- if (c_tree_expr_nonnegative_p (sop))
+ if (tree_expr_nonnegative_p (sop))
/* OK */;
/* Do not warn if the comparison is an equality operation,
the unsigned quantity is an integral constant, and it
{
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)
- : fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+ result = require_constant_value ? fold_initializer (result)
+ : fold (result);
+
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);
+}