/* Build expressions with type checking for C compiler.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "rtl.h"
#include "tree.h"
#include "langhooks.h"
#include "c-tree.h"
-#include "tm_p.h"
+#include "c-lang.h"
#include "flags.h"
#include "output.h"
-#include "expr.h"
#include "toplev.h"
#include "intl.h"
-#include "ggc.h"
#include "target.h"
#include "tree-iterator.h"
+#include "bitmap.h"
#include "gimple.h"
-#include "tree-flow.h"
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
static bool null_pointer_constant_p (const_tree);
static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *);
+static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
+ bool *);
static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *);
+static int function_types_compatible_p (const_tree, const_tree, bool *,
+ bool *);
+static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
static tree lookup_field (tree, tree);
static int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree,
tree);
static char *print_spelling (char *);
static void warning_init (int, const char *);
static tree digest_init (location_t, tree, tree, tree, bool, bool, int);
-static void output_init_element (tree, tree, bool, tree, tree, int, bool);
-static void output_pending_init_elements (int);
-static int set_designator (int);
-static void push_range_stack (tree);
-static void add_pending_init (tree, tree, tree, bool);
-static void set_nonincremental_init (void);
-static void set_nonincremental_init_from_string (tree);
-static tree find_init_member (tree);
+static void output_init_element (tree, tree, bool, tree, tree, int, bool,
+ struct obstack *);
+static void output_pending_init_elements (int, struct obstack *);
+static int set_designator (int, struct obstack *);
+static void push_range_stack (tree, struct obstack *);
+static void add_pending_init (tree, tree, tree, bool, struct obstack *);
+static void set_nonincremental_init (struct obstack *);
+static void set_nonincremental_init_from_string (tree, struct obstack *);
+static tree find_init_member (tree, struct obstack *);
static void readonly_error (tree, enum lvalue_use);
static void readonly_warning (tree, enum lvalue_use);
static int lvalue_or_else (const_tree, enum lvalue_use);
static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *);
+static int comptypes_internal (const_tree, const_tree, bool *, bool *);
\f
/* Return true if EXP is a null pointer constant, false otherwise. */
return type;
}
+/* Return true if between two named address spaces, whether there is a superset
+ named address space that encompasses both address spaces. If there is a
+ superset, return which address space is the superset. */
+
+static bool
+addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common)
+{
+ if (as1 == as2)
+ {
+ *common = as1;
+ return true;
+ }
+ else if (targetm.addr_space.subset_p (as1, as2))
+ {
+ *common = as2;
+ return true;
+ }
+ else if (targetm.addr_space.subset_p (as2, as1))
+ {
+ *common = as1;
+ return true;
+ }
+ else
+ return false;
+}
+
/* Return a variant of TYPE which has all the type qualifiers of LIKE
as well as those of TYPE. */
static tree
qualify_type (tree type, tree like)
{
+ addr_space_t as_type = TYPE_ADDR_SPACE (type);
+ addr_space_t as_like = TYPE_ADDR_SPACE (like);
+ addr_space_t as_common;
+
+ /* If the two named address spaces are different, determine the common
+ superset address space. If there isn't one, raise an error. */
+ if (!addr_space_superset (as_type, as_like, &as_common))
+ {
+ as_common = as_type;
+ error ("%qT and %qT are in disjoint named address spaces",
+ type, like);
+ }
+
return c_build_qualified_type (type,
- TYPE_QUALS (type) | TYPE_QUALS (like));
+ TYPE_QUALS_NO_ADDR_SPACE (type)
+ | TYPE_QUALS_NO_ADDR_SPACE (like)
+ | ENCODE_QUAL_ADDR_SPACE (as_common));
}
/* Return true iff the given tree T is a variable length array. */
bool t1_complete, t2_complete;
/* We should not have any type quals on arrays at all. */
- gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
+ gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1)
+ && !TYPE_QUALS_NO_ADDR_SPACE (t2));
t1_complete = COMPLETE_TYPE_P (t1);
t2_complete = COMPLETE_TYPE_P (t2);
{
TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
TREE_VALUE (p2));
- pedwarn (input_location, OPT_pedantic,
+ pedwarn (input_location, OPT_pedantic,
"function types not truly compatible in ISO C");
goto parm_done;
}
{
TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
TREE_VALUE (p1));
- pedwarn (input_location, OPT_pedantic,
+ pedwarn (input_location, OPT_pedantic,
"function types not truly compatible in ISO C");
goto parm_done;
}
tree pointed_to_2, mv2;
tree target;
unsigned target_quals;
+ addr_space_t as1, as2, as_common;
+ int quals1, quals2;
/* Save time if the two types are the same. */
/* For function types do not merge const qualifiers, but drop them
if used inconsistently. The middle-end uses these to mark const
and noreturn functions. */
+ quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
+ quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
+
if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
- target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2);
+ target_quals = (quals1 & quals2);
else
- target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2);
+ target_quals = (quals1 | quals2);
+
+ /* If the two named address spaces are different, determine the common
+ superset address space. This is guaranteed to exist due to the
+ assumption that comp_target_type returned non-zero. */
+ as1 = TYPE_ADDR_SPACE (pointed_to_1);
+ as2 = TYPE_ADDR_SPACE (pointed_to_2);
+ if (!addr_space_superset (as1, as2, &as_common))
+ gcc_unreachable ();
+
+ target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+
t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
return build_type_attribute_variant (t1, attributes);
}
const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
int val;
- val = comptypes_internal (type1, type2, NULL);
+ val = comptypes_internal (type1, type2, NULL, NULL);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
return val;
const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
int val;
- val = comptypes_internal (type1, type2, enum_and_int_p);
+ val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
+ free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+
+ return val;
+}
+
+/* Like comptypes, but if it returns nonzero for different types, it
+ sets *DIFFERENT_TYPES_P to true. */
+
+int
+comptypes_check_different_types (tree type1, tree type2,
+ bool *different_types_p)
+{
+ const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
+ int val;
+
+ val = comptypes_internal (type1, type2, NULL, different_types_p);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
return val;
but a warning may be needed if you use them together. If
ENUM_AND_INT_P is not NULL, and one type is an enum and the other a
compatible integer type, then this sets *ENUM_AND_INT_P to true;
- *ENUM_AND_INT_P is never set to false. This differs from
- comptypes, in that we don't free the seen types. */
+ *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not
+ NULL, and the types are compatible but different enough not to be
+ permitted in C1X typedef redeclarations, then this sets
+ *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to
+ false, but may or may not be set if the types are incompatible.
+ This differs from comptypes, in that we don't free the seen
+ types. */
static int
-comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p)
+comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
+ bool *different_types_p)
{
const_tree t1 = type1;
const_tree t2 = type2;
if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
{
t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
- if (enum_and_int_p != NULL && TREE_CODE (t2) != VOID_TYPE)
- *enum_and_int_p = true;
+ if (TREE_CODE (t2) != VOID_TYPE)
+ {
+ if (enum_and_int_p != NULL)
+ *enum_and_int_p = true;
+ if (different_types_p != NULL)
+ *different_types_p = true;
+ }
}
else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE)
{
t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
- if (enum_and_int_p != NULL && TREE_CODE (t1) != VOID_TYPE)
- *enum_and_int_p = true;
+ if (TREE_CODE (t1) != VOID_TYPE)
+ {
+ if (enum_and_int_p != NULL)
+ *enum_and_int_p = true;
+ if (different_types_p != NULL)
+ *different_types_p = true;
+ }
}
if (t1 == t2)
break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p));
+ enum_and_int_p, different_types_p));
break;
case FUNCTION_TYPE:
- val = function_types_compatible_p (t1, t2, enum_and_int_p);
+ val = function_types_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
break;
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
&& 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p)))
+ enum_and_int_p,
+ different_types_p)))
return 0;
+ if (different_types_p != NULL
+ && (d1 == 0) != (d2 == 0))
+ *different_types_p = true;
/* Sizes must match unless one is missing or variable. */
if (d1 == 0 || d2 == 0 || d1 == d2)
break;
d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
+ if (different_types_p != NULL
+ && d1_variable != d2_variable)
+ *different_types_p = true;
if (d1_variable || d2_variable)
break;
if (d1_zero && d2_zero)
break;
if (attrval != 2)
- return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
- val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
+ return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
+ val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+ different_types_p);
}
break;
case VECTOR_TYPE:
val = (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
&& comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
- enum_and_int_p));
+ enum_and_int_p, different_types_p));
break;
default:
return attrval == 2 && val == 1 ? 2 : val;
}
-/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. */
+/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring
+ their qualifiers, except for named address spaces. If the pointers point to
+ different named addresses, then we must determine if one address space is a
+ subset of the other. */
static int
comp_target_types (location_t location, tree ttl, tree ttr)
{
int val;
- tree mvl, mvr;
+ tree mvl = TREE_TYPE (ttl);
+ tree mvr = TREE_TYPE (ttr);
+ addr_space_t asl = TYPE_ADDR_SPACE (mvl);
+ addr_space_t asr = TYPE_ADDR_SPACE (mvr);
+ addr_space_t as_common;
bool enum_and_int_p;
+ /* Fail if pointers point to incompatible address spaces. */
+ if (!addr_space_superset (asl, asr, &as_common))
+ return 0;
+
/* Do not lose qualifiers on element types of array types that are
pointer targets by taking their TYPE_MAIN_VARIANT. */
- mvl = TREE_TYPE (ttl);
- mvr = TREE_TYPE (ttr);
if (TREE_CODE (mvl) != ARRAY_TYPE)
mvl = TYPE_MAIN_VARIANT (mvl);
if (TREE_CODE (mvr) != ARRAY_TYPE)
compatible. If the two types are not the same (which has been
checked earlier), this can only happen when multiple translation
units are being compiled. See C99 6.2.7 paragraph 1 for the exact
- rules. ENUM_AND_INT_P is as in comptypes_internal. */
+ rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+ comptypes_internal. */
static int
tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
tree s1, s2;
bool needs_warning = false;
if (DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p, different_types_p);
if (result != 1 && !DECL_NAME (s1))
break;
int result;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p,
+ different_types_p);
if (result != 1 && !DECL_NAME (s1))
continue;
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
- enum_and_int_p);
+ enum_and_int_p, different_types_p);
if (result == 0)
break;
if (result == 2)
Otherwise, if one type specifies only the number of arguments,
the other must specify that number of self-promoting arg types.
Otherwise, the argument types must match.
- ENUM_AND_INT_P is as in comptypes_internal. */
+ ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */
static int
function_types_compatible_p (const_tree f1, const_tree f2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
tree args1, args2;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
- val = comptypes_internal (ret1, ret2, enum_and_int_p);
+ val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p);
if (val == 0)
return 0;
args1 = TYPE_ARG_TYPES (f1);
args2 = TYPE_ARG_TYPES (f2);
+ if (different_types_p != NULL
+ && (args1 == 0) != (args2 == 0))
+ *different_types_p = true;
+
/* An unspecified parmlist matches any specified parmlist
whose argument types don't need default promotions. */
If they don't match, ask for a warning (but no error). */
if (TYPE_ACTUAL_ARG_TYPES (f1)
&& 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
- enum_and_int_p))
+ enum_and_int_p, different_types_p))
val = 2;
return val;
}
return 0;
if (TYPE_ACTUAL_ARG_TYPES (f2)
&& 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
- enum_and_int_p))
+ enum_and_int_p, different_types_p))
val = 2;
return val;
}
/* Both types have argument lists: compare them and propagate results. */
- val1 = type_lists_compatible_p (args1, args2, enum_and_int_p);
+ val1 = type_lists_compatible_p (args1, args2, enum_and_int_p,
+ different_types_p);
return val1 != 1 ? val1 : val;
}
/* Check two lists of types for compatibility, returning 0 for
incompatible, 1 for compatible, or 2 for compatible with
- warning. ENUM_AND_INT_P is as in comptypes_internal. */
+ warning. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+ comptypes_internal. */
static int
type_lists_compatible_p (const_tree args1, const_tree args2,
- bool *enum_and_int_p)
+ bool *enum_and_int_p, bool *different_types_p)
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
means there is supposed to be an argument
but nothing is specified about what type it has.
So match anything that self-promotes. */
+ if (different_types_p != NULL
+ && (a1 == 0) != (a2 == 0))
+ *different_types_p = true;
if (a1 == 0)
{
if (c_type_promotes_to (a2) != a2)
else if (TREE_CODE (a1) == ERROR_MARK
|| TREE_CODE (a2) == ERROR_MARK)
;
- else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p)))
+ else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p,
+ different_types_p)))
{
+ if (different_types_p != NULL)
+ *different_types_p = true;
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
if (TREE_CODE (a1) == UNION_TYPE
&& (TYPE_NAME (a1) == 0
- || TYPE_TRANSPARENT_UNION (a1))
+ || TYPE_TRANSPARENT_AGGR (a1))
&& TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
&& tree_int_cst_equal (TYPE_SIZE (a1),
TYPE_SIZE (a2)))
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes_internal (mv3, mv2, enum_and_int_p))
+ if (comptypes_internal (mv3, mv2, enum_and_int_p,
+ different_types_p))
break;
}
if (memb == 0)
}
else if (TREE_CODE (a2) == UNION_TYPE
&& (TYPE_NAME (a2) == 0
- || TYPE_TRANSPARENT_UNION (a2))
+ || TYPE_TRANSPARENT_AGGR (a2))
&& TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
&& tree_int_cst_equal (TYPE_SIZE (a2),
TYPE_SIZE (a1)))
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
- if (comptypes_internal (mv3, mv1, enum_and_int_p))
+ if (comptypes_internal (mv3, mv1, enum_and_int_p,
+ different_types_p))
break;
}
if (memb == 0)
return build_unary_op (loc, ADDR_EXPR, exp, 0);
}
+/* Mark EXP as read, not just set, for set but not used -Wunused
+ warning purposes. */
+
+void
+mark_exp_read (tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ DECL_READ_P (exp) = 1;
+ break;
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ CASE_CONVERT:
+ case ADDR_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 0));
+ break;
+ case COMPOUND_EXPR:
+ case C_MAYBE_CONST_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ break;
+ default:
+ break;
+ }
+}
+
/* Perform the default conversion of arrays and functions to pointers.
Return the result of converting EXP. For any other expression, just
return EXP.
return exp;
}
+struct c_expr
+default_function_array_read_conversion (location_t loc, struct c_expr exp)
+{
+ mark_exp_read (exp.value);
+ return default_function_array_conversion (loc, exp);
+}
/* EXP is an expression of integer type. Apply the integer promotions
to it and return the promoted value. */
enum tree_code code = TREE_CODE (type);
tree promoted_type;
+ mark_exp_read (exp);
+
/* Functions and arrays have been converted during parsing. */
gcc_assert (code != FUNCTION_TYPE);
if (code == ARRAY_TYPE)
return exp;
}
\f
-/* Look up COMPONENT in a structure or union DECL.
+/* Look up COMPONENT in a structure or union TYPE.
If the component name is not found, returns NULL_TREE. Otherwise,
the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
unions, the list steps down the chain to the component. */
static tree
-lookup_field (tree decl, tree component)
+lookup_field (tree type, tree component)
{
- tree type = TREE_TYPE (decl);
tree field;
/* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
- tree anon = lookup_field (field, component);
+ tree anon = lookup_field (TREE_TYPE (field), component);
if (anon)
return tree_cons (NULL_TREE, field, anon);
&& (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
{
- tree anon = lookup_field (field, component);
+ tree anon = lookup_field (TREE_TYPE (field), component);
if (anon)
return tree_cons (NULL_TREE, field, anon);
return error_mark_node;
}
- field = lookup_field (datum, component);
+ field = lookup_field (type, component);
if (!field)
{
LOC is the location to use for the generated tree. */
tree
-build_indirect_ref (location_t loc, tree ptr, const char *errorstring)
+build_indirect_ref (location_t loc, tree ptr, ref_operator errstring)
{
tree pointer = default_conversion (ptr);
tree type = TREE_TYPE (pointer);
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error_at (loc,
- "invalid type argument of %qs (have %qT)", errorstring, type);
+ switch (errstring)
+ {
+ case RO_ARRAY_INDEXING:
+ error_at (loc,
+ "invalid type argument of array indexing (have %qT)",
+ type);
+ break;
+ case RO_UNARY_STAR:
+ error_at (loc,
+ "invalid type argument of unary %<*%> (have %qT)",
+ type);
+ break;
+ case RO_ARROW:
+ error_at (loc,
+ "invalid type argument of %<->%> (have %qT)",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
return error_mark_node;
}
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
- pedwarn (loc, OPT_pedantic,
+ pedwarn (loc, OPT_pedantic,
"ISO C forbids subscripting %<register%> array");
else if (!flag_isoc99 && !lvalue_p (foo))
- pedwarn (loc, OPT_pedantic,
+ pedwarn (loc, OPT_pedantic,
"ISO C90 forbids subscripting non-lvalue array");
}
return build_indirect_ref
(loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0),
- "array indexing");
+ RO_ARRAY_INDEXING);
}
}
\f
warn_deprecated_use (ref, NULL_TREE);
/* Recursive call does not count as usage. */
- if (ref != current_function_decl)
+ if (ref != current_function_decl)
{
TREE_USED (ref) = 1;
}
tree tem;
int nargs;
tree *argarray;
-
+
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
&& !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
{
if (require_constant_value)
- result =
+ result =
fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
function, nargs, argarray);
else
{
tree typetail, val;
unsigned int parmnum;
+ bool error_args = false;
const bool type_generic = fundecl
&& lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl)));
bool type_generic_remove_excess_precision = false;
if (type == void_type_node)
{
- error ("too many arguments to function %qE", function);
+ error_at (input_location,
+ "too many arguments to function %qE", function);
+ if (fundecl && !DECL_BUILT_IN (fundecl))
+ inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
return parmnum;
}
parmval = default_conversion (val);
VEC_replace (tree, values, parmnum, parmval);
+ if (parmval == error_mark_node)
+ error_args = true;
if (typetail)
typetail = TREE_CHAIN (typetail);
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
- error ("too few arguments to function %qE", function);
+ error_at (input_location,
+ "too few arguments to function %qE", function);
+ if (fundecl && !DECL_BUILT_IN (fundecl))
+ inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
return -1;
}
- return parmnum;
+ return error_args ? -1 : (int) parmnum;
}
\f
/* This is the entry point used by the parser to build unary operators
warning_at (location, OPT_Waddress,
"comparison with string literal results in unspecified behavior");
- if (TREE_OVERFLOW_P (result.value)
- && !TREE_OVERFLOW_P (arg1.value)
+ if (TREE_OVERFLOW_P (result.value)
+ && !TREE_OVERFLOW_P (arg1.value)
&& !TREE_OVERFLOW_P (arg2.value))
overflow_warning (location, result.value);
pointer_diff (location_t loc, tree op0, tree op1)
{
tree restype = ptrdiff_type_node;
+ tree result, inttype;
+ addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
+ addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
tree target_type = TREE_TYPE (TREE_TYPE (op0));
tree con0, con1, lit0, lit1;
tree orig_op1 = op1;
+ /* If the operands point into different address spaces, we need to
+ explicitly convert them to pointers into the common address space
+ before we can subtract the numerical address values. */
+ if (as0 != as1)
+ {
+ addr_space_t as_common;
+ tree common_type;
+
+ /* Determine the common superset address space. This is guaranteed
+ to exist because the caller verified that comp_target_types
+ returned non-zero. */
+ if (!addr_space_superset (as0, as1, &as_common))
+ gcc_unreachable ();
+
+ common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1));
+ op0 = convert (common_type, op0);
+ op1 = convert (common_type, op1);
+ }
+
+ /* Determine integer type to perform computations in. This will usually
+ be the same as the result type (ptrdiff_t), but may need to be a wider
+ type if pointers for the address space are wider than ptrdiff_t. */
+ if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
+ inttype = lang_hooks.types.type_for_size
+ (TYPE_PRECISION (TREE_TYPE (op0)), 0);
+ else
+ inttype = restype;
+
+
if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"pointer of type %<void *%> used in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
- pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"pointer to a function used in subtraction");
/* If the conversion to ptrdiff_type does anything like widening or
in case restype is a short type. */
op0 = build_binary_op (loc,
- MINUS_EXPR, convert (restype, op0),
- convert (restype, op1), 0);
+ MINUS_EXPR, convert (inttype, op0),
+ convert (inttype, op1), 0);
/* This generates an error if op1 is pointer to incomplete type. */
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
error_at (loc, "arithmetic on pointer to an incomplete type");
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold_build2_loc (loc, EXACT_DIV_EXPR, restype,
- op0, convert (restype, op1));
+ result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype,
+ op0, convert (inttype, op1));
+
+ /* Convert to final result type if necessary. */
+ return convert (restype, result);
}
\f
/* Construct and perhaps optimize a tree representation
else if (typecode == COMPLEX_TYPE)
{
code = CONJ_EXPR;
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C does not support %<~%> for complex conjugation");
if (!noconvert)
arg = default_conversion (arg);
{
tree real, imag;
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C does not support %<++%> and %<--%> on complex types");
arg = stabilize_reference (arg);
|| TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE)
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"wrong type argument to increment");
else
- pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"wrong type argument to decrement");
}
argtype = TREE_TYPE (arg);
/* If the lvalue is const or volatile, merge that into the type
- to which the address will point. Note that you can't get a
- restricted pointer by taking the address of something, so we
- only have to deal with `const' and `volatile' here. */
+ to which the address will point. This should only be needed
+ for function types. */
if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
&& (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
- argtype = c_build_type_variant (argtype,
- TREE_READONLY (arg),
- TREE_THIS_VOLATILE (arg));
+ {
+ int orig_quals = TYPE_QUALS (strip_array_types (argtype));
+ int quals = orig_quals;
+
+ if (TREE_READONLY (arg))
+ quals |= TYPE_QUAL_CONST;
+ if (TREE_THIS_VOLATILE (arg))
+ quals |= TYPE_QUAL_VOLATILE;
+
+ gcc_assert (quals == orig_quals
+ || TREE_CODE (argtype) == FUNCTION_TYPE);
+
+ argtype = c_build_qualified_type (argtype, quals);
+ }
if (!c_mark_addressable (arg))
return error_mark_node;
}
}
\f
+/* Convert EXPR to TYPE, warning about conversion problems with
+ constants. SEMANTIC_TYPE is the type this conversion would use
+ without excess precision. If SEMANTIC_TYPE is NULL, this function
+ is equivalent to convert_and_check. This function is a wrapper that
+ handles conversions that may be different than
+ the usual ones because of excess precision. */
+
+static tree
+ep_convert_and_check (tree type, tree expr, tree semantic_type)
+{
+ if (TREE_TYPE (expr) == type)
+ return expr;
+
+ if (!semantic_type)
+ return convert_and_check (type, expr);
+
+ if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ && TREE_TYPE (expr) != semantic_type)
+ {
+ /* For integers, we need to check the real conversion, not
+ the conversion to the excess precision type. */
+ expr = convert_and_check (semantic_type, expr);
+ }
+ /* Result type is the excess precision type, which should be
+ large enough, so do not check. */
+ return convert (type, expr);
+}
+
/* Build and return a conditional expression IFEXP ? OP1 : OP2. If
IFEXP_BCP then the condition is a call to __builtin_constant_p, and
if folded to an integer constant then the unselected half may
enum tree_code code1;
enum tree_code code2;
tree result_type = NULL;
- tree ep_result_type = NULL;
+ tree semantic_result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
bool int_const, op1_int_operands, op2_int_operands, int_operands;
bool ifexp_int_operands;
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE
|| code2 == COMPLEX_TYPE))
{
- ep_result_type = c_common_type (type1, type2);
+ semantic_result_type = c_common_type (type1, type2);
if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
{
op1 = TREE_OPERAND (op1, 0);
that folding in this case even without
warn_sign_compare to avoid warning options
possibly affecting code generation. */
+ c_inhibit_evaluation_warnings
+ += (ifexp == truthvalue_false_node);
op1 = c_fully_fold (op1, require_constant_value,
&op1_maybe_const);
+ c_inhibit_evaluation_warnings
+ -= (ifexp == truthvalue_false_node);
+
+ c_inhibit_evaluation_warnings
+ += (ifexp == truthvalue_true_node);
op2 = c_fully_fold (op2, require_constant_value,
&op2_maybe_const);
+ c_inhibit_evaluation_warnings
+ -= (ifexp == truthvalue_true_node);
if (warn_sign_compare)
{
"conditional expression"));
}
if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
- {
- op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
- NULL, op1);
- C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
- }
+ op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
- {
- op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2),
- NULL, op2);
- C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const;
- }
+ op2 = c_wrap_maybe_const (op2, !op2_maybe_const);
}
}
}
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
+ addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+ addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2));
+ addr_space_t as_common;
+
if (comp_target_types (colon_loc, type1, type2))
result_type = common_pointer_type (type1, type2);
else if (null_pointer_constant_p (orig_op1))
- result_type = qualify_type (type2, type1);
+ result_type = type2;
else if (null_pointer_constant_p (orig_op2))
- result_type = qualify_type (type1, type2);
+ result_type = type1;
+ else if (!addr_space_superset (as1, as2, &as_common))
+ {
+ error_at (colon_loc, "pointers to disjoint address spaces "
+ "used in conditional expression");
+ return error_mark_node;
+ }
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
}
else
{
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+
if (!objc_ok)
pedwarn (colon_loc, 0,
"pointer type mismatch in conditional expression");
- result_type = build_pointer_type (void_type_node);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
/* Merge const and volatile flags of the incoming types. */
result_type
= build_type_variant (result_type,
- TREE_READONLY (op1) || TREE_READONLY (op2),
- TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
+ TYPE_READONLY (type1) || TYPE_READONLY (type2),
+ TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2));
- if (result_type != TREE_TYPE (op1))
- op1 = convert_and_check (result_type, op1);
- if (result_type != TREE_TYPE (op2))
- op2 = convert_and_check (result_type, op2);
+ op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
+ op2 = ep_convert_and_check (result_type, op2, semantic_result_type);
if (ifexp_bcp && ifexp == truthvalue_true_node)
{
if (int_operands)
ret = note_integer_operands (ret);
}
- if (ep_result_type)
- ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
+ if (semantic_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
protected_set_expr_location (ret, colon_loc);
return ret;
&& CONVERT_EXPR_P (TREE_OPERAND (expr1, 1)))
; /* (void) a, (void) b, c */
else
- warning_at (loc, OPT_Wunused_value,
+ warning_at (loc, OPT_Wunused_value,
"left-hand operand of comma expression has no effect");
}
}
/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to
which we are casting. OTYPE is the type of the expression being
- cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared
- on the command line. */
+ cast. Both TYPE and OTYPE are pointer types. LOC is the location
+ of the cast. -Wcast-qual appeared on the command line. Named
+ address space qualifiers are not handled here, because they result
+ in different warnings. */
static void
-handle_warn_cast_qual (tree type, tree otype)
+handle_warn_cast_qual (location_t loc, tree type, tree otype)
{
tree in_type = type;
tree in_otype = otype;
taken away. */
if (TREE_CODE (in_otype) == FUNCTION_TYPE
&& TREE_CODE (in_type) == FUNCTION_TYPE)
- added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+ added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
else
- discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+ discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));
}
while (TREE_CODE (in_type) == POINTER_TYPE
&& TREE_CODE (in_otype) == POINTER_TYPE);
if (added)
- warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
+ warning_at (loc, OPT_Wcast_qual,
+ "cast adds %q#v qualifier to function type", added);
if (discarded)
/* There are qualifiers present in IN_OTYPE that are not present
in IN_TYPE. */
- warning (OPT_Wcast_qual,
- "cast discards qualifiers from pointer target type");
+ warning_at (loc, OPT_Wcast_qual,
+ "cast discards %q#v qualifier from pointer target type",
+ discarded);
if (added || discarded)
return;
if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
&& !is_const)
{
- warning (OPT_Wcast_qual,
- ("new qualifiers in middle of multi-level non-const cast "
- "are unsafe"));
+ warning_at (loc, OPT_Wcast_qual,
+ "to be safe all intermediate pointers in cast from "
+ "%qT to %qT must be %<const%> qualified",
+ otype, type);
break;
}
if (is_const)
while (TREE_CODE (in_type) == POINTER_TYPE);
}
-/* Build an expression representing a cast to type TYPE of expression EXPR.
+/* Build an expression representing a cast to type TYPE of expression EXPR.
LOC is the location of the cast-- typically the open paren of the cast. */
tree
{
if (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
- pedwarn (loc, OPT_pedantic,
+ pedwarn (loc, OPT_pedantic,
"ISO C forbids casting nonscalar to the same type");
}
else if (TREE_CODE (type) == UNION_TYPE)
if (field)
{
tree t;
+ bool maybe_const = true;
pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type");
- t = digest_init (loc, type,
- build_constructor_single (type, field, value),
+ t = c_fully_fold (value, false, &maybe_const);
+ t = build_constructor_single (type, field, t);
+ if (!maybe_const)
+ t = c_wrap_maybe_const (t, true);
+ t = digest_init (loc, type, t,
NULL_TREE, false, true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
return t;
if (warn_cast_qual
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE)
- handle_warn_cast_qual (type, otype);
+ handle_warn_cast_qual (loc, type, otype);
+
+ /* Warn about conversions between pointers to disjoint
+ address spaces. */
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && !null_pointer_constant_p (value))
+ {
+ addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+ addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype));
+ addr_space_t as_common;
+
+ if (!addr_space_superset (as_to, as_from, &as_common))
+ {
+ if (ADDR_SPACE_GENERIC_P (as_from))
+ warning_at (loc, 0, "cast to %s address space pointer "
+ "from disjoint generic address space pointer",
+ c_addr_space_name (as_to));
+
+ else if (ADDR_SPACE_GENERIC_P (as_to))
+ warning_at (loc, 0, "cast to generic address space pointer "
+ "from disjoint %s address space pointer",
+ c_addr_space_name (as_from));
+
+ else
+ warning_at (loc, 0, "cast to %s address space pointer "
+ "from disjoint %s address space pointer",
+ c_addr_space_name (as_to),
+ c_addr_space_name (as_from));
+ }
+ }
/* Warn about possible alignment problems. */
if (STRICT_ALIGNMENT
tree
build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
- enum tree_code modifycode,
+ enum tree_code modifycode,
location_t rhs_loc, tree rhs, tree rhs_origtype)
{
tree result;
pedwarn (LOCATION, OPT, AS); \
break; \
case ic_init: \
- pedwarn (LOCATION, OPT, IN); \
+ pedwarn_init (LOCATION, OPT, IN); \
break; \
case ic_return: \
pedwarn (LOCATION, OPT, RE); \
} \
} while (0)
+ /* This macro is used to emit diagnostics to ensure that all format
+ strings are complete sentences, visible to gettext and checked at
+ compile time. It is the same as WARN_FOR_ASSIGNMENT but with an
+ extra parameter to enumerate qualifiers. */
+
+#define WARN_FOR_QUALIFIERS(LOCATION, OPT, AR, AS, IN, RE, QUALS) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ if (pedwarn (LOCATION, OPT, AR, parmnum, rname, QUALS)) \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_assign: \
+ pedwarn (LOCATION, OPT, AS, QUALS); \
+ break; \
+ case ic_init: \
+ pedwarn (LOCATION, OPT, IN, QUALS); \
+ break; \
+ case ic_return: \
+ pedwarn (LOCATION, OPT, RE, QUALS); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } while (0)
+
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
rhs = TREE_OPERAND (rhs, 0);
&& comptypes (type, rhstype))
return convert_and_check (type, rhs);
- /* Conversion to a transparent union from its member types.
+ /* Conversion to a transparent union or record from its member types.
This applies only to function arguments. */
- if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
+ if (((codel == UNION_TYPE || codel == RECORD_TYPE)
+ && TYPE_TRANSPARENT_AGGR (type))
&& errtype == ic_argpass)
{
tree memb, marginal_memb = NULL_TREE;
certain things, it is okay to use a const or volatile
function where an ordinary one is wanted, but not
vice-versa. */
- if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- WARN_FOR_ASSIGNMENT (location, 0,
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE "
- "makes qualified function "
+ "makes %q#v qualified function "
"pointer from unqualified"),
- G_("assignment makes qualified "
+ G_("assignment makes %q#v qualified "
"function pointer from "
"unqualified"),
- G_("initialization makes qualified "
+ G_("initialization makes %q#v qualified "
"function pointer from "
"unqualified"),
- G_("return makes qualified function "
- "pointer from unqualified"));
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
- else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (location, 0,
+ else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- G_("assignment discards qualifiers "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
"from pointer target type"),
- G_("initialization discards qualifiers "
+ G_("initialization discards %qv qualifier "
"from pointer target type"),
- G_("return discards qualifiers from "
- "pointer target type"));
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
memb = marginal_memb;
}
if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ISO C prohibits argument conversion to union type");
rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs);
tree mvr = ttr;
bool is_opaque_pointer;
int target_cmp = 0; /* Cache comp_target_types () result. */
+ addr_space_t asl;
+ addr_space_t asr;
if (TREE_CODE (mvl) != ARRAY_TYPE)
mvl = TYPE_MAIN_VARIANT (mvl);
"request for implicit conversion "
"from %qT to %qT not permitted in C++", rhstype, type);
+ /* See if the pointers point to incompatible address spaces. */
+ asl = TYPE_ADDR_SPACE (ttl);
+ asr = TYPE_ADDR_SPACE (ttr);
+ if (!null_pointer_constant_p (rhs)
+ && asr != asl && !targetm.addr_space.subset_p (asr, asl))
+ {
+ switch (errtype)
+ {
+ case ic_argpass:
+ error_at (location, "passing argument %d of %qE from pointer to "
+ "non-enclosed address space", parmnum, rname);
+ break;
+ case ic_assign:
+ error_at (location, "assignment from pointer to "
+ "non-enclosed address space");
+ break;
+ case ic_init:
+ error_at (location, "initialization from pointer to "
+ "non-enclosed address space");
+ break;
+ case ic_return:
+ error_at (location, "return from pointer to "
+ "non-enclosed address space");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+ }
+
/* Check if the right-hand side has a format attribute but the
left-hand side doesn't. */
if (warn_missing_format_attribute
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
- if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
{
/* Types differing only by the presence of the 'volatile'
qualifier are acceptable if the 'volatile' has been added
in by the Objective-C EH machinery. */
if (!objc_type_quals_match (ttl, ttr))
- WARN_FOR_ASSIGNMENT (location, 0,
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- G_("assignment discards qualifiers "
+ "%qv qualifier from pointer target type"),
+ G_("assignment discards %qv qualifier "
"from pointer target type"),
- G_("initialization discards qualifiers "
+ G_("initialization discards %qv qualifier "
"from pointer target type"),
- G_("return discards qualifiers from "
- "pointer target type"));
+ G_("return discards %qv qualifier from "
+ "pointer target type"),
+ TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
}
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
that say the function will not do certain things,
it is okay to use a const or volatile function
where an ordinary one is wanted, but not vice-versa. */
- if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- WARN_FOR_ASSIGNMENT (location, 0,
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+ WARN_FOR_QUALIFIERS (location, 0,
G_("passing argument %d of %qE makes "
- "qualified function pointer "
+ "%q#v qualified function pointer "
"from unqualified"),
- G_("assignment makes qualified function "
+ G_("assignment makes %q#v qualified function "
"pointer from unqualified"),
- G_("initialization makes qualified "
+ G_("initialization makes %q#v qualified "
"function pointer from unqualified"),
- G_("return makes qualified function "
- "pointer from unqualified"));
+ G_("return makes %q#v qualified function "
+ "pointer from unqualified"),
+ TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
}
}
else
/* ANSI wants warnings about out-of-range constant initializers. */
STRIP_TYPE_NOPS (value);
- if (TREE_STATIC (decl))
+ if (TREE_STATIC (decl))
constant_expression_warning (value);
/* Check if we need to set array size from compound literal size. */
}
/* Issue an error message for a bad initializer component.
- MSGID identifies the message.
+ GMSGID identifies the message.
The component name is taken from the spelling stack. */
void
-error_init (const char *msgid)
+error_init (const char *gmsgid)
{
char *ofwhat;
- error ("%s", _(msgid));
+ /* The gmsgid may be a format string with %< and %>. */
+ error (gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
error ("(near initialization for %qs)", ofwhat);
/* Issue a pedantic warning for a bad initializer component. OPT is
the option OPT_* (from options.h) controlling this warning or 0 if
- it is unconditionally given. MSGID identifies the message. The
+ it is unconditionally given. GMSGID identifies the message. The
component name is taken from the spelling stack. */
void
-pedwarn_init (location_t location, int opt, const char *msgid)
+pedwarn_init (location_t location, int opt, const char *gmsgid)
{
char *ofwhat;
-
- pedwarn (location, opt, "%s", _(msgid));
+
+ /* The gmsgid may be a format string with %< and %>. */
+ pedwarn (location, opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
pedwarn (location, opt, "(near initialization for %qs)", ofwhat);
}
-/* Issue a warning for a bad initializer component.
+/* Issue a warning for a bad initializer component.
OPT is the OPT_W* value corresponding to the warning option that
- controls this warning. MSGID identifies the message. The
+ controls this warning. GMSGID identifies the message. The
component name is taken from the spelling stack. */
static void
-warning_init (int opt, const char *msgid)
+warning_init (int opt, const char *gmsgid)
{
char *ofwhat;
- warning (opt, "%s", _(msgid));
+ /* The gmsgid may be a format string with %< and %>. */
+ warning (opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
warning (opt, "(near initialization for %qs)", ofwhat);
&& TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (expr.value) == STRING_CST
&& expr.original_code != STRING_CST)
- pedwarn_init (input_location, OPT_pedantic,
+ pedwarn_init (input_location, OPT_pedantic,
"array initialized from parenthesized string constant");
}
IMPLICIT is 1 (or 2 if the push is because of designator list). */
void
-push_init_level (int implicit)
+push_init_level (int implicit, struct obstack * braced_init_obstack)
{
struct constructor_stack *p;
tree value = NULL_TREE;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& constructor_max_index
&& tree_int_cst_lt (constructor_max_index,
constructor_index))
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else
break;
}
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields)
- value = find_init_member (constructor_fields);
+ value = find_init_member (constructor_fields, braced_init_obstack);
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- value = find_init_member (constructor_index);
+ value = find_init_member (constructor_index, braced_init_obstack);
}
p = XNEW (struct constructor_stack);
if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == ARRAY_TYPE))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
}
if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
/* We need to split the char/wchar array into individual
characters, so that we don't have to special case it
everywhere. */
- set_nonincremental_init_from_string (value);
+ set_nonincremental_init_from_string (value, braced_init_obstack);
}
}
else
Otherwise, return a CONSTRUCTOR expression as the value. */
struct c_expr
-pop_init_level (int implicit)
+pop_init_level (int implicit, struct obstack * braced_init_obstack)
{
struct constructor_stack *p;
struct c_expr ret;
/* When we come to an explicit close brace,
pop any inner levels that didn't have explicit braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1), true);
-
+ {
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
+ }
gcc_assert (!constructor_range_stack);
}
/* Now output all pending elements. */
constructor_incremental = 1;
- output_pending_init_elements (1);
+ output_pending_init_elements (1, braced_init_obstack);
p = constructor_stack;
ARRAY argument is nonzero for array ranges. Returns zero for success. */
static int
-set_designator (int array)
+set_designator (int array, struct obstack * braced_init_obstack)
{
tree subtype;
enum tree_code subcode;
/* Designator list starts at the level of closest explicit
braces. */
while (constructor_stack->implicit)
- process_init_element (pop_init_level (1), true);
+ {
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
+ }
constructor_designated = 1;
return 0;
}
}
constructor_designated = 1;
- push_init_level (2);
+ push_init_level (2, braced_init_obstack);
return 0;
}
NULL_TREE if there is no range designator at this level. */
static void
-push_range_stack (tree range_end)
+push_range_stack (tree range_end, struct obstack * braced_init_obstack)
{
struct constructor_range_stack *p;
- p = GGC_NEW (struct constructor_range_stack);
+ p = (struct constructor_range_stack *)
+ obstack_alloc (braced_init_obstack,
+ sizeof (struct constructor_range_stack));
p->prev = constructor_range_stack;
p->next = 0;
p->fields = constructor_fields;
of indices, running from FIRST through LAST. */
void
-set_init_index (tree first, tree last)
+set_init_index (tree first, tree last,
+ struct obstack * braced_init_obstack)
{
- if (set_designator (1))
+ if (set_designator (1, braced_init_obstack))
return;
designator_erroneous = 1;
designator_depth++;
designator_erroneous = 0;
if (constructor_range_stack || last)
- push_range_stack (last);
+ push_range_stack (last, braced_init_obstack);
}
}
/* Within a struct initializer, specify the next field to be initialized. */
void
-set_init_label (tree fieldname)
+set_init_label (tree fieldname, struct obstack * braced_init_obstack)
{
- tree tail;
+ tree field;
- if (set_designator (0))
+ if (set_designator (0, braced_init_obstack))
return;
designator_erroneous = 1;
return;
}
- for (tail = TYPE_FIELDS (constructor_type); tail;
- tail = TREE_CHAIN (tail))
- {
- if (DECL_NAME (tail) == fieldname)
- break;
- }
+ field = lookup_field (constructor_type, fieldname);
- if (tail == 0)
+ if (field == 0)
error ("unknown field %qE specified in initializer", fieldname);
else
- {
- constructor_fields = tail;
- designator_depth++;
- designator_erroneous = 0;
- if (constructor_range_stack)
- push_range_stack (NULL_TREE);
- }
+ do
+ {
+ constructor_fields = TREE_VALUE (field);
+ designator_depth++;
+ designator_erroneous = 0;
+ if (constructor_range_stack)
+ push_range_stack (NULL_TREE, braced_init_obstack);
+ field = TREE_CHAIN (field);
+ if (field)
+ {
+ if (set_designator (0, braced_init_obstack))
+ return;
+ }
+ }
+ while (field != NULL_TREE);
}
\f
/* Add a new initializer to the tree of pending initializers. PURPOSE
existing initializer. */
static void
-add_pending_init (tree purpose, tree value, tree origtype, bool implicit)
+add_pending_init (tree purpose, tree value, tree origtype, bool implicit,
+ struct obstack * braced_init_obstack)
{
struct init_node *p, **q, *r;
}
}
- r = GGC_NEW (struct init_node);
+ r = (struct init_node *) obstack_alloc (braced_init_obstack,
+ sizeof (struct init_node));
r->purpose = purpose;
r->value = value;
r->origtype = origtype;
/* Build AVL tree from a sorted chain. */
static void
-set_nonincremental_init (void)
+set_nonincremental_init (struct obstack * braced_init_obstack)
{
unsigned HOST_WIDE_INT ix;
tree index, value;
return;
FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
- add_pending_init (index, value, NULL_TREE, false);
+ {
+ add_pending_init (index, value, NULL_TREE, false,
+ braced_init_obstack);
+ }
constructor_elements = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
/* Build AVL tree from a string constant. */
static void
-set_nonincremental_init_from_string (tree str)
+set_nonincremental_init_from_string (tree str,
+ struct obstack * braced_init_obstack)
{
tree value, purpose, type;
HOST_WIDE_INT val[2];
}
value = build_int_cst_wide (type, val[1], val[0]);
- add_pending_init (purpose, value, NULL_TREE, false);
+ add_pending_init (purpose, value, NULL_TREE, false,
+ braced_init_obstack);
}
constructor_incremental = 0;
not initialized yet. */
static tree
-find_init_member (tree field)
+find_init_member (tree field, struct obstack * braced_init_obstack)
{
struct init_node *p;
{
if (constructor_incremental
&& tree_int_cst_lt (field, constructor_unfilled_index))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
p = constructor_pending_elts;
while (p)
&& (!constructor_unfilled_fields
|| tree_int_cst_lt (bitpos,
bit_position (constructor_unfilled_fields))))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
p = constructor_pending_elts;
while (p)
static void
output_init_element (tree value, tree origtype, bool strict_string, tree type,
- tree field, int pending, bool implicit)
+ tree field, int pending, bool implicit,
+ struct obstack * braced_init_obstack)
{
tree semantic_type = NULL_TREE;
constructor_elt *celt;
{
if (constructor_incremental
&& tree_int_cst_lt (field, constructor_unfilled_index))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
- add_pending_init (field, value, origtype, implicit);
+ add_pending_init (field, value, origtype, implicit,
+ braced_init_obstack);
return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
if (constructor_incremental)
{
if (!constructor_unfilled_fields)
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
else
{
tree bitpos, unfillpos;
unfillpos = bit_position (constructor_unfilled_fields);
if (tree_int_cst_lt (bitpos, unfillpos))
- set_nonincremental_init ();
+ set_nonincremental_init (braced_init_obstack);
}
}
- add_pending_init (field, value, origtype, implicit);
+ add_pending_init (field, value, origtype, implicit,
+ braced_init_obstack);
return;
}
else if (TREE_CODE (constructor_type) == UNION_TYPE
/* Now output any pending elements which have become next. */
if (pending)
- output_pending_init_elements (0);
+ output_pending_init_elements (0, braced_init_obstack);
}
/* Output any pending elements which have become next.
If ALL is 1, we output space as necessary so that
we can output all the pending elements. */
-
static void
-output_pending_init_elements (int all)
+output_pending_init_elements (int all, struct obstack * braced_init_obstack)
{
struct init_node *elt = constructor_pending_elts;
tree next;
constructor_unfilled_index))
output_init_element (elt->value, elt->origtype, true,
TREE_TYPE (constructor_type),
- constructor_unfilled_index, 0, false);
+ constructor_unfilled_index, 0, false,
+ braced_init_obstack);
else if (tree_int_cst_lt (constructor_unfilled_index,
elt->purpose))
{
constructor_unfilled_fields = elt->purpose;
output_init_element (elt->value, elt->origtype, true,
TREE_TYPE (elt->purpose),
- elt->purpose, 0, false);
+ elt->purpose, 0, false,
+ braced_init_obstack);
}
else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
{
existing initializer. */
void
-process_init_element (struct c_expr value, bool implicit)
+process_init_element (struct c_expr value, bool implicit,
+ struct obstack * braced_init_obstack)
{
tree orig_value = value.value;
int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
if ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
&& constructor_fields == 0)
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else if ((TREE_CODE (constructor_type) == ARRAY_TYPE
|| TREE_CODE (constructor_type) == VECTOR_TYPE)
&& (constructor_max_index == 0
|| tree_int_cst_lt (constructor_max_index,
constructor_index)))
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
else
break;
}
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_member_name (constructor_fields);
output_init_element (value.value, value.original_type,
strict_string, fieldtype,
- constructor_fields, 1, implicit);
+ constructor_fields, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
&& (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
|| fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_member_name (constructor_fields);
output_init_element (value.value, value.original_type,
strict_string, fieldtype,
- constructor_fields, 1, implicit);
+ constructor_fields, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
else
&& (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
|| eltcode == UNION_TYPE || eltcode == VECTOR_TYPE))
{
- push_init_level (1);
+ push_init_level (1, braced_init_obstack);
continue;
}
push_array_bounds (tree_low_cst (constructor_index, 1));
output_init_element (value.value, value.original_type,
strict_string, elttype,
- constructor_index, 1, implicit);
+ constructor_index, 1, implicit,
+ braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
}
elttype = TYPE_MAIN_VARIANT (constructor_type);
output_init_element (value.value, value.original_type,
strict_string, elttype,
- constructor_index, 1, implicit);
+ constructor_index, 1, implicit,
+ braced_init_obstack);
}
constructor_index
if (value.value)
output_init_element (value.value, value.original_type,
strict_string, constructor_type,
- NULL_TREE, 1, implicit);
+ NULL_TREE, 1, implicit,
+ braced_init_obstack);
constructor_fields = 0;
}
while (constructor_stack != range_stack->stack)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1,
+ braced_init_obstack),
+ true, braced_init_obstack);
}
for (p = range_stack;
!p->range_end || tree_int_cst_equal (p->index, p->range_end);
p = p->prev)
{
gcc_assert (constructor_stack->implicit);
- process_init_element (pop_init_level (1), true);
+ process_init_element (pop_init_level (1, braced_init_obstack),
+ true, braced_init_obstack);
}
p->index = size_binop_loc (input_location,
p = p->next;
if (!p)
break;
- push_init_level (2);
+ push_init_level (2, braced_init_obstack);
p->stack = constructor_stack;
if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
p->index = p->range_start;
are subtly different. We use a ASM_EXPR node to represent this. */
tree
build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
- tree clobbers, bool simple)
+ tree clobbers, tree labels, bool simple)
{
tree tail;
tree args;
noutputs = list_length (outputs);
oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
- string = resolve_asm_operand_names (string, outputs, inputs);
+ string = resolve_asm_operand_names (string, outputs, inputs, labels);
/* Remove output conversions that change the type but not the mode. */
for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = input;
}
- args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers);
+ /* ASMs with labels cannot have outputs. This should have been
+ enforced by the parser. */
+ gcc_assert (outputs == NULL || labels == NULL);
+
+ args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels);
/* asm statements without outputs, including simple ones, are treated
as volatile. */
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
{
- pedwarn_c99 (loc, flag_isoc99 ? 0 : OPT_Wreturn_type,
+ pedwarn_c99 (loc, flag_isoc99 ? 0 : OPT_Wreturn_type,
"%<return%> with no value, in "
"function returning non-void");
no_warning = true;
{
current_function_returns_null = 1;
if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn (loc, 0,
+ pedwarn (loc, 0,
"%<return%> with a value, in function returning void");
- else
+ else
pedwarn (loc, OPT_pedantic, "ISO C forbids "
"%<return%> with expression, in function returning void");
}
tree
c_process_expr_stmt (location_t loc, tree expr)
{
+ tree exprv;
+
if (!expr)
return NULL_TREE;
&& warn_unused_value)
emit_side_effect_warnings (loc, expr);
+ exprv = expr;
+ while (TREE_CODE (exprv) == COMPOUND_EXPR)
+ exprv = TREE_OPERAND (exprv, 1);
+ if (DECL_P (exprv) || handled_component_p (exprv))
+ mark_exp_read (exprv);
+
/* If the expression is not of a type to which we cannot assign a line
number, wrap the thing in a no-op NOP_EXPR. */
if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
goto continue_searching;
}
+ if (last == error_mark_node)
+ return last;
+
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
- if (last == error_mark_node
- || (last == BIND_EXPR_BODY (body)
- && BIND_EXPR_VARS (body) == NULL))
+ if (last == BIND_EXPR_BODY (body)
+ && BIND_EXPR_VARS (body) == NULL)
{
/* Even if this looks constant, do not allow it in a constant
expression. */
- last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
- C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
+ last = c_wrap_maybe_const (last, true);
/* Do not warn if the return value of a statement expression is
unused. */
TREE_NO_WARNING (last) = 1;
/* When the computation is in excess precision, the type of the
final EXCESS_PRECISION_EXPR. */
- tree real_result_type = NULL;
+ tree semantic_result_type = NULL;
/* Nonzero means operands have already been type-converted
in whatever way is necessary.
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
short_compare = 1;
+ else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
+ {
+ if (TREE_CODE (op0) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
+ {
+ if (code == EQ_EXPR)
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<false%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op0, 0));
+ else
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<true%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op0, 0));
+ }
+ result_type = type0;
+ }
+ else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
+ {
+ if (TREE_CODE (op1) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
+ {
+ if (code == EQ_EXPR)
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<false%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ else
+ warning_at (location,
+ OPT_Waddress,
+ "the comparison will always evaluate as %<true%> "
+ "for the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ }
+ result_type = type1;
+ }
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
tree tt0 = TREE_TYPE (type0);
tree tt1 = TREE_TYPE (type1);
+ addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
+ addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
+ addr_space_t as_common = ADDR_SPACE_GENERIC;
+
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
if (comp_target_types (location, type0, type1))
result_type = common_pointer_type (type0, type1);
+ else if (!addr_space_superset (as0, as1, &as_common))
+ {
+ error_at (location, "comparison of pointers to "
+ "disjoint address spaces");
+ return error_mark_node;
+ }
else if (VOID_TYPE_P (tt0))
{
- /* op0 != orig_op0 detects the case of something
- whose value is 0 but which isn't a valid null ptr const. */
- if (pedantic && !null_pointer_constant_p (orig_op0)
- && TREE_CODE (tt1) == FUNCTION_TYPE)
+ if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"comparison of %<void *%> with function pointer");
}
else if (VOID_TYPE_P (tt1))
{
- if (pedantic && !null_pointer_constant_p (orig_op1)
- && TREE_CODE (tt0) == FUNCTION_TYPE)
+ if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"comparison of %<void *%> with function pointer");
}
"comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
- result_type = ptr_type_node;
- }
- else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
- {
- if (TREE_CODE (op0) == ADDR_EXPR
- && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
- warning_at (location,
- OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op0, 0));
- result_type = type0;
- }
- else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
- {
- if (TREE_CODE (op1) == ADDR_EXPR
- && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
- warning_at (location,
- OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op1, 0));
- result_type = type1;
+ {
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
+ }
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
+ addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
+ addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+ addr_space_t as_common;
+
if (comp_target_types (location, type0, type1))
{
result_type = common_pointer_type (type0, type1);
else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"ordered comparisons of pointers to functions");
+ else if (null_pointer_constant_p (orig_op0)
+ || null_pointer_constant_p (orig_op1))
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with null pointer");
+
+ }
+ else if (!addr_space_superset (as0, as1, &as_common))
+ {
+ error_at (location, "comparison of pointers to "
+ "disjoint address spaces");
+ return error_mark_node;
}
else
{
- result_type = ptr_type_node;
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
pedwarn (location, 0,
"comparison of distinct pointer types lacks a cast");
}
{
result_type = type0;
if (pedantic)
- pedwarn (location, OPT_pedantic,
+ pedwarn (location, OPT_pedantic,
"ordered comparison of pointer with integer zero");
else if (extra_warnings)
warning_at (location, OPT_Wextra,
- "ordered comparison of pointer with integer zero");
+ "ordered comparison of pointer with integer zero");
}
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
{
result_type = type1;
- pedwarn (location, OPT_pedantic,
- "ordered comparison of pointer with integer zero");
+ if (pedantic)
+ pedwarn (location, OPT_pedantic,
+ "ordered comparison of pointer with integer zero");
+ else if (extra_warnings)
+ warning_at (location, OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
if (type0 != orig_type0 || type1 != orig_type1)
{
gcc_assert (may_need_excess_precision && common);
- real_result_type = c_common_type (orig_type0, orig_type1);
+ semantic_result_type = c_common_type (orig_type0, orig_type1);
}
if (first_complex)
{
if (shorten && none_complex)
{
final_type = result_type;
- result_type = shorten_binary_op (result_type, op0, op1,
+ result_type = shorten_binary_op (result_type, op0, op1,
shorten == -1);
}
unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+ && tree_int_cst_sgn (op1) > 0
/* 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
build_conditional_expr. This requires the
"original" values to be folded, not just op0 and
op1. */
+ c_inhibit_evaluation_warnings++;
op0 = c_fully_fold (op0, require_constant_value,
&op0_maybe_const);
op1 = c_fully_fold (op1, require_constant_value,
&op1_maybe_const);
+ c_inhibit_evaluation_warnings--;
orig_op0_folded = c_fully_fold (orig_op0,
require_constant_value,
NULL);
if (!in_late_binary_op)
{
if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
- {
- op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0),
- NULL, op0);
- C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const;
- }
+ op0 = c_wrap_maybe_const (op0, !op0_maybe_const);
if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
- {
- op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
- NULL, op1);
- C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
- }
+ op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
}
}
}
return error_mark_node;
}
- if (!converted)
- {
- if (TREE_TYPE (op0) != result_type)
- op0 = convert_and_check (result_type, op0);
- if (TREE_TYPE (op1) != result_type)
- op1 = convert_and_check (result_type, op1);
-
- /* This can happen if one operand has a vector type, and the other
- has a different type. */
- if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
- return error_mark_node;
- }
-
if (build_type == NULL_TREE)
{
build_type = result_type;
if (type0 != orig_type0 || type1 != orig_type1)
{
gcc_assert (may_need_excess_precision && common);
- real_result_type = c_common_type (orig_type0, orig_type1);
+ semantic_result_type = c_common_type (orig_type0, orig_type1);
}
}
+ if (!converted)
+ {
+ op0 = ep_convert_and_check (result_type, op0, semantic_result_type);
+ op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
+
+ /* This can happen if one operand has a vector type, and the other
+ has a different type. */
+ if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
+ }
+
/* Treat expressions in initializers specially as they can't trap. */
if (int_const_or_overflow)
ret = (require_constant_value
else if (TREE_CODE (ret) != INTEGER_CST && int_operands
&& !in_late_binary_op)
ret = note_integer_operands (ret);
- if (real_result_type)
- ret = build1 (EXCESS_PRECISION_EXPR, real_result_type, ret);
+ if (semantic_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
protected_set_expr_location (ret, location);
return ret;
}
else if (TYPE_CANONICAL (element_type) != element_type
|| (domain && TYPE_CANONICAL (domain) != domain))
{
- tree unqualified_canon
+ tree unqualified_canon
= build_array_type (TYPE_CANONICAL (element_type),
- domain? TYPE_CANONICAL (domain)
+ domain? TYPE_CANONICAL (domain)
: NULL_TREE);
- TYPE_CANONICAL (t)
+ TYPE_CANONICAL (t)
= c_build_qualified_type (unqualified_canon, type_quals);
}
else