/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file is part of the C front end.
#include "ggc.h"
#include "target.h"
#include "tree-iterator.h"
-#include "tree-gimple.h"
+#include "gimple.h"
#include "tree-flow.h"
/* Possible cases of implicit bad conversions. Used to select
static int require_constant_value;
static int require_constant_elements;
-static bool null_pointer_constant_p (tree);
+static bool null_pointer_constant_p (const_tree);
static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (tree, tree);
+static int tagged_types_tu_compatible_p (const_tree, const_tree);
static int comp_target_types (tree, tree);
-static int function_types_compatible_p (tree, tree);
-static int type_lists_compatible_p (tree, tree);
+static int function_types_compatible_p (const_tree, const_tree);
+static int type_lists_compatible_p (const_tree, const_tree);
static tree decl_constant_value_for_broken_optimization (tree);
static tree lookup_field (tree, tree);
-static tree convert_arguments (tree, tree, tree, tree);
+static int convert_arguments (int, tree *, tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
int);
static void push_member_name (tree);
static int spelling_length (void);
static char *print_spelling (char *);
-static void warning_init (const char *);
+static void warning_init (int, const char *);
static tree digest_init (tree, tree, bool, int);
static void output_init_element (tree, bool, tree, tree, int);
static void output_pending_init_elements (int);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
static void readonly_error (tree, enum lvalue_use);
-static int lvalue_or_else (tree, enum lvalue_use);
-static int lvalue_p (tree);
+static int lvalue_or_else (const_tree, enum lvalue_use);
+static int lvalue_p (const_tree);
static void record_maybe_used_decl (tree);
-static int comptypes_internal (tree, tree);
+static int comptypes_internal (const_tree, const_tree);
\f
/* Return true if EXP is a null pointer constant, false otherwise. */
static bool
-null_pointer_constant_p (tree expr)
+null_pointer_constant_p (const_tree expr)
{
/* This should really operate on c_expr structures, but they aren't
yet available everywhere required. */
tree type = TREE_TYPE (expr);
return (TREE_CODE (expr) == INTEGER_CST
- && !TREE_CONSTANT_OVERFLOW (expr)
+ && !TREE_OVERFLOW (expr)
&& integer_zerop (expr)
&& (INTEGRAL_TYPE_P (type)
|| (TREE_CODE (type) == POINTER_TYPE
struct tagged_tu_seen_cache {
const struct tagged_tu_seen_cache * next;
- tree t1;
- tree t2;
+ const_tree t1;
+ const_tree t2;
/* The return value of tagged_types_tu_compatible_p if we had seen
these two types already. */
int val;
and TYPE is the type that was invalid. */
void
-c_incomplete_type_error (tree value, tree type)
+c_incomplete_type_error (const_tree value, const_tree type)
{
const char *type_code_string;
{
/* Preserve unsignedness if not really getting any wider. */
if (TYPE_UNSIGNED (type)
- && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
- return unsigned_type_node;
+ && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+ return unsigned_type_node;
return integer_type_node;
}
/* Return true iff the given tree T is a variable length array. */
bool
-c_vla_type_p (tree t)
+c_vla_type_p (const_tree t)
{
if (TREE_CODE (t) == ARRAY_TYPE
&& C_TYPE_VARIABLE_SIZE (t))
/* We should not have any type quals on arrays at all. */
gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
-
+
d1_zero = d1 == 0 || !TYPE_MAX_VALUE (d1);
d2_zero = d2 == 0 || !TYPE_MAX_VALUE (d2);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)
&& (d1_variable || d1_zero || !d2_variable))
return build_type_attribute_variant (t2, attributes);
-
+
if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
return build_type_attribute_variant (t2, attributes);
-
+
/* Merge the element types, and have a size if either arg has
one. We may have qualifiers on the element types. To set
up TYPE_MAIN_VARIANT correctly, we need to form the
return build_type_attribute_variant (t1, attributes);
}
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ if (attributes != NULL)
+ {
+ /* Try harder not to create a new aggregate type. */
+ if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes))
+ return t1;
+ if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes))
+ return t2;
+ }
+ return build_type_attribute_variant (t1, attributes);
+
case FUNCTION_TYPE:
/* Function types: prefer the one that specified arg types.
If both do, merge the arg types. Also merge the return types. */
{
TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
TREE_VALUE (p2));
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
+ 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));
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
+ pedwarn (input_location, OPT_pedantic,
+ "function types not truly compatible in ISO C");
goto parm_done;
}
}
tree pointed_to_1, mv1;
tree pointed_to_2, mv2;
tree target;
+ unsigned target_quals;
/* Save time if the two types are the same. */
return t1;
gcc_assert (TREE_CODE (t1) == POINTER_TYPE
- && TREE_CODE (t2) == POINTER_TYPE);
+ && TREE_CODE (t2) == POINTER_TYPE);
/* Merge the attributes. */
attributes = targetm.merge_type_attributes (t1, t2);
if (TREE_CODE (mv2) != ARRAY_TYPE)
mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
target = composite_type (mv1, mv2);
- t1 = build_pointer_type (c_build_qualified_type
- (target,
- TYPE_QUALS (pointed_to_1) |
- TYPE_QUALS (pointed_to_2)));
+
+ /* 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. */
+ if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
+ target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2);
+ else
+ target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2);
+ t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
return build_type_attribute_variant (t1, attributes);
}
code2 = TREE_CODE (t2);
gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
- || code1 == REAL_TYPE || code1 == INTEGER_TYPE);
+ || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE
+ || code1 == INTEGER_TYPE);
gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
- || code2 == REAL_TYPE || code2 == INTEGER_TYPE);
+ || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE
+ || code2 == INTEGER_TYPE);
+
+ /* When one operand is a decimal float type, the other operand cannot be
+ a generic float type or a complex type. We also disallow vector types
+ here. */
+ if ((DECIMAL_FLOAT_TYPE_P (t1) || DECIMAL_FLOAT_TYPE_P (t2))
+ && !(DECIMAL_FLOAT_TYPE_P (t1) && DECIMAL_FLOAT_TYPE_P (t2)))
+ {
+ if (code1 == VECTOR_TYPE || code2 == VECTOR_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and vector types");
+ return error_mark_node;
+ }
+ if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and complex types");
+ return error_mark_node;
+ }
+ if (code1 == REAL_TYPE && code2 == REAL_TYPE)
+ {
+ error ("can%'t mix operands of decimal float and other float types");
+ return error_mark_node;
+ }
+ }
/* If one type is a vector type, return that type. (How the usual
arithmetic conversions apply to the vector types extension is not
return dfloat32_type_node;
}
+ /* Deal with fixed-point types. */
+ if (code1 == FIXED_POINT_TYPE || code2 == FIXED_POINT_TYPE)
+ {
+ unsigned int unsignedp = 0, satp = 0;
+ enum machine_mode m1, m2;
+ unsigned int fbit1, ibit1, fbit2, ibit2, max_fbit, max_ibit;
+
+ m1 = TYPE_MODE (t1);
+ m2 = TYPE_MODE (t2);
+
+ /* If one input type is saturating, the result type is saturating. */
+ if (TYPE_SATURATING (t1) || TYPE_SATURATING (t2))
+ satp = 1;
+
+ /* If both fixed-point types are unsigned, the result type is unsigned.
+ When mixing fixed-point and integer types, follow the sign of the
+ fixed-point type.
+ Otherwise, the result type is signed. */
+ if ((TYPE_UNSIGNED (t1) && TYPE_UNSIGNED (t2)
+ && code1 == FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE)
+ || (code1 == FIXED_POINT_TYPE && code2 != FIXED_POINT_TYPE
+ && TYPE_UNSIGNED (t1))
+ || (code1 != FIXED_POINT_TYPE && code2 == FIXED_POINT_TYPE
+ && TYPE_UNSIGNED (t2)))
+ unsignedp = 1;
+
+ /* The result type is signed. */
+ if (unsignedp == 0)
+ {
+ /* If the input type is unsigned, we need to convert to the
+ signed type. */
+ if (code1 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t1))
+ {
+ enum mode_class mclass = (enum mode_class) 0;
+ if (GET_MODE_CLASS (m1) == MODE_UFRACT)
+ mclass = MODE_FRACT;
+ else if (GET_MODE_CLASS (m1) == MODE_UACCUM)
+ mclass = MODE_ACCUM;
+ else
+ gcc_unreachable ();
+ m1 = mode_for_size (GET_MODE_PRECISION (m1), mclass, 0);
+ }
+ if (code2 == FIXED_POINT_TYPE && TYPE_UNSIGNED (t2))
+ {
+ enum mode_class mclass = (enum mode_class) 0;
+ if (GET_MODE_CLASS (m2) == MODE_UFRACT)
+ mclass = MODE_FRACT;
+ else if (GET_MODE_CLASS (m2) == MODE_UACCUM)
+ mclass = MODE_ACCUM;
+ else
+ gcc_unreachable ();
+ m2 = mode_for_size (GET_MODE_PRECISION (m2), mclass, 0);
+ }
+ }
+
+ if (code1 == FIXED_POINT_TYPE)
+ {
+ fbit1 = GET_MODE_FBIT (m1);
+ ibit1 = GET_MODE_IBIT (m1);
+ }
+ else
+ {
+ fbit1 = 0;
+ /* Signed integers need to subtract one sign bit. */
+ ibit1 = TYPE_PRECISION (t1) - (!TYPE_UNSIGNED (t1));
+ }
+
+ if (code2 == FIXED_POINT_TYPE)
+ {
+ fbit2 = GET_MODE_FBIT (m2);
+ ibit2 = GET_MODE_IBIT (m2);
+ }
+ else
+ {
+ fbit2 = 0;
+ /* Signed integers need to subtract one sign bit. */
+ ibit2 = TYPE_PRECISION (t2) - (!TYPE_UNSIGNED (t2));
+ }
+
+ max_ibit = ibit1 >= ibit2 ? ibit1 : ibit2;
+ max_fbit = fbit1 >= fbit2 ? fbit1 : fbit2;
+ return c_common_fixed_point_type_for_size (max_ibit, max_fbit, unsignedp,
+ satp);
+ }
+
/* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
return long_long_unsigned_type_node;
else
- return long_long_integer_type_node;
+ return long_long_integer_type_node;
}
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
val = comptypes_internal (type1, type2);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
+
return val;
-}\f
+}
+\f
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. This
differs from comptypes, in that we don't free the seen types. */
static int
-comptypes_internal (tree type1, tree type2)
+comptypes_internal (const_tree type1, const_tree type2)
{
- tree t1 = type1;
- tree t2 = type2;
+ const_tree t1 = type1;
+ const_tree t2 = type2;
int attrval, val;
/* Suppress errors caused by previously reported errors. */
|| !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
val = 0;
- break;
+ break;
}
case ENUMERAL_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
- {
+ {
+ tree a1 = TYPE_ATTRIBUTES (t1);
+ tree a2 = TYPE_ATTRIBUTES (t2);
+
+ if (! attribute_list_contained (a1, a2)
+ && ! attribute_list_contained (a2, a1))
+ break;
+
if (attrval != 2)
return tagged_types_tu_compatible_p (t1, t2);
val = tagged_types_tu_compatible_p (t1, t2);
mvr = TYPE_MAIN_VARIANT (mvr);
val = comptypes (mvl, mvr);
- if (val == 2 && pedantic)
- pedwarn ("types are not quite compatible");
+ if (val == 2)
+ pedwarn (input_location, OPT_pedantic, "types are not quite compatible");
return val;
}
\f
being parsed, so if two trees have context chains ending in null,
they're in the same translation unit. */
int
-same_translation_unit_p (tree t1, tree t2)
+same_translation_unit_p (const_tree t1, const_tree t2)
{
while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
switch (TREE_CODE_CLASS (TREE_CODE (t1)))
/* Allocate the seen two types, assuming that they are compatible. */
static struct tagged_tu_seen_cache *
-alloc_tagged_tu_seen_cache (tree t1, tree t2)
+alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2)
{
struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache);
tu->next = tagged_tu_seen_base;
tu->t1 = t1;
tu->t2 = t2;
-
+
tagged_tu_seen_base = tu;
-
+
/* The C standard says that two structures in different translation
units are compatible with each other only if the types of their
fields are compatible (among other things). We assume that they
const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base;
while (tu != tu_til)
{
- struct tagged_tu_seen_cache *tu1 = (struct tagged_tu_seen_cache*)tu;
+ const struct tagged_tu_seen_cache *const tu1
+ = (const struct tagged_tu_seen_cache *) tu;
tu = tu1->next;
- free (tu1);
+ free (CONST_CAST (struct tagged_tu_seen_cache *, tu1));
}
tagged_tu_seen_base = tu_til;
}
rules. */
static int
-tagged_types_tu_compatible_p (tree t1, tree t2)
+tagged_types_tu_compatible_p (const_tree t1, const_tree t2)
{
tree s1, s2;
bool needs_warning = false;
case ENUMERAL_TYPE:
{
struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
- /* Speed up the case where the type values are in the same order. */
- tree tv1 = TYPE_VALUES (t1);
- tree tv2 = TYPE_VALUES (t2);
+ /* Speed up the case where the type values are in the same order. */
+ tree tv1 = TYPE_VALUES (t1);
+ tree tv2 = TYPE_VALUES (t2);
- if (tv1 == tv2)
+ 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)
+ for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
+ {
+ if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
+ break;
+ if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
{
- tu->val = 0;
+ tu->val = 0;
return 0;
}
- }
+ }
- if (tv1 == NULL_TREE && tv2 == NULL_TREE)
+ if (tv1 == NULL_TREE && tv2 == NULL_TREE)
{
return 1;
}
- if (tv1 == NULL_TREE || tv2 == NULL_TREE)
+ if (tv1 == NULL_TREE || tv2 == NULL_TREE)
{
tu->val = 0;
return 0;
tu->val = 0;
return 0;
}
-
+
/* Speed up the common case where the fields are in the same order. */
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2;
s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
{
int result;
-
-
- if (DECL_NAME (s1) == NULL
- || DECL_NAME (s1) != DECL_NAME (s2))
+
+ if (DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
+
+ if (result != 1 && !DECL_NAME (s1))
+ break;
if (result == 0)
{
tu->val = 0;
{
bool ok = false;
- if (DECL_NAME (s1) != NULL)
- for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
- if (DECL_NAME (s1) == DECL_NAME (s2))
- {
- int result;
- result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
- if (result == 0)
- {
- tu->val = 0;
- return 0;
- }
- if (result == 2)
- needs_warning = true;
+ for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
+ if (DECL_NAME (s1) == DECL_NAME (s2))
+ {
+ int result;
- if (TREE_CODE (s1) == FIELD_DECL
- && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
- DECL_FIELD_BIT_OFFSET (s2)) != 1)
- break;
+ result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
+
+ if (result != 1 && !DECL_NAME (s1))
+ continue;
+ if (result == 0)
+ {
+ tu->val = 0;
+ return 0;
+ }
+ if (result == 2)
+ needs_warning = true;
- ok = true;
+ if (TREE_CODE (s1) == FIELD_DECL
+ && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+ DECL_FIELD_BIT_OFFSET (s2)) != 1)
break;
- }
+
+ ok = true;
+ break;
+ }
if (!ok)
{
tu->val = 0;
case RECORD_TYPE:
{
- struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
+ struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
s1 && s2;
Otherwise, the argument types must match. */
static int
-function_types_compatible_p (tree f1, tree f2)
+function_types_compatible_p (const_tree f1, const_tree f2)
{
tree args1, args2;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
/* 'volatile' qualifiers on a function's return type used to mean
the function is noreturn. */
if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2))
- pedwarn ("function return types not compatible due to %<volatile%>");
+ pedwarn (input_location, 0, "function return types not compatible due to %<volatile%>");
if (TYPE_VOLATILE (ret1))
ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1),
TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
or 2 for compatible with warning. */
static int
-type_lists_compatible_p (tree args1, tree args2)
+type_lists_compatible_p (const_tree args1, const_tree args2)
{
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
int val = 1;
/* Compute the size to increment a pointer by. */
static tree
-c_size_in_bytes (tree type)
+c_size_in_bytes (const_tree type)
{
enum tree_code code = TREE_CODE (type);
bool lvalue_array_p;
while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR
- || TREE_CODE (exp.value) == NOP_EXPR
- || TREE_CODE (exp.value) == CONVERT_EXPR)
+ || CONVERT_EXPR_P (exp.value))
&& TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type)
{
if (TREE_CODE (exp.value) == NON_LVALUE_EXPR)
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
- if (INTEGRAL_TYPE_P (type))
- return perform_integral_promotions (exp);
-
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
+
+ exp = require_complete_type (exp);
+ if (exp == error_mark_node)
+ return error_mark_node;
+
+ if (INTEGRAL_TYPE_P (type))
+ return perform_integral_promotions (exp);
+
return exp;
}
\f
do
{
tree subdatum = TREE_VALUE (field);
+ int quals;
+ tree subtype;
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
- ref = build3 (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+ quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
+ quals |= TYPE_QUALS (TREE_TYPE (datum));
+ subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
+
+ ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
NULL_TREE);
if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
TREE_READONLY (ref) = 1;
\f
/* Given an expression PTR for a pointer, return an expression
for the value pointed to.
- ERRORSTRING is the name of the operator to appear in error messages. */
+ ERRORSTRING is the name of the operator to appear in error messages.
+
+ LOC is the location to use for the generated tree. */
tree
-build_indirect_ref (tree ptr, const char *errorstring)
+build_indirect_ref (tree ptr, const char *errorstring, location_t loc)
{
tree pointer = default_conversion (ptr);
tree type = TREE_TYPE (pointer);
+ tree ref;
if (TREE_CODE (type) == POINTER_TYPE)
{
+ if (CONVERT_EXPR_P (pointer)
+ || TREE_CODE (pointer) == VIEW_CONVERT_EXPR)
+ {
+ /* If a warning is issued, mark it to avoid duplicates from
+ the backend. This only needs to be done at
+ warn_strict_aliasing > 2. */
+ if (warn_strict_aliasing > 2)
+ if (strict_aliasing_warning (TREE_TYPE (TREE_OPERAND (pointer, 0)),
+ type, TREE_OPERAND (pointer, 0)))
+ TREE_NO_WARNING (pointer) = 1;
+ }
+
if (TREE_CODE (pointer) == ADDR_EXPR
&& (TREE_TYPE (TREE_OPERAND (pointer, 0))
== TREE_TYPE (type)))
- return TREE_OPERAND (pointer, 0);
+ {
+ ref = TREE_OPERAND (pointer, 0);
+ protected_set_expr_location (ref, loc);
+ return ref;
+ }
else
{
tree t = TREE_TYPE (type);
- tree ref;
ref = build1 (INDIRECT_REF, t, pointer);
TREE_SIDE_EFFECTS (ref)
= TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+ protected_set_expr_location (ref, loc);
return ref;
}
}
else if (TREE_CODE (pointer) != ERROR_MARK)
- error ("invalid type argument of %qs", errorstring);
+ error ("invalid type argument of %qs (have %qT)", errorstring, type);
return error_mark_node;
}
If A is a variable or a member, we generate a primitive ARRAY_REF.
This avoids forcing the array out of registers, and can work on
arrays that are not lvalues (for example, members of structures returned
- by functions). */
+ by functions).
+
+ LOC is the location to use for the returned expression. */
tree
-build_array_ref (tree array, tree index)
+build_array_ref (tree array, tree index, location_t loc)
{
+ tree ret;
bool swapped = false;
if (TREE_TYPE (array) == error_mark_node
|| TREE_TYPE (index) == error_mark_node)
if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
{
- error ("subscripted value is neither array nor pointer");
+ error_at (loc, "subscripted value is neither array nor pointer");
return error_mark_node;
}
temp = array;
if (!INTEGRAL_TYPE_P (TREE_TYPE (index)))
{
- error ("array subscript is not an integer");
+ error_at (loc, "array subscript is not an integer");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE)
{
- error ("subscripted value is pointer to function");
+ error_at (loc, "subscripted value is pointer to function");
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 ("ISO C forbids subscripting %<register%> array");
+ pedwarn (loc, OPT_pedantic,
+ "ISO C forbids subscripting %<register%> array");
else if (!flag_isoc99 && !lvalue_p (foo))
- pedwarn ("ISO C90 forbids subscripting non-lvalue array");
+ pedwarn (loc, OPT_pedantic,
+ "ISO C90 forbids subscripting non-lvalue array");
}
type = TREE_TYPE (TREE_TYPE (array));
- if (TREE_CODE (type) != ARRAY_TYPE)
- type = TYPE_MAIN_VARIANT (type);
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
- or if the array is. */
+ or if the array is. */
TREE_READONLY (rval)
|= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array)))
| TREE_READONLY (array));
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
- return require_complete_type (fold (rval));
+ ret = require_complete_type (fold (rval));
+ protected_set_expr_location (ret, loc);
+ return ret;
}
else
{
gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
- "array indexing");
+ "array indexing", loc);
}
}
\f
if (TREE_DEPRECATED (ref))
warn_deprecated_use (ref);
- if (!skip_evaluation)
- assemble_external (ref);
- TREE_USED (ref) = 1;
+ /* Recursive call does not count as usage. */
+ if (ref != current_function_decl)
+ {
+ TREE_USED (ref) = 1;
+ }
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
if (TREE_CODE (ref) == CONST_DECL)
{
+ used_types_insert (TREE_TYPE (ref));
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)
if (context != 0 && context != current_function_decl)
DECL_NONLOCAL (ref) = 1;
}
+ /* C99 6.7.4p3: An inline definition of a function with external
+ linkage ... shall not contain a reference to an identifier with
+ internal linkage. */
+ else if (current_function_decl != 0
+ && DECL_DECLARED_INLINE_P (current_function_decl)
+ && DECL_EXTERNAL (current_function_decl)
+ && VAR_OR_FUNCTION_DECL_P (ref)
+ && (TREE_CODE (ref) != VAR_DECL || TREE_STATIC (ref))
+ && ! TREE_PUBLIC (ref)
+ && DECL_CONTEXT (ref) != current_function_decl)
+ pedwarn (loc, 0, "%qD is static but used in inline function %qD "
+ "which is not static", ref, current_function_decl);
return ref;
}
type = groktypename (t);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
- pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+ pop_maybe_used (type != error_mark_node
+ ? C_TYPE_VARIABLE_SIZE (type) : false);
return ret;
}
build_function_call (tree function, tree params)
{
tree fntype, fundecl = 0;
- tree coerced_params;
tree name = NULL_TREE, result;
tree tem;
+ int nargs;
+ tree *argarray;
+
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (function);
expression if necessary. This has the nice side-effect to prevent
the tree-inliner from generating invalid assignment trees which may
blow up in the RTL expander later. */
- if ((TREE_CODE (function) == NOP_EXPR
- || TREE_CODE (function) == CONVERT_EXPR)
+ if (CONVERT_EXPR_P (function)
&& TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
&& !comptypes (fntype, TREE_TYPE (tem)))
/* 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 (0, "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 (warning (0, "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 (input_location, "if this code is reached, the program will abort");
if (VOID_TYPE_P (return_type))
return trap;
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
- coerced_params
- = convert_arguments (TYPE_ARG_TYPES (fntype), params, function, fundecl);
+ nargs = list_length (params);
+ argarray = (tree *) alloca (nargs * sizeof (tree));
+ nargs = convert_arguments (nargs, argarray, TYPE_ARG_TYPES (fntype),
+ params, function, fundecl);
+ if (nargs < 0)
+ return error_mark_node;
- if (coerced_params == error_mark_node)
+ /* Check that arguments to builtin functions match the expectations. */
+ if (fundecl
+ && DECL_BUILT_IN (fundecl)
+ && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL
+ && !check_builtin_function_arguments (fundecl, nargs, argarray))
return error_mark_node;
/* Check that the arguments to the function are valid. */
-
- check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
+ check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
TYPE_ARG_TYPES (fntype));
if (require_constant_value)
{
- result = fold_build3_initializer (CALL_EXPR, TREE_TYPE (fntype),
- function, coerced_params, NULL_TREE);
-
+ result = fold_build_call_array_initializer (TREE_TYPE (fntype),
+ function, nargs, argarray);
if (TREE_CONSTANT (result)
&& (name == NULL_TREE
|| strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
- pedwarn_init ("initializer element is not constant");
+ pedwarn_init (input_location, 0, "initializer element is not constant");
}
else
- result = fold_build3 (CALL_EXPR, TREE_TYPE (fntype),
- function, coerced_params, NULL_TREE);
+ result = fold_build_call_array (TREE_TYPE (fntype),
+ function, nargs, argarray);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
}
\f
/* Convert the argument expressions in the list VALUES
- to the types in the list TYPELIST. The result is a list of converted
- argument expressions, unless there are too few arguments in which
- case it is error_mark_node.
+ to the types in the list TYPELIST. The resulting arguments are
+ stored in the array ARGARRAY which has size NARGS.
If TYPELIST is exhausted, or when an element has NULL as its type,
perform the default conversions.
This is also where warnings about wrong number of args are generated.
- Both VALUES and the returned value are chains of TREE_LIST nodes
- with the elements of the list in the TREE_VALUE slots of those nodes. */
+ VALUES is a chain of TREE_LIST nodes with the elements of the list
+ in the TREE_VALUE slots of those nodes.
-static tree
-convert_arguments (tree typelist, tree values, tree function, tree fundecl)
+ Returns the actual number of arguments processed (which may be less
+ than NARGS in some error situations), or -1 on failure. */
+
+static int
+convert_arguments (int nargs, tree *argarray,
+ tree typelist, tree values, tree function, tree fundecl)
{
tree typetail, valtail;
- tree result = NULL;
int parmnum;
+ const bool type_generic = fundecl
+ && lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl)));
tree selector;
/* Change pointer to function to the function itself for
selector = objc_message_selector ();
/* Scan the given expressions and types, producing individual
- converted arguments and pushing them on RESULT in reverse order. */
+ converted arguments and storing them in ARGARRAY. */
for (valtail = values, typetail = typelist, parmnum = 0;
valtail;
if (type == void_type_node)
{
error ("too many arguments to function %qE", function);
- break;
+ return parmnum;
}
if (selector && argnum > 2)
{
/* Optionally warn about conversions that
differ from the default conversions. */
- if (warn_conversion || warn_traditional)
+ if (warn_traditional_conversion || warn_traditional)
{
unsigned int formal_prec = TYPE_PRECISION (type);
else if (type != TREE_TYPE (val)
&& (type == dfloat32_type_node
|| type == dfloat64_type_node
- || type == dfloat128_type_node
+ || type == dfloat128_type_node
|| TREE_TYPE (val) == dfloat32_type_node
|| TREE_TYPE (val) == dfloat64_type_node
|| TREE_TYPE (val) == dfloat128_type_node)
- && (formal_prec
+ && (formal_prec
<= TYPE_PRECISION (TREE_TYPE (val))
|| (type == dfloat128_type_node
&& (TREE_TYPE (val)
- != dfloat64_type_node
- && (TREE_TYPE (val)
+ != dfloat64_type_node
+ && (TREE_TYPE (val)
!= dfloat32_type_node)))
|| (type == dfloat64_type_node
&& (TREE_TYPE (val)
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
- -Wconversion, not with -Wtraditional. */
- else if (warn_conversion && INTEGRAL_TYPE_P (type)
+ -Wtraditional-conversion, not with -Wtraditional. */
+ else if (warn_traditional_conversion && INTEGRAL_TYPE_P (type)
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
{
tree would_have_been = default_conversion (val);
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warning (OPT_Wconversion, "passing argument %d of %qE "
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
"with different width due to prototype",
argnum, rname);
else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
&& TYPE_UNSIGNED (TREE_TYPE (val)))
;
else if (TYPE_UNSIGNED (type))
- warning (OPT_Wconversion, "passing argument %d of %qE "
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
"as unsigned due to prototype",
argnum, rname);
else
- warning (OPT_Wconversion, "passing argument %d of %qE "
+ warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
"as signed due to prototype", argnum, rname);
}
}
&& (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
}
- result = tree_cons (NULL_TREE, parmval, result);
+ argarray[parmnum] = parmval;
}
else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (val))
- < TYPE_PRECISION (double_type_node))
+ && (TYPE_PRECISION (TREE_TYPE (val))
+ < TYPE_PRECISION (double_type_node))
&& !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
- /* Convert `float' to `double'. */
- result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
- else if ((invalid_func_diag =
- targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+ {
+ if (type_generic)
+ argarray[parmnum] = val;
+ else
+ /* Convert `float' to `double'. */
+ argarray[parmnum] = convert (double_type_node, val);
+ }
+ else if ((invalid_func_diag =
+ targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
{
error (invalid_func_diag);
- return error_mark_node;
+ return -1;
}
else
/* Convert `short' and `char' to full-size `int'. */
- result = tree_cons (NULL_TREE, default_conversion (val), result);
+ argarray[parmnum] = default_conversion (val);
if (typetail)
typetail = TREE_CHAIN (typetail);
}
+ gcc_assert (parmnum == nargs);
+
if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
error ("too few arguments to function %qE", function);
- return error_mark_node;
+ return -1;
}
- return nreverse (result);
+ return parmnum;
}
\f
/* This is the entry point used by the parser to build unary operators
in the input. CODE, a tree_code, specifies the unary operator, and
ARG is the operand. For unary plus, the C parser currently uses
- CONVERT_EXPR for code. */
+ CONVERT_EXPR for code.
+
+ LOC is the location to use for the tree generated.
+*/
struct c_expr
-parser_build_unary_op (enum tree_code code, struct c_expr arg)
+parser_build_unary_op (enum tree_code code, struct c_expr arg, location_t loc)
{
struct c_expr result;
result.original_code = ERROR_MARK;
result.value = build_unary_op (code, arg.value, 0);
- overflow_warning (result.value);
+ protected_set_expr_location (result.value, loc);
+
+ if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
+ overflow_warning (result.value);
+
return result;
}
/* Check for cases such as x+y<<z which users are likely
to misinterpret. */
if (warn_parentheses)
- {
- if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
- {
- if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
- || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (OPT_Wparentheses,
- "suggest parentheses around + or - inside shift");
- }
+ warn_about_parentheses (code, code1, code2);
- if (code == TRUTH_ORIF_EXPR)
- {
- if (code1 == TRUTH_ANDIF_EXPR
- || code2 == TRUTH_ANDIF_EXPR)
- warning (OPT_Wparentheses,
- "suggest parentheses around && within ||");
- }
-
- if (code == BIT_IOR_EXPR)
- {
- if (code1 == BIT_AND_EXPR || code1 == BIT_XOR_EXPR
- || code1 == PLUS_EXPR || code1 == MINUS_EXPR
- || code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
- || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of |");
- /* Check cases like x|y==z */
- if (TREE_CODE_CLASS (code1) == tcc_comparison
- || TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of |");
- }
-
- if (code == BIT_XOR_EXPR)
- {
- if (code1 == BIT_AND_EXPR
- || code1 == PLUS_EXPR || code1 == MINUS_EXPR
- || code2 == BIT_AND_EXPR
- || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of ^");
- /* Check cases like x^y==z */
- if (TREE_CODE_CLASS (code1) == tcc_comparison
- || TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of ^");
- }
-
- if (code == BIT_AND_EXPR)
- {
- if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
- || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning (OPT_Wparentheses,
- "suggest parentheses around + or - in operand of &");
- /* Check cases like x&y==z */
- if (TREE_CODE_CLASS (code1) == tcc_comparison
- || TREE_CODE_CLASS (code2) == tcc_comparison)
- warning (OPT_Wparentheses,
- "suggest parentheses around comparison in operand of &");
- }
- /* Similarly, check for cases like 1<=i<=10 that are probably errors. */
- if (TREE_CODE_CLASS (code) == tcc_comparison
- && (TREE_CODE_CLASS (code1) == tcc_comparison
- || TREE_CODE_CLASS (code2) == tcc_comparison))
- warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
- "have their mathematical meaning");
-
- }
+ if (TREE_CODE_CLASS (code1) != tcc_comparison)
+ warn_logical_operator (code, arg1.value, arg2.value);
/* Warn about comparisons against string literals, with the exception
of testing for equality or inequality of a string literal with NULL. */
{
if ((code1 == STRING_CST && !integer_zerop (arg2.value))
|| (code2 == STRING_CST && !integer_zerop (arg1.value)))
- warning (OPT_Wstring_literal_comparison,
- "comparison with string literal");
+ warning (OPT_Waddress, "comparison with string literal results in unspecified behavior");
}
else if (TREE_CODE_CLASS (code) == tcc_comparison
&& (code1 == STRING_CST || code2 == STRING_CST))
- warning (OPT_Wstring_literal_comparison,
- "comparison with string literal");
+ warning (OPT_Waddress, "comparison with string literal results in unspecified behavior");
- overflow_warning (result.value);
+ if (TREE_OVERFLOW_P (result.value)
+ && !TREE_OVERFLOW_P (arg1.value)
+ && !TREE_OVERFLOW_P (arg2.value))
+ overflow_warning (result.value);
return result;
}
tree con0, con1, lit0, lit1;
tree orig_op1 = op1;
- if (pedantic || warn_pointer_arith)
- {
- if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn ("pointer of type %<void *%> used in subtraction");
- if (TREE_CODE (target_type) == FUNCTION_TYPE)
- pedwarn ("pointer to a function used in subtraction");
- }
+ if (TREE_CODE (target_type) == VOID_TYPE)
+ pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer of type %<void *%> used in subtraction");
+ if (TREE_CODE (target_type) == FUNCTION_TYPE)
+ pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "pointer to a function used in subtraction");
/* If the conversion to ptrdiff_type does anything like widening or
converting a partial to an integral mode, we get a convert_expression
different mode in place.)
So first try to find a common term here 'by hand'; we want to cover
at least the cases that occur in legal static initializers. */
- if ((TREE_CODE (op0) == NOP_EXPR || TREE_CODE (op0) == CONVERT_EXPR)
+ if (CONVERT_EXPR_P (op0)
&& (TYPE_PRECISION (TREE_TYPE (op0))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))))
con0 = TREE_OPERAND (op0, 0);
else
con0 = op0;
- if ((TREE_CODE (op1) == NOP_EXPR || TREE_CODE (op1) == CONVERT_EXPR)
+ if (CONVERT_EXPR_P (op1)
&& (TYPE_PRECISION (TREE_TYPE (op1))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))))
con1 = TREE_OPERAND (op1, 0);
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg;
tree argtype = 0;
- enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
+ enum tree_code typecode;
tree val;
int noconvert = flag;
const char *invalid_op_diag;
+ if (code != ADDR_EXPR)
+ arg = require_complete_type (arg);
+
+ typecode = TREE_CODE (TREE_TYPE (arg));
if (typecode == ERROR_MARK)
return error_mark_node;
if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
is enough to prevent anybody from looking inside for
associativity, but won't generate any code. */
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
- || typecode == COMPLEX_TYPE
+ || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE))
{
error ("wrong type argument to unary plus");
case NEGATE_EXPR:
if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
- || typecode == COMPLEX_TYPE
+ || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
|| typecode == VECTOR_TYPE))
{
error ("wrong type argument to unary minus");
break;
case BIT_NOT_EXPR:
- if (typecode == INTEGER_TYPE || typecode == VECTOR_TYPE)
+ /* ~ works on integer types and non float vectors. */
+ if (typecode == INTEGER_TYPE
+ || (typecode == VECTOR_TYPE
+ && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg))))
{
if (!noconvert)
arg = default_conversion (arg);
else if (typecode == COMPLEX_TYPE)
{
code = CONJ_EXPR;
- if (pedantic)
- pedwarn ("ISO C does not support %<~%> for complex conjugation");
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C does not support %<~%> for complex conjugation");
if (!noconvert)
arg = default_conversion (arg);
}
break;
case TRUTH_NOT_EXPR:
- if (typecode != INTEGER_TYPE
+ if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
&& typecode != REAL_TYPE && typecode != POINTER_TYPE
&& typecode != COMPLEX_TYPE)
{
{
tree real, imag;
- if (pedantic)
- pedwarn ("ISO C does not support %<++%> and %<--%>"
- " on complex types");
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C does not support %<++%> and %<--%> on complex types");
arg = stabilize_reference (arg);
real = build_unary_op (REALPART_EXPR, arg, 1);
imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+ real = build_unary_op (code, real, 1);
+ if (real == error_mark_node || imag == error_mark_node)
+ return error_mark_node;
return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
- build_unary_op (code, real, 1), imag);
+ real, imag);
}
/* Report invalid types. */
- if (typecode != POINTER_TYPE
+ if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
&& typecode != INTEGER_TYPE && typecode != REAL_TYPE)
{
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- error ("wrong type argument to increment");
- else
- error ("wrong type argument to decrement");
+ error ("wrong type argument to increment");
+ else
+ error ("wrong type argument to decrement");
return error_mark_node;
}
else
error ("decrement of pointer to unknown structure");
}
- else if ((pedantic || warn_pointer_arith)
- && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
- {
+ else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
+ {
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- pedwarn ("wrong type argument to increment");
+ pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "wrong type argument to increment");
else
- pedwarn ("wrong type argument to decrement");
+ pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+ "wrong type argument to decrement");
}
inc = c_size_in_bytes (TREE_TYPE (result_type));
+ inc = fold_convert (sizetype, inc);
+ }
+ else if (FRACT_MODE_P (TYPE_MODE (result_type)))
+ {
+ /* For signed fract types, we invert ++ to -- or
+ -- to ++, and change inc from 1 to -1, because
+ it is not possible to represent 1 in signed fract constants.
+ For unsigned fract types, the result always overflows and
+ we get an undefined (original) or the maximum value. */
+ if (code == PREINCREMENT_EXPR)
+ code = PREDECREMENT_EXPR;
+ else if (code == PREDECREMENT_EXPR)
+ code = PREINCREMENT_EXPR;
+ else if (code == POSTINCREMENT_EXPR)
+ code = POSTDECREMENT_EXPR;
+ else /* code == POSTDECREMENT_EXPR */
+ code = POSTINCREMENT_EXPR;
+
+ inc = integer_minus_one_node;
+ inc = convert (argtype, inc);
}
else
- inc = integer_one_node;
-
- inc = convert (argtype, inc);
+ {
+ inc = integer_one_node;
+ inc = convert (argtype, inc);
+ }
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
argtype = TREE_TYPE (arg);
/* If the lvalue is const or volatile, merge that into the type
- to which the address will point. Note that you can't get a
+ to which the address will point. Note that you can't get a
restricted pointer by taking the address of something, so we
only have to deal with `const' and `volatile' here. */
if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
if (val && TREE_CODE (val) == INDIRECT_REF
&& TREE_CONSTANT (TREE_OPERAND (val, 0)))
{
- tree op0 = fold_convert (argtype, fold_offsetof (arg)), op1;
+ tree op0 = fold_convert (sizetype, fold_offsetof (arg, val)), op1;
op1 = fold_convert (argtype, TREE_OPERAND (val, 0));
- return fold_build2 (PLUS_EXPR, argtype, op0, op1);
+ return fold_build2 (POINTER_PLUS_EXPR, argtype, op1, op0);
}
val = build1 (ADDR_EXPR, argtype, arg);
if (argtype == 0)
argtype = TREE_TYPE (arg);
return require_constant_value ? fold_build1_initializer (code, argtype, arg)
- : fold_build1 (code, argtype, arg);
+ : fold_build1 (code, argtype, arg);
}
/* Return nonzero if REF is an lvalue valid for this language.
Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
static int
-lvalue_p (tree ref)
+lvalue_p (const_tree ref)
{
- enum tree_code code = TREE_CODE (ref);
+ const enum tree_code code = TREE_CODE (ref);
switch (code)
{
ensures that all the format strings are checked at compile
time. */
#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A) \
- : (use == lv_increment ? (I) \
+ : (use == lv_increment ? (I) \
: (use == lv_decrement ? (D) : (AS))))
if (TREE_CODE (arg) == COMPONENT_REF)
{
G_("read-only variable %qD used as %<asm%> output")),
arg);
else
- error (READONLY_MSG (G_("assignment of read-only location"),
- G_("increment of read-only location"),
- G_("decrement of read-only location"),
- G_("read-only location used as %<asm%> output")));
+ error (READONLY_MSG (G_("assignment of read-only location %qE"),
+ G_("increment of read-only location %qE"),
+ G_("decrement of read-only location %qE"),
+ G_("read-only location %qE used as %<asm%> output")),
+ arg);
}
how the lvalue is being used and so selects the error message. */
static int
-lvalue_or_else (tree ref, enum lvalue_use use)
+lvalue_or_else (const_tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
("global register variable %qD used in nested function", x);
return false;
}
- pedwarn ("register variable %qD used in nested function", x);
+ pedwarn (input_location, 0, "register variable %qD used in nested function", x);
}
else if (C_DECL_REGISTER (x))
{
result_type = TYPE_MAIN_VARIANT (type1);
}
else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE)
- && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
- || code2 == COMPLEX_TYPE))
+ || code1 == COMPLEX_TYPE)
+ && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
+ || code2 == COMPLEX_TYPE))
{
result_type = c_common_type (type1, type2);
if (unsigned_op1 ^ unsigned_op2)
{
+ bool ovf;
+
/* 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. */
/* 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 && tree_expr_nonnegative_p (op1))
- || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
+ else if ((unsigned_op2
+ && tree_expr_nonnegative_warnv_p (op1, &ovf))
+ || (unsigned_op1
+ && tree_expr_nonnegative_warnv_p (op2, &ovf)))
/* OK */;
else
- warning (0, "signed and unsigned type in conditional expression");
+ warning (OPT_Wsign_compare, "signed and unsigned type in conditional expression");
}
}
}
else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
{
- if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
- pedwarn ("ISO C forbids conditional expr with only one void side");
+ if (code1 != VOID_TYPE || code2 != VOID_TYPE)
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids conditional expr with only one void side");
result_type = void_type_node;
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
result_type = qualify_type (type1, type2);
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
- if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between "
+ if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids conditional expr between "
"%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
TREE_TYPE (type2)));
}
else if (VOID_TYPE_P (TREE_TYPE (type2)))
{
- if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids conditional expr between "
+ if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids conditional expr between "
"%<void *%> and function pointer");
result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
TREE_TYPE (type1)));
}
else
{
- pedwarn ("pointer type mismatch in conditional expression");
+ pedwarn (input_location, 0,
+ "pointer type mismatch in conditional expression");
result_type = build_pointer_type (void_type_node);
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
if (!null_pointer_constant_p (orig_op2))
- pedwarn ("pointer/integer type mismatch in conditional expression");
+ pedwarn (input_location, 0,
+ "pointer/integer type mismatch in conditional expression");
else
{
op2 = null_pointer_node;
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
if (!null_pointer_constant_p (orig_op1))
- pedwarn ("pointer/integer type mismatch in conditional expression");
+ pedwarn (input_location, 0,
+ "pointer/integer type mismatch in conditional expression");
else
{
op1 = null_pointer_node;
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
- statement: with -Wextra or -Wunused, we should warn if it doesn't have
+ statement: with -Wunused, we should warn if it doesn't have
any side-effects, unless it was explicitly cast to (void). */
if (warn_unused_value)
{
if (VOID_TYPE_P (TREE_TYPE (expr1))
- && (TREE_CODE (expr1) == NOP_EXPR
- || TREE_CODE (expr1) == CONVERT_EXPR))
+ && CONVERT_EXPR_P (expr1))
; /* (void) a, b */
else if (VOID_TYPE_P (TREE_TYPE (expr1))
&& TREE_CODE (expr1) == COMPOUND_EXPR
- && (TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR
- || TREE_CODE (TREE_OPERAND (expr1, 1)) == NOP_EXPR))
+ && CONVERT_EXPR_P (TREE_OPERAND (expr1, 1)))
; /* (void) a, (void) b, c */
else
- warning (0, "left-hand operand of comma expression has no effect");
+ warning (OPT_Wunused_value,
+ "left-hand operand of comma expression has no effect");
}
}
else if (warn_unused_value)
warn_if_unused_value (expr1, input_location);
+ if (expr2 == error_mark_node)
+ return error_mark_node;
+
return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
}
return error_mark_node;
}
+ if (!VOID_TYPE_P (type))
+ {
+ value = require_complete_type (value);
+ if (value == error_mark_node)
+ return error_mark_node;
+ }
+
if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
{
- if (pedantic)
- {
- if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE)
- pedwarn ("ISO C forbids casting nonscalar to the same type");
- }
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids casting nonscalar to the same type");
}
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
- TYPE_MAIN_VARIANT (TREE_TYPE (value))))
+ if (TREE_TYPE (field) != error_mark_node
+ && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (value))))
break;
if (field)
{
tree t;
- if (pedantic)
- pedwarn ("ISO C forbids casts to union type");
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C forbids casts to union type");
t = digest_init (type,
build_constructor_single (type, field, value),
true, 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");
&& TREE_CODE (in_otype) == POINTER_TYPE);
if (added)
- warning (0, "cast adds new qualifiers to function type");
+ warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
if (discarded)
/* There are qualifiers present in IN_OTYPE that are not
present in IN_TYPE. */
- warning (0, "cast discards qualifiers from pointer target type");
+ warning (OPT_Wcast_qual, "cast discards qualifiers from pointer target type");
}
/* Warn about possible alignment problems. */
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
- /* Unlike conversion of integers to pointers, where the
- warning is disabled for converting constants because
- of cases such as SIG_*, warn about converting constant
- pointers to integers. In some cases it may cause unwanted
+ /* Unlike conversion of integers to pointers, where the
+ warning is disabled for converting constants because
+ of cases such as SIG_*, warn about converting constant
+ pointers to integers. In some cases it may cause unwanted
sign extension, and a warning is appropriate. */
warning (OPT_Wpointer_to_int_cast,
"cast from pointer to integer of different size");
warning (OPT_Wint_to_pointer_cast, "cast to pointer from integer "
"of different size");
- strict_aliasing_warning (otype, type, expr);
+ if (warn_strict_aliasing <= 2)
+ strict_aliasing_warning (otype, type, expr);
/* If pedantic, warn for conversions between function and object
pointer types, except for converting a null pointer constant
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
- pedwarn ("ISO C forbids conversion of function pointer to object pointer type");
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids "
+ "conversion of function pointer to object pointer type");
if (pedantic
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
&& !null_pointer_constant_p (value))
- pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids "
+ "conversion of object pointer to function pointer type");
ovalue = value;
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
{
- if (CONSTANT_CLASS_P (ovalue)
- && (TREE_OVERFLOW (ovalue) || TREE_CONSTANT_OVERFLOW (ovalue)))
+ if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue))
{
- /* Avoid clobbering a shared constant. */
- value = copy_node (value);
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ if (!TREE_OVERFLOW (value))
+ {
+ /* Avoid clobbering a shared constant. */
+ value = copy_node (value);
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ }
}
- else if (TREE_OVERFLOW (value) || TREE_CONSTANT_OVERFLOW (value))
+ else if (TREE_OVERFLOW (value))
/* Reset VALUE's overflow flags, ensuring constant sharing. */
value = build_int_cst_wide (TREE_TYPE (value),
TREE_INT_CST_LOW (value),
return build_c_cast (type, expr);
}
-
\f
/* Build an assignment expression of lvalue LHS from value RHS.
MODIFYCODE is the code for a binary operator that we use
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
+ if (!lvalue_or_else (lhs, lv_assign))
+ return error_mark_node;
+
STRIP_TYPE_NOPS (rhs);
newrhs = rhs;
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- if (!lvalue_or_else (lhs, lv_assign))
- return error_mark_node;
-
/* Give an error for storing in something that is 'const'. */
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
/* This macro is used to emit diagnostics to ensure that all format
strings are complete sentences, visible to gettext and checked at
compile time. */
-#define WARN_FOR_ASSIGNMENT(AR, AS, IN, RE) \
- do { \
- switch (errtype) \
- { \
- case ic_argpass: \
- pedwarn (AR, parmnum, rname); \
- break; \
- case ic_argpass_nonproto: \
- warning (0, AR, parmnum, rname); \
- break; \
- case ic_assign: \
- pedwarn (AS); \
- break; \
- case ic_init: \
- pedwarn (IN); \
- break; \
- case ic_return: \
- pedwarn (RE); \
- break; \
- default: \
- gcc_unreachable (); \
- } \
+#define WARN_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ if (pedwarn (LOCATION, OPT, AR, parmnum, rname)) \
+ inform (fundecl ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_argpass_nonproto: \
+ warning (OPT, AR, parmnum, rname); \
+ break; \
+ case ic_assign: \
+ pedwarn (LOCATION, OPT, AS); \
+ break; \
+ case ic_init: \
+ pedwarn (LOCATION, OPT, IN); \
+ break; \
+ case ic_return: \
+ pedwarn (LOCATION, OPT, RE); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
} while (0)
STRIP_TYPE_NOPS (rhs);
}
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
- {
- overflow_warning (rhs);
- return rhs;
- }
+ return rhs;
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
+ rhs = require_complete_type (rhs);
+ if (rhs == error_mark_node)
+ return error_mark_node;
/* A type converts to a reference to it.
This code doesn't fully support references, it's just for the
special case of va_start and va_copy. */
}
/* Some types can interconvert without explicit casts. */
else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
- && vector_types_convertible_p (type, TREE_TYPE (rhs)))
+ && vector_types_convertible_p (type, TREE_TYPE (rhs), true))
return convert (type, rhs);
/* Arithmetic types all interconvert, and enum is treated like int. */
else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
+ || codel == FIXED_POINT_TYPE
|| codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
|| codel == BOOLEAN_TYPE)
&& (coder == INTEGER_TYPE || coder == REAL_TYPE
+ || coder == FIXED_POINT_TYPE
|| coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
|| coder == BOOLEAN_TYPE))
return convert_and_check (type, rhs);
+ /* Aggregates in different TUs might need conversion. */
+ if ((codel == RECORD_TYPE || codel == UNION_TYPE)
+ && codel == coder
+ && comptypes (type, rhstype))
+ return convert_and_check (type, rhs);
+
/* Conversion to a transparent union from its member types.
This applies only to function arguments. */
- else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
- && (errtype == ic_argpass || errtype == ic_argpass_nonproto))
+ if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
+ && (errtype == ic_argpass || errtype == ic_argpass_nonproto))
{
tree memb, marginal_memb = NULL_TREE;
function where an ordinary one is wanted, but not
vice-versa. */
if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
- WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE "
"makes qualified function "
"pointer from unqualified"),
G_("assignment makes qualified "
"pointer from unqualified"));
}
else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
G_("assignment discards qualifiers "
"from pointer target type"),
memb = marginal_memb;
}
- if (pedantic && (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)))
- pedwarn ("ISO C prohibits argument conversion to union type");
+ if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C prohibits argument conversion to union type");
+ rhs = fold_convert (TREE_TYPE (memb), rhs);
return build_constructor_single (type, memb, rhs);
}
}
if (TREE_CODE (mvr) != ARRAY_TYPE)
mvr = TYPE_MAIN_VARIANT (mvr);
/* Opaque pointers are treated like void pointers. */
- is_opaque_pointer = (targetm.vector_opaque_p (type)
- || targetm.vector_opaque_p (rhstype))
- && TREE_CODE (ttl) == VECTOR_TYPE
- && TREE_CODE (ttr) == VECTOR_TYPE;
-
+ is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
+
/* C++ does not allow the implicit conversion void* -> T*. However,
- for the purpose of reducing the number of false positives, we
- tolerate the special case of
+ for the purpose of reducing the number of false positives, we
+ tolerate the special case of
- int *p = NULL;
+ int *p = NULL;
- where NULL is typically defined in C to be '(void *) 0'. */
+ where NULL is typically defined in C to be '(void *) 0'. */
if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl))
- warning (OPT_Wc___compat, "request for implicit conversion from "
- "%qT to %qT not permitted in C++", rhstype, type);
+ warning (OPT_Wc___compat, "request for implicit conversion from "
+ "%qT to %qT not permitted in C++", rhstype, type);
/* Check if the right-hand side has a format attribute but the
left-hand side doesn't. */
if (warn_missing_format_attribute
&& check_missing_format_attribute (type, rhstype))
- {
+ {
switch (errtype)
{
case ic_argpass:
gcc_unreachable ();
}
}
-
+
/* Any non-function converts to a [const][volatile] void *
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
(VOID_TYPE_P (ttr)
&& !null_pointer_constant_p (rhs)
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
- WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
+ WARN_FOR_ASSIGNMENT (input_location, OPT_pedantic,
+ G_("ISO C forbids passing argument %d of "
"%qE between function pointer "
"and %<void *%>"),
G_("ISO C forbids assignment between "
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 (G_("passing argument %d of %qE discards "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
G_("assignment discards qualifiers "
"from pointer target type"),
;
/* If there is a mismatch, do warn. */
else if (warn_pointer_sign)
- WARN_FOR_ASSIGNMENT (G_("pointer targets in passing argument "
+ WARN_FOR_ASSIGNMENT (input_location, OPT_Wpointer_sign,
+ G_("pointer targets in passing argument "
"%d of %qE differ in signedness"),
G_("pointer targets in assignment "
"differ in signedness"),
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 (G_("passing argument %d of %qE makes "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE makes "
"qualified function pointer "
"from unqualified"),
G_("assignment makes qualified function "
else
/* Avoid warning about the volatile ObjC EH puts on decls. */
if (!objc_ok)
- WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE from "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE from "
"incompatible pointer type"),
G_("assignment from incompatible pointer type"),
G_("initialization from incompatible "
or one that results from arithmetic, even including
a cast to integer type. */
if (!null_pointer_constant_p (rhs))
- WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE makes "
"pointer from integer without a cast"),
G_("assignment makes pointer from integer "
"without a cast"),
}
else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
{
- WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes integer "
+ WARN_FOR_ASSIGNMENT (input_location, 0,
+ G_("passing argument %d of %qE makes integer "
"from pointer without a cast"),
G_("assignment makes integer from pointer "
"without a cast"),
return error_mark_node;
}
-
-/* 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, int argnum)
-{
- tree ret, type;
-
- /* If FN was prototyped, the value has been converted already
- in convert_arguments. */
- if (!value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
- return value;
-
- type = TREE_TYPE (parm);
- ret = convert_for_assignment (type, value,
- ic_argpass_nonproto, fn,
- fn, argnum);
- if (targetm.calls.promote_prototypes (TREE_TYPE (fn))
- && INTEGRAL_TYPE_P (type)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
- ret = default_conversion (ret);
- return ret;
-}
\f
/* If VALUE is a compound expr all of whose expressions are constant, then
return its value. Otherwise, return error_mark_node.
/* ANSI wants warnings about out-of-range constant initializers. */
STRIP_TYPE_NOPS (value);
- constant_expression_warning (value);
+ if (TREE_STATIC (decl))
+ constant_expression_warning (value);
/* Check if we need to set array size from compound literal size. */
if (TREE_CODE (type) == ARRAY_TYPE
if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
- tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+ tree cldecl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
- if (TYPE_DOMAIN (TREE_TYPE (decl)))
+ if (TYPE_DOMAIN (TREE_TYPE (cldecl)))
{
/* For int foo[] = (int [3]){1}; we need to set array size
now since later on array initializer will be just the
brace enclosed list of the compound literal. */
- TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (decl));
+ type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TREE_TYPE (decl) = type;
+ TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (cldecl));
layout_type (type);
- layout_decl (decl, 0);
+ layout_decl (cldecl, 0);
}
}
}
error ("(near initialization for %qs)", ofwhat);
}
-/* Issue a pedantic warning for a bad initializer component.
- MSGID identifies the message.
- The component name is taken from the spelling stack. */
+/* 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
+ component name is taken from the spelling stack. */
void
-pedwarn_init (const char *msgid)
+pedwarn_init (location_t location, int opt, const char *msgid)
{
char *ofwhat;
- pedwarn ("%s", _(msgid));
+ pedwarn (location, opt, "%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- pedwarn ("(near initialization for %qs)", ofwhat);
+ pedwarn (location, opt, "(near initialization for %qs)", ofwhat);
}
-/* Issue a warning for a bad initializer component.
- MSGID identifies the message.
- The component name is taken from the spelling stack. */
+/* 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
+ component name is taken from the spelling stack. */
static void
-warning_init (const char *msgid)
+warning_init (int opt, const char *msgid)
{
char *ofwhat;
- warning (0, "%s", _(msgid));
+ warning (opt, "%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning (0, "(near initialization for %qs)", ofwhat);
+ warning (opt, "(near initialization for %qs)", ofwhat);
}
\f
/* If TYPE is an array type and EXPR is a parenthesized string
&& TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (expr.value) == STRING_CST
&& expr.original_code != STRING_CST)
- pedwarn_init ("array initialized from parenthesized string constant");
+ pedwarn_init (input_location, OPT_pedantic,
+ "array initialized from parenthesized string constant");
}
/* Digest the parser output INIT as an initializer for type TYPE.
|| typ1 == signed_char_type_node
|| typ1 == unsigned_char_type_node);
bool wchar_array = !!comptypes (typ1, wchar_type_node);
- if (char_array || wchar_array)
+ bool char16_array = !!comptypes (typ1, char16_type_node);
+ bool char32_array = !!comptypes (typ1, char32_type_node);
+
+ if (char_array || wchar_array || char16_array || char32_array)
{
struct c_expr expr;
- bool char_string;
+ tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)));
expr.value = inside_init;
expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
maybe_warn_string_init (type, expr);
- char_string
- = (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
- == char_type_node);
-
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
TYPE_MAIN_VARIANT (type)))
return inside_init;
- if (!wchar_array && !char_string)
+ if (char_array)
{
- error_init ("char-array initialized from wide string");
- return error_mark_node;
+ if (typ2 != char_type_node)
+ {
+ error_init ("char-array initialized from wide string");
+ return error_mark_node;
+ }
}
- if (char_string && !char_array)
+ else
{
- error_init ("wchar_t-array initialized from non-wide string");
- return error_mark_node;
+ if (typ2 == char_type_node)
+ {
+ error_init ("wide character array initialized from non-wide "
+ "string");
+ return error_mark_node;
+ }
+ else if (!comptypes(typ1, typ2))
+ {
+ error_init ("wide character array initialized from "
+ "incompatible wide string");
+ return error_mark_node;
+ }
}
TREE_TYPE (inside_init) = type;
if (TYPE_DOMAIN (type) != 0
&& TYPE_SIZE (type) != 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
- /* Subtract 1 (or sizeof (wchar_t))
+ /* Subtract the size of a single (possibly wide) character
because it's ok to ignore the terminating null char
that is counted in the length of the constant. */
&& 0 > compare_tree_int (TYPE_SIZE_UNIT (type),
TREE_STRING_LENGTH (inside_init)
- - ((TYPE_PRECISION (typ1)
- != TYPE_PRECISION (char_type_node))
- ? (TYPE_PRECISION (wchar_type_node)
- / BITS_PER_UNIT)
- : 1)))
- pedwarn_init ("initializer-string for array of chars is too long");
+ - (TYPE_PRECISION (typ1)
+ / BITS_PER_UNIT)))
+ pedwarn_init (input_location, 0,
+ "initializer-string for array of chars is too long");
return inside_init;
}
below and handle as a constructor. */
if (code == VECTOR_TYPE
&& TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
- && vector_types_convertible_p (TREE_TYPE (inside_init), type)
+ && vector_types_convertible_p (TREE_TYPE (inside_init), type, true)
&& TREE_CONSTANT (inside_init))
{
if (TREE_CODE (inside_init) == VECTOR_CST
}
}
+ if (warn_sequence_point)
+ verify_sequence_points (inside_init);
+
/* Any type can be initialized
from an expression of the same type, optionally with braces. */
conversion. */
inside_init = convert (type, inside_init);
- if (require_constant && !flag_isoc99
+ if (require_constant
+ && (code == VECTOR_TYPE || !flag_isoc99)
&& TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
{
/* As an extension, allow initializing objects with static storage
duration with compound literals (which are then treated just as
- the brace enclosed list they contain). */
+ the brace enclosed list they contain). Also allow this for
+ vectors, as we can only assign them with compound literals. */
tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
inside_init = DECL_INITIAL (decl);
}
if (inside_init == error_mark_node)
error_init ("initializer element is not constant");
else
- pedwarn_init ("initializer element is not constant");
+ pedwarn_init (input_location, OPT_pedantic,
+ "initializer element is not constant");
if (flag_pedantic_errors)
inside_init = error_mark_node;
}
/* 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 == VECTOR_TYPE)
+ if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE
+ || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE
+ || code == COMPLEX_TYPE || code == VECTOR_TYPE)
{
if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
&& (TREE_CODE (init) == STRING_CST
if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
{
missing_braces_mentioned = 1;
- warning_init ("missing braces around initializer");
+ warning_init (OPT_Wmissing_braces, "missing braces around initializer");
}
if (TREE_CODE (constructor_type) == RECORD_TYPE
else
{
if (constructor_type != error_mark_node)
- warning_init ("braces around scalar initializer");
+ warning_init (0, "braces around scalar initializer");
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
}
else
{
gcc_assert (!TYPE_SIZE (constructor_type));
-
+
if (constructor_depth > 2)
error_init ("initialization of flexible array member in a nested context");
- else if (pedantic)
- pedwarn_init ("initialization of a flexible array member");
+ else
+ pedwarn_init (input_location, OPT_pedantic,
+ "initialization of a flexible array member");
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
if (constructor_unfilled_fields && !constructor_designated)
{
push_member_name (constructor_unfilled_fields);
- warning_init ("missing initializer");
+ warning_init (OPT_Wmissing_field_initializers,
+ "missing initializer");
RESTORE_SPELLING_DEPTH (constructor_depth);
}
}
ret.value = build_constructor (constructor_type,
constructor_elements);
if (constructor_constant)
- TREE_CONSTANT (ret.value) = TREE_INVARIANT (ret.value) = 1;
+ TREE_CONSTANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
TREE_STATIC (ret.value) = 1;
}
else
{
if (TREE_SIDE_EFFECTS (p->value))
- warning_init ("initialized field with side-effects overwritten");
+ warning_init (0, "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
p->value = value;
return;
}
else
{
if (TREE_SIDE_EFFECTS (p->value))
- warning_init ("initialized field with side-effects overwritten");
+ warning_init (0, "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
p->value = value;
return;
}
gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE);
- if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
- == TYPE_PRECISION (char_type_node))
- wchar_bytes = 1;
- else
- {
- gcc_assert (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
- == TYPE_PRECISION (wchar_type_node));
- wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
- }
+ wchar_bytes = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str))) / BITS_PER_UNIT;
charwidth = TYPE_PRECISION (char_type_node);
type = TREE_TYPE (constructor_type);
p = TREE_STRING_POINTER (str);
else if (bitpos == HOST_BITS_PER_WIDE_INT)
{
if (val[1] < 0)
- val[0] = -1;
+ val[0] = -1;
}
else if (val[0] & (((HOST_WIDE_INT) 1)
<< (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
value = error_mark_node;
}
else if (require_constant_elements)
- pedwarn ("initializer element is not computable at load time");
+ pedwarn (input_location, 0,
+ "initializer element is not computable at load time");
}
/* If this field is empty (and not at the end of structure),
{
if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
constructor_elements)->value))
- warning_init ("initialized field with side-effects overwritten");
+ warning_init (0, "initialized field with side-effects overwritten");
+ else if (warn_override_init)
+ warning_init (OPT_Woverride_init, "initialized field overwritten");
/* We can have just one union field set. */
constructor_elements = 0;
&& integer_zerop (constructor_unfilled_index))
{
if (constructor_stack->replacement_value.value)
- error_init ("excess elements in char array initializer");
+ error_init ("excess elements in char array initializer");
constructor_stack->replacement_value = value;
return;
}
if (constructor_fields == 0)
{
- pedwarn_init ("excess elements in struct initializer");
+ pedwarn_init (input_location, 0,
+ "excess elements in struct initializer");
break;
}
{
/* For a record, keep track of end position of last field. */
if (DECL_SIZE (constructor_fields))
- constructor_bit_index
+ constructor_bit_index
= size_binop (PLUS_EXPR,
- bit_position (constructor_fields),
- DECL_SIZE (constructor_fields));
+ bit_position (constructor_fields),
+ DECL_SIZE (constructor_fields));
/* If the current field was the first one not yet written out,
it isn't now, so update. */
if (constructor_fields == 0)
{
- pedwarn_init ("excess elements in union initializer");
+ pedwarn_init (input_location, 0,
+ "excess elements in union initializer");
break;
}
&& (tree_int_cst_lt (constructor_max_index, constructor_index)
|| integer_all_onesp (constructor_max_index)))
{
- pedwarn_init ("excess elements in array initializer");
+ pedwarn_init (input_location, 0,
+ "excess elements in array initializer");
break;
}
{
tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
- /* Do a basic check of initializer size. Note that vectors
- always have a fixed size derived from their type. */
+ /* Do a basic check of initializer size. Note that vectors
+ always have a fixed size derived from their type. */
if (tree_int_cst_lt (constructor_max_index, constructor_index))
{
- pedwarn_init ("excess elements in vector initializer");
+ pedwarn_init (input_location, 0,
+ "excess elements in vector initializer");
break;
}
else if (constructor_type != error_mark_node
&& constructor_fields == 0)
{
- pedwarn_init ("excess elements in scalar initializer");
+ pedwarn_init (input_location, 0,
+ "excess elements in scalar initializer");
break;
}
else
output = error_mark_node;
}
else
- output = error_mark_node;
+ output = error_mark_node;
TREE_VALUE (tail) = output;
}
tree
c_finish_goto_ptr (tree expr)
{
- if (pedantic)
- pedwarn ("ISO C forbids %<goto *expr;%>");
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids %<goto *expr;%>");
expr = convert (ptr_type_node, expr);
return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
{
- pedwarn_c99 ("%<return%> with no value, in "
+ pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wreturn_type,
+ "%<return%> with no value, in "
"function returning non-void");
no_warning = true;
}
else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
- if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("%<return%> with a value, in function returning void");
+ if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
+ pedwarn (input_location, 0,
+ "%<return%> with a value, in function returning void");
+ else
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids "
+ "%<return%> with expression, in function returning void");
}
else
{
{
switch (TREE_CODE (inner))
{
- case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR:
+ CASE_CONVERT: case NON_LVALUE_EXPR:
case PLUS_EXPR:
inner = TREE_OPERAND (inner, 0);
continue;
tree op1 = TREE_OPERAND (inner, 1);
while (!POINTER_TYPE_P (TREE_TYPE (op1))
- && (TREE_CODE (op1) == NOP_EXPR
- || TREE_CODE (op1) == NON_LVALUE_EXPR
- || TREE_CODE (op1) == CONVERT_EXPR))
+ && (CONVERT_EXPR_P (op1)
+ || TREE_CODE (op1) == NON_LVALUE_EXPR))
op1 = TREE_OPERAND (op1, 0);
if (POINTER_TYPE_P (TREE_TYPE (op1)))
inner = TREE_OPERAND (inner, 0);
while (REFERENCE_CLASS_P (inner)
- && TREE_CODE (inner) != INDIRECT_REF)
+ && TREE_CODE (inner) != INDIRECT_REF)
inner = TREE_OPERAND (inner, 0);
if (DECL_P (inner)
}
retval = build2 (MODIFY_EXPR, TREE_TYPE (res), res, t);
+
+ if (warn_sequence_point)
+ verify_sequence_points (retval);
}
ret_stmt = build_stmt (RETURN_EXPR, retval);
tree
c_start_case (tree exp)
{
- enum tree_code code;
- tree type, orig_type = error_mark_node;
+ tree orig_type = error_mark_node;
struct c_switch *cs;
if (exp != error_mark_node)
{
- code = TREE_CODE (TREE_TYPE (exp));
orig_type = TREE_TYPE (exp);
- if (!INTEGRAL_TYPE_P (orig_type)
- && code != ERROR_MARK)
+ if (!INTEGRAL_TYPE_P (orig_type))
{
- error ("switch quantity not an integer");
+ if (orig_type != error_mark_node)
+ {
+ error ("switch quantity not an integer");
+ orig_type = error_mark_node;
+ }
exp = integer_zero_node;
- orig_type = error_mark_node;
}
else
{
- type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ tree type = TYPE_MAIN_VARIANT (orig_type);
if (!in_system_header
&& (type == long_integer_type_node
"converted to %<int%> in ISO C");
exp = default_conversion (exp);
- type = TREE_TYPE (exp);
+
+ if (warn_sequence_point)
+ verify_sequence_points (exp);
}
}
&if_locus);
}
- empty_body_warning (then_block, else_block);
+ empty_if_body_warning (then_block, else_block);
stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
SET_EXPR_LOCATION (stmt, if_locus);
else
{
tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-
+
/* If we have an exit condition, then we build an IF with gotos either
- out of the loop, or to the top of it. If there's no exit condition,
- then we just build a jump back to the top. */
+ out of the loop, or to the top of it. If there's no exit condition,
+ then we just build a jump back to the top. */
exit = build_and_jump (&LABEL_EXPR_LABEL (top));
-
+
if (cond && !integer_nonzerop (cond))
- {
- /* Canonicalize the loop condition to the end. This means
- generating a branch to the loop condition. Reuse the
- continue label, if possible. */
- if (cond_is_first)
- {
- if (incr || !clab)
- {
- entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
- t = build_and_jump (&LABEL_EXPR_LABEL (entry));
- }
- else
- t = build1 (GOTO_EXPR, void_type_node, clab);
+ {
+ /* Canonicalize the loop condition to the end. This means
+ generating a branch to the loop condition. Reuse the
+ continue label, if possible. */
+ if (cond_is_first)
+ {
+ if (incr || !clab)
+ {
+ entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+ t = build_and_jump (&LABEL_EXPR_LABEL (entry));
+ }
+ else
+ t = build1 (GOTO_EXPR, void_type_node, clab);
SET_EXPR_LOCATION (t, start_locus);
- add_stmt (t);
- }
-
+ add_stmt (t);
+ }
+
t = build_and_jump (&blab);
- exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t);
+ exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t);
if (cond_is_first)
- SET_EXPR_LOCATION (exit, start_locus);
+ SET_EXPR_LOCATION (exit, start_locus);
else
- SET_EXPR_LOCATION (exit, input_location);
- }
-
+ SET_EXPR_LOCATION (exit, input_location);
+ }
+
add_stmt (top);
}
-
+
if (body)
add_stmt (body);
if (clab)
if (is_break)
error ("break statement not within loop or switch");
else
- error ("continue statement not within a loop");
+ error ("continue statement not within a loop");
return NULL_TREE;
case 1:
if (skip)
return NULL_TREE;
+ if (!is_break)
+ add_stmt (build_predict_expr (PRED_CONTINUE, NOT_TAKEN));
+
return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
}
else if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
- warning (0, "%Hstatement with no effect",
+ warning (OPT_Wunused_value, "%Hstatement with no effect",
EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
}
- else if (warn_unused_value)
+ else
warn_if_unused_value (expr, input_location);
}
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))
+ && warn_unused_value)
emit_side_effect_warnings (expr);
/* If the expression is not of a type to which we cannot assign a line
if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
- if (EXPR_P (expr))
+ if (CAN_HAVE_LOCATION_P (expr))
SET_EXPR_LOCATION (expr, input_location);
return expr;
/* If we're supposed to generate side effects warnings, process
all of the statements except the last. */
- if (extra_warnings || warn_unused_value)
+ if (warn_unused_value)
{
for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
emit_side_effect_warnings (tsi_stmt (i));
{
/* Do not warn if the return value of a statement expression is
unused. */
- if (EXPR_P (last))
+ if (CAN_HAVE_LOCATION_P (last))
TREE_NO_WARNING (last) = 1;
return last;
}
struct c_label_list *glist;
gcc_assert (scope > 0);
+
+ /* At file_scope, we don't have to do any processing. */
+ if (label_context_stack_vm == NULL)
+ return;
+
if (c_switch_stack && !c_switch_stack->blocked_vm)
c_switch_stack->blocked_vm = scope;
for (glist = label_context_stack_vm->labels_used;
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
- /* Floating point division by zero is a legitimate way to obtain
- infinities and NaNs. */
- if (skip_evaluation == 0 && integer_zerop (op1))
- warning (OPT_Wdiv_by_zero, "division by zero");
+ warn_for_div_by_zero (op1);
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == FIXED_POINT_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == FIXED_POINT_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
enum tree_code tcode0 = code0, tcode1 = code1;
if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
- if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
+ if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)
+ || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
resultcode = RDIV_EXPR;
else
/* Although it would be tempting to shorten always here, that
case BIT_XOR_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
shorten = -1;
- else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ /* Allow vector types which are not floating point types. */
+ else if (code0 == VECTOR_TYPE
+ && code1 == VECTOR_TYPE
+ && !VECTOR_FLOAT_TYPE_P (type0)
+ && !VECTOR_FLOAT_TYPE_P (type1))
common = 1;
break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
- if (skip_evaluation == 0 && integer_zerop (op1))
- warning (OPT_Wdiv_by_zero, "division by zero");
+ warn_for_div_by_zero (op1);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
- || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+ || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
+ || code0 == FIXED_POINT_TYPE)
&& (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
- || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+ || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+ || code1 == FIXED_POINT_TYPE))
{
/* Result of these operations is always an int,
but that does not mean the operands should be
Also set SHORT_SHIFT if shifting rightward. */
case RSHIFT_EXPR:
- if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ && code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
break;
case LSHIFT_EXPR:
- if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+ if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+ && code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
case EQ_EXPR:
case NE_EXPR:
- if (code0 == REAL_TYPE || code1 == REAL_TYPE)
+ if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1))
warning (OPT_Wfloat_equal,
"comparing floating point with == or != is unsafe");
/* Result of comparison is always int,
but don't convert the args to int! */
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
- || code0 == COMPLEX_TYPE)
+ || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
- || code1 == COMPLEX_TYPE))
+ || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
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)
- pedwarn ("ISO C forbids comparison of %<void *%>"
- " with function pointer");
+ pedwarn (input_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)
- pedwarn ("ISO C forbids comparison of %<void *%>"
- " with function pointer");
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids "
+ "comparison of %<void *%> with function pointer");
}
else
/* Avoid warning about the volatile ObjC EH puts on decls. */
if (!objc_ok)
- pedwarn ("comparison of distinct pointer types lacks a cast");
+ pedwarn (input_location, 0,
+ "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_P (TREE_OPERAND (op0, 0))
- && !DECL_WEAK (TREE_OPERAND (op0, 0)))
- warning (OPT_Walways_true, "the address of %qD will never be NULL",
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
+ warning (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_P (TREE_OPERAND (op1, 0))
- && !DECL_WEAK (TREE_OPERAND (op1, 0)))
- warning (OPT_Walways_true, "the address of %qD will never be NULL",
+ if (TREE_CODE (op1) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
+ warning (OPT_Waddress, "the address of %qD will never be NULL",
TREE_OPERAND (op1, 0));
result_type = type1;
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- pedwarn ("comparison between pointer and integer");
+ pedwarn (input_location, 0, "comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- pedwarn ("comparison between pointer and integer");
+ pedwarn (input_location, 0, "comparison between pointer and integer");
}
break;
case LT_EXPR:
case GT_EXPR:
build_type = integer_type_node;
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == FIXED_POINT_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == FIXED_POINT_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
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");
- else if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
+ pedwarn (input_location, 0,
+ "comparison of complete and incomplete pointers");
+ else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+ pedwarn (input_location, OPT_pedantic, "ISO C forbids "
+ "ordered comparisons of pointers to functions");
}
else
{
result_type = ptr_type_node;
- pedwarn ("comparison of distinct pointer types lacks a cast");
+ pedwarn (input_location, 0,
+ "comparison of distinct pointer types lacks a cast");
}
}
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
{
result_type = type0;
- if (pedantic || extra_warnings)
- pedwarn ("ordered comparison of pointer with integer zero");
+ if (pedantic)
+ pedwarn (input_location, OPT_pedantic,
+ "ordered comparison of pointer with integer zero");
+ else if (extra_warnings)
+ warning (OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
}
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
{
result_type = type1;
- if (pedantic)
- pedwarn ("ordered comparison of pointer with integer zero");
+ pedwarn (input_location, OPT_pedantic,
+ "ordered comparison of pointer with integer zero");
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- pedwarn ("comparison between pointer and integer");
+ pedwarn (input_location, 0, "comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- pedwarn ("comparison between pointer and integer");
+ pedwarn (input_location, 0, "comparison between pointer and integer");
}
break;
|| !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
TREE_TYPE (type1))))
{
- binary_op_error (code);
+ binary_op_error (code, type0, type1);
return error_mark_node;
}
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
- || code0 == VECTOR_TYPE)
+ || code0 == FIXED_POINT_TYPE || code0 == VECTOR_TYPE)
&&
(code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
- || code1 == VECTOR_TYPE))
+ || code1 == FIXED_POINT_TYPE || code1 == VECTOR_TYPE))
{
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
if (shorten || common || short_compare)
- result_type = c_common_type (type0, type1);
+ {
+ result_type = c_common_type (type0, type1);
+ if (result_type == error_mark_node)
+ return error_mark_node;
+ }
/* For certain operations (which identify themselves by shorten != 0)
if both args were extended from the same smaller type,
if (shorten && none_complex)
{
- int unsigned0, unsigned1;
- tree arg0, arg1;
- int uns;
- tree type;
-
- /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents
- excessive narrowing when we call get_narrower below. For
- example, suppose that OP0 is of unsigned int extended
- from signed char and that RESULT_TYPE is long long int.
- If we explicitly cast OP0 to RESULT_TYPE, OP0 would look
- like
-
- (long long int) (unsigned int) signed_char
-
- which get_narrower would narrow down to
-
- (unsigned int) signed char
-
- If we do not cast OP0 first, get_narrower would return
- signed_char, which is inconsistent with the case of the
- explicit cast. */
- op0 = convert (result_type, op0);
- op1 = convert (result_type, op1);
-
- arg0 = get_narrower (op0, &unsigned0);
- arg1 = get_narrower (op1, &unsigned1);
-
- /* UNS is 1 if the operation to be done is an unsigned one. */
- uns = TYPE_UNSIGNED (result_type);
-
final_type = result_type;
-
- /* Handle the case that OP0 (or OP1) does not *contain* a conversion
- but it *requires* conversion to FINAL_TYPE. */
-
- if ((TYPE_PRECISION (TREE_TYPE (op0))
- == TYPE_PRECISION (TREE_TYPE (arg0)))
- && TREE_TYPE (op0) != final_type)
- unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
- if ((TYPE_PRECISION (TREE_TYPE (op1))
- == TYPE_PRECISION (TREE_TYPE (arg1)))
- && TREE_TYPE (op1) != final_type)
- unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
-
- /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
-
- /* For bitwise operations, signedness of nominal type
- does not matter. Consider only how operands were extended. */
- if (shorten == -1)
- uns = unsigned0;
-
- /* Note that in all three cases below we refrain from optimizing
- an unsigned operation on sign-extended args.
- That would not be valid. */
-
- /* Both args variable: if both extended in same way
- from same width, do it in that width.
- Do it unsigned if args were zero-extended. */
- if ((TYPE_PRECISION (TREE_TYPE (arg0))
- < TYPE_PRECISION (result_type))
- && (TYPE_PRECISION (TREE_TYPE (arg1))
- == TYPE_PRECISION (TREE_TYPE (arg0)))
- && unsigned0 == unsigned1
- && (unsigned0 || !uns))
- result_type
- = c_common_signed_or_unsigned_type
- (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
- else if (TREE_CODE (arg0) == INTEGER_CST
- && (unsigned1 || !uns)
- && (TYPE_PRECISION (TREE_TYPE (arg1))
- < TYPE_PRECISION (result_type))
- && (type
- = c_common_signed_or_unsigned_type (unsigned1,
- TREE_TYPE (arg1)),
- int_fits_type_p (arg0, type)))
- result_type = type;
- else if (TREE_CODE (arg1) == INTEGER_CST
- && (unsigned0 || !uns)
- && (TYPE_PRECISION (TREE_TYPE (arg0))
- < TYPE_PRECISION (result_type))
- && (type
- = c_common_signed_or_unsigned_type (unsigned0,
- TREE_TYPE (arg0)),
- int_fits_type_p (arg1, type)))
- result_type = type;
+ result_type = shorten_binary_op (result_type, op0, op1,
+ shorten == -1);
}
/* Shifts can be shortened if shifting right. */
converted = 1;
resultcode = xresultcode;
- if (warn_sign_compare && skip_evaluation == 0)
- {
- 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);
-
- xop0 = orig_op0;
- xop1 = orig_op1;
- STRIP_TYPE_NOPS (xop0);
- STRIP_TYPE_NOPS (xop1);
-
- /* Give warnings for comparisons between signed and unsigned
- quantities that may fail.
-
- Do the checking based on the original operand trees, so that
- casts will be considered, but default promotions won't be.
-
- 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 (!TYPE_UNSIGNED (result_type))
- /* OK */;
- /* Do not warn if both operands are the same signedness. */
- else if (op0_signed == op1_signed)
- /* OK */;
- else
- {
- tree sop, uop;
-
- if (op0_signed)
- sop = xop0, uop = xop1;
- else
- sop = xop1, uop = xop0;
-
- /* Do not warn if the signed quantity is an
- unsuffixed integer literal (or some static
- constant expression involving such literals or a
- conditional expression involving such literals)
- and it is non-negative. */
- 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
- would fit in the result if the result were signed. */
- else if (TREE_CODE (uop) == INTEGER_CST
- && (resultcode == EQ_EXPR || resultcode == NE_EXPR)
- && int_fits_type_p
- (uop, c_common_signed_type (result_type)))
- /* OK */;
- /* Do not warn if the unsigned quantity is an enumeration
- constant and its maximum value would fit in the result
- if the result were signed. */
- else if (TREE_CODE (uop) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
- && int_fits_type_p
- (TYPE_MAX_VALUE (TREE_TYPE (uop)),
- c_common_signed_type (result_type)))
- /* OK */;
- else
- warning (0, "comparison between signed and unsigned");
- }
-
- /* Warn if two unsigned values are being compared in a size
- larger than their original size, and one (and only one) is the
- result of a `~' operator. This comparison will always fail.
-
- Also warn if one operand is a constant, and the constant
- does not have all bits set that are set in the ~ operand
- when it is extended. */
-
- if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
- != (TREE_CODE (primop1) == BIT_NOT_EXPR))
- {
- if (TREE_CODE (primop0) == BIT_NOT_EXPR)
- primop0 = get_narrower (TREE_OPERAND (primop0, 0),
- &unsignedp0);
- else
- primop1 = get_narrower (TREE_OPERAND (primop1, 0),
- &unsignedp1);
-
- if (host_integerp (primop0, 0) || host_integerp (primop1, 0))
- {
- tree primop;
- HOST_WIDE_INT constant, mask;
- int unsignedp, bits;
-
- if (host_integerp (primop0, 0))
- {
- primop = primop1;
- unsignedp = unsignedp1;
- constant = tree_low_cst (primop0, 0);
- }
- else
- {
- primop = primop0;
- unsignedp = unsignedp0;
- constant = tree_low_cst (primop1, 0);
- }
-
- bits = TYPE_PRECISION (TREE_TYPE (primop));
- if (bits < TYPE_PRECISION (result_type)
- && bits < HOST_BITS_PER_WIDE_INT && unsignedp)
- {
- mask = (~(HOST_WIDE_INT) 0) << bits;
- if ((mask & constant) != mask)
- warning (0, "comparison of promoted ~unsigned with constant");
- }
- }
- else if (unsignedp0 && unsignedp1
- && (TYPE_PRECISION (TREE_TYPE (primop0))
- < TYPE_PRECISION (result_type))
- && (TYPE_PRECISION (TREE_TYPE (primop1))
- < TYPE_PRECISION (result_type)))
- warning (0, "comparison of promoted ~unsigned with unsigned");
- }
+ if (warn_sign_compare && !skip_evaluation)
+ {
+ warn_for_sign_compare (orig_op0, orig_op1, op0, op1,
+ result_type, resultcode);
}
}
}
if (!result_type)
{
- binary_op_error (code);
+ binary_op_error (code, TREE_TYPE (op0), TREE_TYPE (op1));
return error_mark_node;
}
required. */
tree
-c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED,
- bool *ti ATTRIBUTE_UNUSED, bool *se)
+c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se)
{
if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR)
{
else
return expr;
}
-
\f
/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */
return block;
}
+/* Generate OMP_PARALLEL, with CLAUSES and BLOCK as its compound statement. */
+
tree
c_finish_omp_parallel (tree clauses, tree block)
{
return add_stmt (stmt);
}
+/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */
+
+tree
+c_begin_omp_task (void)
+{
+ tree block;
+
+ keep_next_level ();
+ block = c_begin_compound_stmt (true);
+
+ return block;
+}
+
+/* Generate OMP_TASK, with CLAUSES and BLOCK as its compound statement. */
+
+tree
+c_finish_omp_task (tree clauses, tree block)
+{
+ tree stmt;
+
+ block = c_end_compound_stmt (block, true);
+
+ stmt = make_node (OMP_TASK);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TASK_CLAUSES (stmt) = clauses;
+ OMP_TASK_BODY (stmt) = block;
+
+ return add_stmt (stmt);
+}
+
/* For all elements of CLAUSES, validate them vs OpenMP constraints.
Remove any elements from the list that are invalid. */
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
+ case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_COLLAPSE:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
bitmap_obstack_release (NULL);
return clauses;
}
+
+/* Make a variant type in the proper way for C/C++, propagating qualifiers
+ down to the element type of an array. */
+
+tree
+c_build_qualified_type (tree type, int type_quals)
+{
+ if (type == error_mark_node)
+ return type;
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree t;
+ tree element_type = c_build_qualified_type (TREE_TYPE (type),
+ type_quals);
+
+ /* See if we already have an identically qualified type. */
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ if (TYPE_QUALS (strip_array_types (t)) == type_quals
+ && TYPE_NAME (t) == TYPE_NAME (type)
+ && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+ && attribute_list_equal (TYPE_ATTRIBUTES (t),
+ TYPE_ATTRIBUTES (type)))
+ break;
+ }
+ if (!t)
+ {
+ tree domain = TYPE_DOMAIN (type);
+
+ t = build_variant_type_copy (type);
+ TREE_TYPE (t) = element_type;
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (element_type)
+ || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain)))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (element_type) != element_type
+ || (domain && TYPE_CANONICAL (domain) != domain))
+ {
+ tree unqualified_canon
+ = build_array_type (TYPE_CANONICAL (element_type),
+ domain? TYPE_CANONICAL (domain)
+ : NULL_TREE);
+ TYPE_CANONICAL (t)
+ = c_build_qualified_type (unqualified_canon, type_quals);
+ }
+ else
+ TYPE_CANONICAL (t) = t;
+ }
+ return t;
+ }
+
+ /* A restrict-qualified pointer type must be a pointer to object or
+ incomplete type. Note that the use of POINTER_TYPE_P also allows
+ REFERENCE_TYPEs, which is appropriate for C++. */
+ if ((type_quals & TYPE_QUAL_RESTRICT)
+ && (!POINTER_TYPE_P (type)
+ || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
+ {
+ error ("invalid use of %<restrict%>");
+ type_quals &= ~TYPE_QUAL_RESTRICT;
+ }
+
+ return build_qualified_type (type, type_quals);
+}