/* The level of nesting inside "typeof". */
int in_typeof;
-struct c_label_context *label_context_stack;
+struct c_label_context_se *label_context_stack_se;
+struct c_label_context_vm *label_context_stack_vm;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static tree qualify_type (tree, tree);
static int tagged_types_tu_compatible_p (tree, tree);
-static int comp_target_types (tree, tree, int);
+static int comp_target_types (tree, tree);
static int function_types_compatible_p (tree, tree);
static int type_lists_compatible_p (tree, tree);
static tree decl_constant_value_for_broken_optimization (tree);
/* If both args specify argument types, we must merge the two
lists, argument by argument. */
/* Tell global_bindings_p to return false so that variable_size
- doesn't abort on VLAs in parameter types. */
+ doesn't die on VLAs in parameter types. */
c_override_global_bindings_to_false = true;
len = list_length (p1);
}
\f
/* Wrapper around c_common_type that is used by c-common.c. ENUMERAL_TYPEs
- are allowed here and are converted to their compatible integer types. */
+ are allowed here and are converted to their compatible integer types.
+ BOOLEAN_TYPEs are allowed here and return either boolean_type_node or
+ preferably a non-Boolean type as the common type. */
tree
common_type (tree t1, tree t2)
{
t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
+
+ /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */
+ if (TREE_CODE (t1) == BOOLEAN_TYPE
+ && TREE_CODE (t2) == BOOLEAN_TYPE)
+ return boolean_type_node;
+
+ /* If either type is BOOLEAN_TYPE, then return the other. */
+ if (TREE_CODE (t1) == BOOLEAN_TYPE)
+ return t2;
+ if (TREE_CODE (t2) == BOOLEAN_TYPE)
+ return t1;
+
return c_common_type (t1, t2);
}
\f
switch (TREE_CODE (t1))
{
case POINTER_TYPE:
- /* We must give ObjC the first crack at comparing pointers, since
- protocol qualifiers may be involved. */
- if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0)
- break;
/* Do not remove mode or aliasing information. */
if (TYPE_MODE (t1) != TYPE_MODE (t2)
|| TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
break;
}
- case RECORD_TYPE:
- /* We are dealing with two distinct structs. In assorted Objective-C
- corner cases, however, these can still be deemed equivalent. */
- if (c_dialect_objc () && objc_comptypes (t1, t2, 0) == 1)
- val = 1;
-
case ENUMERAL_TYPE:
+ case RECORD_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
val = tagged_types_tu_compatible_p (t1, t2);
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. REFLEXIVE is only used by ObjC - set it
- to 1 or 0 depending if the check of the pointer types is meant to
- be reflexive or not (typically, assignments are not reflexive,
- while comparisons are reflexive).
-*/
+ ignoring their qualifiers. */
static int
-comp_target_types (tree ttl, tree ttr, int reflexive)
+comp_target_types (tree ttl, tree ttr)
{
int val;
tree mvl, mvr;
- /* Give objc_comptypes a crack at letting these types through. */
- if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
- return val;
-
/* Do not lose qualifiers on element types of array types that are
pointer targets by taking their TYPE_MAIN_VARIANT. */
mvl = TREE_TYPE (ttl);
return 0;
/* If one of these types comes from a non-prototype fn definition,
compare that with the other type's arglist.
- If they don't match, ask for a warning (but no error). */
+ If they don't match, ask for a warning (0, but no error). */
if (TYPE_ACTUAL_ARG_TYPES (f1)
&& 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
val = 2;
static tree
decl_constant_value_for_broken_optimization (tree decl)
{
+ tree ret;
+
if (pedantic || DECL_MODE (decl) == BLKmode)
return decl;
- else
- return decl_constant_value (decl);
+
+ ret = decl_constant_value (decl);
+ /* Avoid unwanted tree sharing between the initializer and current
+ function's body where the tree can be modified e.g. by the
+ gimplifier. */
+ if (ret != decl && TREE_STATIC (decl))
+ ret = unshare_expr (ret);
+ return ret;
}
return error_mark_node;
}
if (VOID_TYPE_P (t) && skip_evaluation == 0)
- warning ("dereferencing %<void *%> pointer");
+ warning (0, "dereferencing %<void *%> pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
char[array]. */
if (warn_char_subscripts && !swapped
&& TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
- warning ("array subscript has type %<char%>");
+ warning (0, "array subscript has type %<char%>");
/* Apply default promotions *after* noticing character types. */
index = default_conversion (index);
/* Convert anything with function type to a pointer-to-function. */
if (TREE_CODE (function) == FUNCTION_DECL)
{
+ /* Implement type-directed function overloading for builtins.
+ resolve_overloaded_builtin and targetm.resolve_overloaded_builtin
+ handle all the type checking. The result is a complete expression
+ that implements this function call. */
+ tem = resolve_overloaded_builtin (function, params);
+ if (tem)
+ return tem;
+
name = DECL_NAME (function);
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
else
function = default_conversion (function);
+ /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
+ expressions, like those used for ObjC messenger dispatches. */
+ function = objc_rewrite_function_call (function, params);
+
fntype = TREE_TYPE (function);
if (TREE_CODE (fntype) == ERROR_MARK)
If it is not, replace the call by a trap, wrapped up in a compound
expression if necessary. This has the nice side-effect to prevent
the tree-inliner from generating invalid assignment trees which may
- blow up in the RTL expander later.
-
- ??? This doesn't work for Objective-C because objc_comptypes
- refuses to compare function prototypes, yet the compiler appears
- to build calls that are flagged as invalid by C's comptypes. */
- if (!c_dialect_objc ()
- && TREE_CODE (function) == NOP_EXPR
+ blow up in the RTL expander later. */
+ if (TREE_CODE (function) == NOP_EXPR
&& TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
&& !comptypes (fntype, TREE_TYPE (tem)))
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
executions of the program must execute the code. */
- warning ("function called through a non-compatible type");
+ 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. */
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than floating due to prototype",
argnum, rname);
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as integer "
+ warning (0, "passing argument %d of %qE as integer "
"rather than complex due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than floating due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (val)))
- warning ("passing argument %d of %qE as complex "
+ warning (0, "passing argument %d of %qE as complex "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
&& TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
- warning ("passing argument %d of %qE as floating "
+ warning (0, "passing argument %d of %qE as floating "
"rather than complex due to prototype",
argnum, rname);
/* ??? At some point, messages should be written about
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
if (formal_prec == TYPE_PRECISION (float_type_node))
- warning ("passing argument %d of %qE as %<float%> "
+ warning (0, "passing argument %d of %qE as %<float%> "
"rather than %<double%> due to prototype",
argnum, rname);
}
and the actual arg is that enum type. */
;
else if (formal_prec != TYPE_PRECISION (type1))
- warning ("passing argument %d of %qE with different "
+ warning (0, "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 ("passing argument %d of %qE as unsigned "
+ warning (0, "passing argument %d of %qE as unsigned "
"due to prototype", argnum, rname);
else
- warning ("passing argument %d of %qE as signed "
+ warning (0, "passing argument %d of %qE as signed "
"due to prototype", argnum, rname);
}
}
return nreverse (result);
}
\f
-/* This is the entry point used by the parser
- for binary operators in the input.
- In addition to constructing the expression,
- we check for operands that were written with other binary operators
- in a way that is likely to confuse the user. */
+/* 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. */
+
+struct c_expr
+parser_build_unary_op (enum tree_code code, struct c_expr arg)
+{
+ struct c_expr result;
+
+ result.original_code = ERROR_MARK;
+ result.value = build_unary_op (code, arg.value, 0);
+ overflow_warning (result.value);
+ return result;
+}
+
+/* This is the entry point used by the parser to build binary operators
+ in the input. CODE, a tree_code, specifies the binary operator, and
+ ARG1 and ARG2 are the operands. In addition to constructing the
+ expression, we check for operands that were written with other binary
+ operators in a way that is likely to confuse the user. */
struct c_expr
parser_build_binary_op (enum tree_code code, struct c_expr arg1,
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around + or - inside shift");
+ warning (0, "suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code1 == TRUTH_ANDIF_EXPR
|| code2 == TRUTH_ANDIF_EXPR)
- warning ("suggest parentheses around && within ||");
+ warning (0, "suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of |");
+ warning (0, "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 ("suggest parentheses around comparison in operand of |");
+ warning (0, "suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
- warning ("suggest parentheses around arithmetic in operand of ^");
+ warning (0, "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 ("suggest parentheses around comparison in operand of ^");
+ warning (0, "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 ("suggest parentheses around + or - in operand of &");
+ warning (0, "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 ("suggest parentheses around comparison in operand of &");
+ warning (0, "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 ("comparisons like X<=Y<=Z do not have their mathematical meaning");
+ warning (0, "comparisons like X<=Y<=Z do not have their mathematical meaning");
}
|| (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
- warning ("signed and unsigned type in conditional expression");
+ warning (0, "signed and unsigned type in conditional expression");
}
}
}
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
- if (comp_target_types (type1, type2, 1))
+ if (comp_target_types (type1, type2))
result_type = common_pointer_type (type1, type2);
else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
&& TREE_CODE (orig_op1) != NOP_EXPR)
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- if (TREE_CODE (ifexp) == INTEGER_CST)
- return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
-
- return fold (build3 (COND_EXPR, result_type, ifexp, op1, op2));
+ return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
}
\f
/* Return a compound expression that performs two expressions and
/* 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
any side-effects, unless it was explicitly cast to (void). */
- if (warn_unused_value
- && !(TREE_CODE (expr1) == CONVERT_EXPR
- && VOID_TYPE_P (TREE_TYPE (expr1))))
- warning ("left-hand operand of comma expression has no effect");
+ if (warn_unused_value)
+ {
+ if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == CONVERT_EXPR)
+ ; /* (void) a, b */
+ else if (VOID_TYPE_P (TREE_TYPE (expr1))
+ && TREE_CODE (expr1) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR)
+ ; /* (void) a, (void) b, c */
+ else
+ warning (0, "left-hand operand of comma expression has no effect");
+ }
}
/* With -Wunused, we should also warn if the left-hand operand does have
&& TREE_CODE (in_otype) == POINTER_TYPE);
if (added)
- warning ("cast adds new qualifiers to function type");
+ warning (0, "cast adds new qualifiers to function type");
if (discarded)
/* There are qualifiers present in IN_OTYPE that are not
present in IN_TYPE. */
- warning ("cast discards qualifiers from pointer target type");
+ warning (0, "cast discards qualifiers from pointer target type");
}
/* Warn about possible alignment problems. */
|| TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
&& TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast increases required alignment of target type");
+ warning (0, "cast increases required alignment of target type");
- if (TREE_CODE (type) == INTEGER_TYPE
+ if (warn_pointer_to_int_cast
+ && TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
&& !TREE_CONSTANT (value))
- warning ("cast from pointer to integer of different size");
+ warning (0, "cast from pointer to integer of different size");
if (warn_bad_function_cast
&& TREE_CODE (value) == CALL_EXPR
&& TREE_CODE (type) != TREE_CODE (otype))
- warning ("cast from function call of type %qT to non-matching "
+ warning (0, "cast from function call of type %qT to non-matching "
"type %qT", otype, type);
- if (TREE_CODE (type) == POINTER_TYPE
+ if (warn_int_to_pointer_cast
+ && TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
/* Don't warn about converting any constant. */
&& !TREE_CONSTANT (value))
- warning ("cast to pointer from integer of different size");
+ warning (0, "cast to pointer from integer of different size");
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
/* Casting the address of a decl to non void pointer. Warn
if the cast breaks type based aliasing. */
if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
- warning ("type-punning to incomplete type might break strict-aliasing rules");
+ warning (0, "type-punning to incomplete type might break strict-aliasing rules");
else
{
HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
if (!alias_sets_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+ warning (0, "dereferencing type-punned pointer will break strict-aliasing rules");
else if (warn_strict_aliasing > 1
&& !alias_sets_might_conflict_p (set1, set2))
- warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+ warning (0, "dereferencing type-punned pointer might break strict-aliasing rules");
}
}
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
+ /* Emit ObjC write barrier, if necessary. */
+ if (c_dialect_objc () && flag_objc_gc)
+ {
+ result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+ if (result)
+ return result;
+ }
+
/* Scan operands. */
result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
tree rhstype;
enum tree_code coder;
tree rname = NULL_TREE;
+ bool objc_ok = false;
if (errtype == ic_argpass || errtype == ic_argpass_nonproto)
{
pedwarn (AR, parmnum, rname); \
break; \
case ic_argpass_nonproto: \
- warning (AR, parmnum, rname); \
+ warning (0, AR, parmnum, rname); \
break; \
case ic_assign: \
pedwarn (AS); \
if (coder == ERROR_MARK)
return error_mark_node;
+ if (c_dialect_objc ())
+ {
+ int parmno;
+
+ switch (errtype)
+ {
+ case ic_return:
+ parmno = 0;
+ break;
+
+ case ic_assign:
+ parmno = -1;
+ break;
+
+ case ic_init:
+ parmno = -2;
+ break;
+
+ default:
+ parmno = parmnum;
+ break;
+ }
+
+ objc_ok = objc_compare_types (type, rhstype, parmno, rname);
+ }
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
overflow_warning (rhs);
- /* Check for Objective-C protocols. This will automatically
- issue a warning if there are protocol violations. No need to
- use the return value. */
- if (c_dialect_objc ())
- objc_comptypes (type, rhstype, 0);
return rhs;
}
Meanwhile, the lhs target must have all the qualifiers of
the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || comp_target_types (memb_type, rhstype, 0))
+ || comp_target_types (memb_type, rhstype))
{
/* If this type won't generate any warnings, use it. */
if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
and vice versa; otherwise, targets must be the same.
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
- || (target_cmp = comp_target_types (type, rhstype, 0))
+ || (target_cmp = comp_target_types (type, rhstype))
|| is_opaque_pointer
|| (c_common_unsigned_type (mvl)
== c_common_unsigned_type (mvr)))
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- N_("assignment discards qualifiers "
- "from pointer target type"),
- N_("initialization discards qualifiers "
- "from pointer target type"),
- N_("return discards qualifiers from "
- "pointer target type"));
+ {
+ /* Types differing only by the presence of the 'volatile'
+ qualifier are acceptable if the 'volatile' has been added
+ in by the Objective-C EH machinery. */
+ if (!objc_type_quals_match (ttl, ttr))
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ "qualifiers from pointer target type"),
+ N_("assignment discards qualifiers "
+ "from pointer target type"),
+ N_("initialization discards qualifiers "
+ "from pointer target type"),
+ N_("return discards qualifiers from "
+ "pointer target type"));
+ }
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
}
}
else
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE from "
- "incompatible pointer type"),
- N_("assignment from incompatible pointer type"),
- N_("initialization from incompatible "
- "pointer type"),
- N_("return from incompatible pointer type"));
+ /* Avoid warning about the volatile ObjC EH puts on decls. */
+ if (!objc_ok)
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE from "
+ "incompatible pointer type"),
+ N_("assignment from incompatible pointer type"),
+ N_("initialization from incompatible "
+ "pointer type"),
+ N_("return from incompatible pointer type"));
+
return convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
if (warn_traditional && !in_system_header
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
- warning ("traditional C rejects automatic aggregate initialization");
+ warning (0, "traditional C rejects automatic aggregate initialization");
DECL_INITIAL (decl) = value;
{
char *ofwhat;
- warning ("%s", _(msgid));
+ warning (0, "%s", _(msgid));
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat)
- warning ("(near initialization for %qs)", ofwhat);
+ warning (0, "(near initialization for %qs)", ofwhat);
}
\f
/* If TYPE is an array type and EXPR is a parenthesized string
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
- Discard the initializer so that we do not abort later. */
+ Discard the initializer so that we do not die later. */
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
constructor_type = NULL_TREE;
}
if (warn_traditional && !in_system_header && !constructor_designated
&& !(value.value && (integer_zerop (value.value)
|| real_zerop (value.value))))
- warning ("traditional C rejects initialization of unions");
+ warning (0, "traditional C rejects initialization of unions");
/* Accept a string constant to initialize a subarray. */
if (value.value != 0
return NULL_TREE;
}
+ if (C_DECL_UNJUMPABLE_VM (decl))
+ {
+ error ("jump into scope of identifier with variably modified type");
+ return NULL_TREE;
+ }
+
if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
{
/* No jump from outside this statement expression context, so
record that there is a jump from within this context. */
struct c_label_list *nlist;
nlist = XOBNEW (&parser_obstack, struct c_label_list);
- nlist->next = label_context_stack->labels_used;
+ nlist->next = label_context_stack_se->labels_used;
nlist->label = decl;
- label_context_stack->labels_used = nlist;
+ label_context_stack_se->labels_used = nlist;
+ }
+
+ if (!C_DECL_UNDEFINABLE_VM (decl))
+ {
+ /* No jump from outside this context context of identifiers with
+ variably modified type, so record that there is a jump from
+ within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack_vm->labels_used;
+ nlist->label = decl;
+ label_context_stack_vm->labels_used = nlist;
}
TREE_USED (decl) = 1;
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared %<noreturn%> has a %<return%> statement");
+ warning (0, "function declared %<noreturn%> has a %<return%> statement");
if (!retval)
{
&& !DECL_EXTERNAL (inner)
&& !TREE_STATIC (inner)
&& DECL_CONTEXT (inner) == current_function_decl)
- warning ("function returns address of local variable");
+ warning (0, "function returns address of local variable");
break;
default:
}
\f
struct c_switch {
- /* The SWITCH_STMT being built. */
- tree switch_stmt;
+ /* The SWITCH_EXPR being built. */
+ tree switch_expr;
/* The original type of the testing expression, i.e. before the
default conversion is applied. */
appear. */
unsigned int blocked_stmt_expr;
+ /* Scope of outermost declarations of identifiers with variably
+ modified type within this switch statement; if nonzero, case and
+ default labels may not appear. */
+ unsigned int blocked_vm;
+
/* The next node on the stack. */
struct c_switch *next;
};
struct c_switch *c_switch_stack;
/* Start a C switch statement, testing expression EXP. Return the new
- SWITCH_STMT. */
+ SWITCH_EXPR. */
tree
c_start_case (tree exp)
if (warn_traditional && !in_system_header
&& (type == long_integer_type_node
|| type == long_unsigned_type_node))
- warning ("%<long%> switch expression not converted to "
+ warning (0, "%<long%> switch expression not converted to "
"%<int%> in ISO C");
exp = default_conversion (exp);
}
}
- /* Add this new SWITCH_STMT to the stack. */
+ /* Add this new SWITCH_EXPR to the stack. */
cs = XNEW (struct c_switch);
- cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
+ cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
cs->blocked_stmt_expr = 0;
+ cs->blocked_vm = 0;
cs->next = c_switch_stack;
c_switch_stack = cs;
- return add_stmt (cs->switch_stmt);
+ return add_stmt (cs->switch_expr);
}
/* Process a case label. */
{
tree label = NULL_TREE;
- if (c_switch_stack && !c_switch_stack->blocked_stmt_expr)
+ if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
+ && !c_switch_stack->blocked_vm)
{
label = c_add_case_label (c_switch_stack->cases,
- SWITCH_STMT_COND (c_switch_stack->switch_stmt),
+ SWITCH_COND (c_switch_stack->switch_expr),
c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
error ("%<default%> label in statement expression not containing "
"enclosing switch statement");
}
+ else if (c_switch_stack && c_switch_stack->blocked_vm)
+ {
+ if (low_value)
+ error ("case label in scope of identifier with variably modified "
+ "type not containing enclosing switch statement");
+ else
+ error ("%<default%> label in scope of identifier with variably "
+ "modified type not containing enclosing switch statement");
+ }
else if (low_value)
error ("case label not within a switch statement");
else
c_finish_case (tree body)
{
struct c_switch *cs = c_switch_stack;
+ location_t switch_location;
- SWITCH_STMT_BODY (cs->switch_stmt) = body;
+ SWITCH_BODY (cs->switch_expr) = body;
+ /* We must not be within a statement expression nested in the switch
+ at this point; we might, however, be within the scope of an
+ identifier with variably modified type nested in the switch. */
gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
- c_do_switch_warnings (cs->cases, cs->switch_stmt);
+ if (EXPR_HAS_LOCATION (cs->switch_expr))
+ switch_location = EXPR_LOCATION (cs->switch_expr);
+ else
+ switch_location = input_location;
+ c_do_switch_warnings (cs->cases, switch_location,
+ TREE_TYPE (cs->switch_expr),
+ SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
c_switch_stack = cs->next;
found:
if (COND_EXPR_ELSE (inner_if))
- warning ("%Hsuggest explicit braces to avoid ambiguous %<else%>",
+ warning (0, "%Hsuggest explicit braces to avoid ambiguous %<else%>",
&if_locus);
}
if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
{
if (!else_block)
- warning ("%Hempty body in an if-statement",
+ warning (0, "%Hempty body in an if-statement",
EXPR_LOCUS (then_block));
then_block = alloc_stmt_list ();
}
&& TREE_CODE (else_block) == NOP_EXPR
&& !TREE_TYPE (else_block))
{
- warning ("%Hempty body in an else-statement",
+ warning (0, "%Hempty body in an else-statement",
EXPR_LOCUS (else_block));
else_block = alloc_stmt_list ();
}
else if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
- warning ("%Hstatement with no effect",
+ warning (0, "%Hstatement with no effect",
EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
}
else if (warn_unused_value)
c_begin_stmt_expr (void)
{
tree ret;
- struct c_label_context *nstack;
+ struct c_label_context_se *nstack;
struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
c_switch_stack->blocked_stmt_expr++;
gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
}
- for (glist = label_context_stack->labels_used;
+ for (glist = label_context_stack_se->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
}
- nstack = XOBNEW (&parser_obstack, struct c_label_context);
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack->labels_def = NULL;
nstack->labels_used = NULL;
- nstack->next = label_context_stack;
- label_context_stack = nstack;
+ nstack->next = label_context_stack_se;
+ label_context_stack_se = nstack;
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
}
/* It is no longer possible to jump to labels defined within this
statement expression. */
- for (dlist = label_context_stack->labels_def;
+ for (dlist = label_context_stack_se->labels_def;
dlist != NULL;
dlist = dlist->next)
{
}
/* It is again possible to define labels with a goto just outside
this statement expression. */
- for (glist = label_context_stack->next->labels_used;
+ for (glist = label_context_stack_se->next->labels_used;
glist != NULL;
glist = glist->next)
{
glist_prev = glist;
}
if (glist_prev != NULL)
- glist_prev->next = label_context_stack->labels_used;
+ glist_prev->next = label_context_stack_se->labels_used;
else
- label_context_stack->next->labels_used = label_context_stack->labels_used;
- label_context_stack = label_context_stack->next;
+ label_context_stack_se->next->labels_used
+ = label_context_stack_se->labels_used;
+ label_context_stack_se = label_context_stack_se->next;
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
+
+/* Begin the scope of an identifier of variably modified type, scope
+ number SCOPE. Jumping from outside this scope to inside it is not
+ permitted. */
+
+void
+c_begin_vm_scope (unsigned int scope)
+{
+ struct c_label_context_vm *nstack;
+ struct c_label_list *glist;
+
+ gcc_assert (scope > 0);
+ if (c_switch_stack && !c_switch_stack->blocked_vm)
+ c_switch_stack->blocked_vm = scope;
+ for (glist = label_context_stack_vm->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->scope = scope;
+ nstack->next = label_context_stack_vm;
+ label_context_stack_vm = nstack;
+}
+
+/* End a scope which may contain identifiers of variably modified
+ type, scope number SCOPE. */
+
+void
+c_end_vm_scope (unsigned int scope)
+{
+ if (label_context_stack_vm == NULL)
+ return;
+ if (c_switch_stack && c_switch_stack->blocked_vm == scope)
+ c_switch_stack->blocked_vm = 0;
+ /* We may have a number of nested scopes of identifiers with
+ variably modified type, all at this depth. Pop each in turn. */
+ while (label_context_stack_vm->scope == scope)
+ {
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
+
+ /* It is no longer possible to jump to labels defined within this
+ scope. */
+ for (dlist = label_context_stack_vm->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this scope. */
+ for (glist = label_context_stack_vm->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_vm->labels_used;
+ else
+ label_context_stack_vm->next->labels_used
+ = label_context_stack_vm->labels_used;
+ label_context_stack_vm = label_context_stack_vm->next;
+ }
+}
\f
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */
/* Nonzero means set RESULT_TYPE to the common type of the args. */
int common = 0;
+ /* True means types are compatible as far as ObjC is concerned. */
+ bool objc_ok;
+
if (convert_p)
{
op0 = default_conversion (orig_op0);
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
+ objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+
switch (code)
{
case PLUS_EXPR:
/* Subtraction of two similar pointers.
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
- && comp_target_types (type0, type1, 1))
+ && comp_target_types (type0, type1))
return pointer_diff (op0, op1);
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
/* Floating point division by zero is a legitimate way to obtain
infinities and NaNs. */
if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ warning (0, "division by zero");
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
- warning ("division by zero");
+ warning (0, "division by zero");
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("right shift count is negative");
+ warning (0, "right shift count is negative");
else
{
if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("right shift count >= width of type");
+ warning (0, "right shift count >= width of type");
}
}
if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
- warning ("left shift count is negative");
+ warning (0, "left shift count is negative");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("left shift count >= width of type");
+ warning (0, "left shift count >= width of type");
}
/* Use the type of the value to be shifted. */
case EQ_EXPR:
case NE_EXPR:
if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
- warning ("comparing floating point with == or != is unsafe");
+ warning (0, "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;
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
- if (comp_target_types (type0, type1, 1))
+ if (comp_target_types (type0, type1))
result_type = common_pointer_type (type0, type1);
else if (VOID_TYPE_P (tt0))
{
" with function pointer");
}
else
- pedwarn ("comparison of distinct pointer types lacks a cast");
+ /* Avoid warning about the volatile ObjC EH puts on decls. */
+ if (!objc_ok)
+ pedwarn ("comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
result_type = ptr_type_node;
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (comp_target_types (type0, type1, 1))
+ if (comp_target_types (type0, type1))
{
result_type = common_pointer_type (type0, type1);
if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
c_common_signed_type (result_type)))
/* OK */;
else
- warning ("comparison between signed and unsigned");
+ warning (0, "comparison between signed and unsigned");
}
/* Warn if two unsigned values are being compared in a size
{
mask = (~(HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
- warning ("comparison of promoted ~unsigned with constant");
+ warning (0, "comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
< TYPE_PRECISION (result_type)))
- warning ("comparison of promoted ~unsigned with unsigned");
+ warning (0, "comparison of promoted ~unsigned with unsigned");
}
}
}