int warn_format;
+/* Warn about using __null (as NULL in C++) as sentinel. For code compiled
+ with GCC this doesn't matter as __null is guaranteed to have the right
+ size. */
+
+int warn_strict_null_sentinel;
+
/* Zero means that faster, ...NonNil variants of objc_msgSend...
calls will be used in ObjC; passing nil receivers to such calls
will most likely result in crashes. */
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("integer overflow in expression");
+ warning (0, "integer overflow in expression");
}
else if ((TREE_CODE (value) == REAL_CST
|| (TREE_CODE (value) == COMPLEX_CST
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("floating point overflow in expression");
+ warning (0, "floating point overflow in expression");
}
else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
if (skip_evaluation == 0)
- warning ("vector overflow in expression");
+ warning (0, "vector overflow in expression");
}
}
{
if (!int_fits_type_p (operand, c_common_signed_type (type)))
/* This detects cases like converting -129 or 256 to unsigned char. */
- warning ("large integer implicitly truncated to unsigned type");
+ warning (0, "large integer implicitly truncated to unsigned type");
else if (warn_conversion)
- warning ("negative integer implicitly converted to unsigned type");
+ warning (0, "negative integer implicitly converted to unsigned type");
}
}
|| !constant_fits_type_p (expr,
c_common_unsigned_type (type)))
&& skip_evaluation == 0)
- warning ("overflow in implicit constant conversion");
+ warning (0, "overflow in implicit constant conversion");
}
else
unsigned_conversion_warning (t, expr);
&& DECL_NAME (list->expr))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
- warning ("operation on %qE may be undefined", list->expr);
+ warning (0, "operation on %qE may be undefined", list->expr);
}
list = list->next;
}
if (value == NULL_TREE)
return value;
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ /* ??? Can we ever get nops here for a valid case value? We
+ shouldn't for C. */
STRIP_TYPE_NOPS (value);
/* In C++, the following is allowed:
value = fold (value);
}
- if (TREE_CODE (value) != INTEGER_CST
- && value != error_mark_node)
+ if (TREE_CODE (value) == INTEGER_CST)
+ /* Promote char or short to int. */
+ value = perform_integral_promotions (value);
+ else if (value != error_mark_node)
{
error ("case label does not reduce to an integer constant");
value = error_mark_node;
}
- else
- /* Promote char or short to int. */
- value = default_conversion (value);
constant_expression_warning (value);
if (tree_int_cst_compare (case_low, min_value) < 0
&& tree_int_cst_compare (case_high, min_value) < 0)
{
- warning ("case label value is less than minimum value for type");
+ warning (0, "case label value is less than minimum value for type");
return false;
}
if (tree_int_cst_compare (case_low, max_value) > 0
&& tree_int_cst_compare (case_high, max_value) > 0)
{
- warning ("case label value exceeds maximum value for type");
+ warning (0, "case label value exceeds maximum value for type");
return false;
}
if (tree_int_cst_compare (case_high, min_value) >= 0
&& tree_int_cst_compare (case_low, min_value) < 0)
{
- warning ("lower value in case label range"
+ warning (0, "lower value in case label range"
" less than minimum value for type");
case_low = min_value;
}
if (tree_int_cst_compare (case_low, max_value) <= 0
&& tree_int_cst_compare (case_high, max_value) > 0)
{
- warning ("upper value in case label range"
+ warning (0, "upper value in case label range"
" exceeds maximum value for type");
case_high = max_value;
}
if (TREE_CODE (primop0) != INTEGER_CST)
{
if (val == truthvalue_false_node)
- warning ("comparison is always false due to limited range of data type");
+ warning (0, "comparison is always false due to limited range of data type");
if (val == truthvalue_true_node)
- warning ("comparison is always true due to limited range of data type");
+ warning (0, "comparison is always true due to limited range of data type");
}
if (val != 0)
&& !(TREE_CODE (primop0) == INTEGER_CST
&& !TREE_OVERFLOW (convert (c_common_signed_type (type),
primop0))))
- warning ("comparison of unsigned expression >= 0 is always true");
+ warning (0, "comparison of unsigned expression >= 0 is always true");
value = truthvalue_true_node;
break;
&& !(TREE_CODE (primop0) == INTEGER_CST
&& !TREE_OVERFLOW (convert (c_common_signed_type (type),
primop0))))
- warning ("comparison of unsigned expression < 0 is always false");
+ warning (0, "comparison of unsigned expression < 0 is always false");
value = truthvalue_false_node;
break;
}
\f
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
- or validate its data type for an `if' or `while' statement or ?..: exp.
+ or for an `if' or `while' statement or ?..: exp. It should already
+ have been validated to be of suitable type; otherwise, a bad
+ diagnostic may result.
This preparation consists of taking the ordinary
representation of an expression expr and producing a valid tree
tree
c_common_truthvalue_conversion (tree expr)
{
- if (TREE_CODE (expr) == ERROR_MARK)
- return expr;
-
- if (TREE_CODE (expr) == FUNCTION_DECL)
- expr = build_unary_op (ADDR_EXPR, expr, 0);
-
switch (TREE_CODE (expr))
{
case EQ_EXPR: case NE_EXPR: case UNEQ_EXPR: case LTGT_EXPR:
case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
case ORDERED_EXPR: case UNORDERED_EXPR:
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
- if (TREE_TYPE (expr) != truthvalue_type_node)
- return build2 (TREE_CODE (expr), truthvalue_type_node,
- TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
- return expr;
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build2 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)));
case TRUTH_NOT_EXPR:
- if (TREE_TYPE (expr) != truthvalue_type_node)
- return build1 (TREE_CODE (expr), truthvalue_type_node,
- TREE_OPERAND (expr, 0));
- return expr;
+ if (TREE_TYPE (expr) == truthvalue_type_node)
+ return expr;
+ return build1 (TREE_CODE (expr), truthvalue_type_node,
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
case ERROR_MARK:
return expr;
? truthvalue_true_node
: truthvalue_false_node;
+ case FUNCTION_DECL:
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ /* Fall through. */
+
case ADDR_EXPR:
{
if (TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL
{
/* Common Ada/Pascal programmer's mistake. We always warn
about this since it is so bad. */
- warning ("the address of %qD, will always evaluate as %<true%>",
+ warning (0, "the address of %qD, will always evaluate as %<true%>",
TREE_OPERAND (expr, 0));
return truthvalue_true_node;
}
case COMPLEX_EXPR:
return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
0);
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
/* These don't change whether an object is nonzero or zero. */
- return lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
case LROTATE_EXPR:
case RROTATE_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
return build2 (COMPOUND_EXPR, truthvalue_type_node,
TREE_OPERAND (expr, 1),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
- return lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
return fold (build3 (COND_EXPR, truthvalue_type_node,
TREE_OPERAND (expr, 0),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 1)),
- lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 2))));
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))));
case CONVERT_EXPR:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
/* If this is widening the argument, we can ignore it. */
if (TYPE_PRECISION (TREE_TYPE (expr))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
- return lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0));
+ return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
break;
case MINUS_EXPR:
case MODIFY_EXPR:
if (warn_parentheses && !TREE_NO_WARNING (expr))
- warning ("suggest parentheses around assignment used as truth value");
+ warning (0, "suggest parentheses around assignment used as truth value");
break;
default:
return (build_binary_op
((TREE_SIDE_EFFECTS (expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- lang_hooks.truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
- lang_hooks.truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
+ c_common_truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
0));
}
second parameter indicates which OPERATOR is being applied. The COMPLAIN
flag controls whether we should diagnose possibly ill-formed
constructs or not. */
+
tree
-c_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
+c_sizeof_or_alignof_type (tree type, bool is_sizeof, int complain)
{
const char *op_name;
tree value = NULL;
enum tree_code type_code = TREE_CODE (type);
- gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR);
- op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__";
+ op_name = is_sizeof ? "sizeof" : "__alignof__";
if (type_code == FUNCTION_TYPE)
{
- if (op == SIZEOF_EXPR)
+ if (is_sizeof)
{
if (complain && (pedantic || warn_pointer_arith))
pedwarn ("invalid application of %<sizeof%> to a function type");
}
else
{
- if (op == (enum tree_code) SIZEOF_EXPR)
+ if (is_sizeof)
/* Convert in case a char is more than one unit. */
value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
size_int (TYPE_PRECISION (char_type_node)
{ \
tree decl; \
\
- gcc_assert (!strncmp (NAME, "__builtin_", \
- strlen ("__builtin_"))); \
+ gcc_assert ((!BOTH_P && !FALLBACK_P) \
+ || !strncmp (NAME, "__builtin_", \
+ strlen ("__builtin_"))); \
\
if (!BOTH_P) \
decl = lang_hooks.builtin_function (NAME, builtin_types[TYPE], \
mudflap_init ();
main_identifier_node = get_identifier ("main");
+
+ /* Create the built-in __null node. It is important that this is
+ not shared. */
+ null_node = make_node (INTEGER_CST);
+ TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
}
/* Look up the function in built_in_decls that corresponds to DECL
&& POINTER_TYPE_P (TREE_TYPE (low_value)))
|| (high_value && TREE_TYPE (high_value)
&& POINTER_TYPE_P (TREE_TYPE (high_value))))
- error ("pointers are not permitted as case values");
+ {
+ error ("pointers are not permitted as case values");
+ goto error_out;
+ }
/* Case ranges are a GNU extension. */
if (high_value && pedantic)
high_value = NULL_TREE;
if (low_value && high_value
&& !tree_int_cst_lt (low_value, high_value))
- warning ("empty range specified");
+ warning (0, "empty range specified");
/* See if the case is in range of the type of the original testing
expression. If both low_value and high_value are out of range,
error_out:
/* Add a label so that the back-end doesn't think that the beginning of
the switch is unreachable. Note that we do not add a case label, as
- that just leads to duplicates and thence to aborts later on. */
+ that just leads to duplicates and thence to failure later on. */
if (!cases->root)
{
tree t = create_artificial_label ();
TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key));
if (TYPE_NAME (type) == 0)
- warning ("%Jcase value %qs not in enumerated type",
+ warning (0, "%Jcase value %qs not in enumerated type",
CASE_LABEL (label), buf);
else
- warning ("%Jcase value %qs not in enumerated type %qT",
+ warning (0, "%Jcase value %qs not in enumerated type %qT",
CASE_LABEL (label), buf, type);
}
return 0;
}
-/* Handle -Wswitch*. Called from the front end after parsing the switch
- construct. */
-/* ??? Should probably be somewhere generic, since other languages besides
- C and C++ would want this. We'd want to agree on the data structure,
- however, which is a problem. Alternately, we operate on gimplified
- switch_exprs, which I don't especially like. At the moment, however,
- C/C++ are the only tree-ssa languages that support enumerations at all,
+/* Handle -Wswitch*. Called from the front end after parsing the
+ switch construct. */
+/* ??? Should probably be somewhere generic, since other languages
+ besides C and C++ would want this. At the moment, however, C/C++
+ are the only tree-ssa languages that support enumerations at all,
so the point is moot. */
void
-c_do_switch_warnings (splay_tree cases, tree switch_stmt)
+c_do_switch_warnings (splay_tree cases, location_t switch_location,
+ tree type, tree cond)
{
splay_tree_node default_node;
- location_t switch_location;
- tree type;
if (!warn_switch && !warn_switch_enum && !warn_switch_default)
return;
- if (EXPR_HAS_LOCATION (switch_stmt))
- switch_location = EXPR_LOCATION (switch_stmt);
- else
- switch_location = input_location;
-
- type = SWITCH_STMT_TYPE (switch_stmt);
-
default_node = splay_tree_lookup (cases, (splay_tree_key) NULL);
if (warn_switch_default && !default_node)
- warning ("%Hswitch missing default case", &switch_location);
+ warning (0, "%Hswitch missing default case", &switch_location);
/* If the switch expression was an enumerated type, check that
exactly all enumeration literals are covered by the cases.
default case, or when -Wswitch-enum was specified. */
if (((warn_switch && !default_node) || warn_switch_enum)
&& type && TREE_CODE (type) == ENUMERAL_TYPE
- && TREE_CODE (SWITCH_STMT_COND (switch_stmt)) != INTEGER_CST)
+ && TREE_CODE (cond) != INTEGER_CST)
{
tree chain;
{
/* Warn if there are enumerators that don't correspond to
case expressions. */
- warning ("%Henumeration value %qE not handled in switch",
+ warning (0, "%Henumeration value %qE not handled in switch",
&switch_location, TREE_PURPOSE (chain));
}
}
that changes what the typedef is typing. */
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
DECL_COMMON (*node) = 0;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
DECL_COMMON (*node) = 1;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
TYPE_READONLY (TREE_TYPE (type)), 1));
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
DECL_UNINLINABLE (*node) = 1;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
TREE_USED (decl) = 1;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
TREE_THIS_VOLATILE (TREE_TYPE (type))));
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
DECL_TRANSPARENT_UNION (decl) = 1;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
}
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
*no_add_attrs = true;
if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
else
{
int j;
case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT:
- warning ("specifying vector types with __attribute__ ((mode)) "
+ warning (0, "specifying vector types with __attribute__ ((mode)) "
"is deprecated");
- warning ("use __attribute__ ((vector_size)) instead");
+ warning (0, "use __attribute__ ((vector_size)) instead");
valid_mode = vector_mode_valid_p (mode);
break;
else if (TYPE_P (*node))
type = node, is_type = 1;
- /* Strip any NOPs of any kind. */
- while (TREE_CODE (align_expr) == NOP_EXPR
- || TREE_CODE (align_expr) == CONVERT_EXPR
- || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
- align_expr = TREE_OPERAND (align_expr, 0);
-
if (TREE_CODE (align_expr) != INTEGER_CST)
{
error ("requested alignment is not a constant");
}
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
{
if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
{
- warning ("%qE attribute ignored on non-class types", name);
+ warning (0, "%qE attribute ignored on non-class types", name);
return NULL_TREE;
}
}
else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
return NULL_TREE;
}
return NULL_TREE;
if (TREE_CODE (decl) == IDENTIFIER_NODE)
{
- warning ("%qE attribute ignored on types",
+ warning (0, "%qE attribute ignored on types",
name);
return NULL_TREE;
}
if (!DECL_THREAD_LOCAL (decl))
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
else
handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
int ARG_UNUSED (flags), bool *no_add_attrs)
{
- if (TREE_CODE (*node) == FUNCTION_DECL)
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
DECL_IS_MALLOC (*node) = 1;
- /* ??? TODO: Support types. */
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
DECL_IS_RETURNS_TWICE (*node) = 1;
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
/* ??? TODO: Support types. */
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
what = DECL_NAME (TYPE_NAME (type));
}
if (what)
- warning ("%qE attribute ignored for %qE", name, what);
+ warning (0, "%qE attribute ignored for %qE", name, what);
else
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
}
return NULL_TREE;
*no_add_attrs = true;
- /* Stripping NON_LVALUE_EXPR allows declarations such as
- typedef short v4si __attribute__((vector_size (4 * sizeof(short)))). */
size = TREE_VALUE (args);
- if (TREE_CODE (size) == NON_LVALUE_EXPR)
- size = TREE_OPERAND (size, 0);
if (!host_integerp (size, 1))
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
return NULL_TREE;
}
if (attr)
{
if (!params)
- warning ("missing sentinel in function call");
+ warning (0, "missing sentinel in function call");
else
{
tree sentinel, end;
if (TREE_VALUE (attr))
{
tree p = TREE_VALUE (TREE_VALUE (attr));
- STRIP_NOPS (p);
pos = TREE_INT_CST_LOW (p);
}
}
if (pos > 0)
{
- warning ("not enough arguments to fit a sentinel");
+ warning (0, "not enough arguments to fit a sentinel");
return;
}
}
/* Validate the sentinel. */
- if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
- || !integer_zerop (TREE_VALUE (sentinel)))
- warning ("missing sentinel in function call");
+ if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
+ || !integer_zerop (TREE_VALUE (sentinel)))
+ /* Although __null (in C++) is only an integer we allow it
+ nevertheless, as we are guaranteed that it's exactly
+ as wide as a pointer, and we don't want to force
+ users to cast the NULL they have written there.
+ We warn with -Wstrict-null-sentinel, though. */
+ && (warn_strict_null_sentinel
+ || null_node != TREE_VALUE (sentinel)))
+ warning (0, "missing sentinel in function call");
}
}
}
return;
if (integer_zerop (param))
- warning ("null argument where non-null required (argument %lu)",
+ warning (0, "null argument where non-null required (argument %lu)",
(unsigned long) param_num);
}
static bool
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
- /* Strip any conversions from the arg number and verify they
- are constants. */
- while (TREE_CODE (arg_num_expr) == NOP_EXPR
- || TREE_CODE (arg_num_expr) == CONVERT_EXPR
- || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR)
- arg_num_expr = TREE_OPERAND (arg_num_expr, 0);
-
+ /* Verify the arg number is a constant. */
if (TREE_CODE (arg_num_expr) != INTEGER_CST
|| TREE_INT_CST_HIGH (arg_num_expr) != 0)
return false;
/* ??? TODO: Support types. */
else
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
we'd be missing too much, since we do have attribute constructor. */
if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
return NULL_TREE;
}
/* Ignore the attribute for functions not returning any value. */
if (VOID_TYPE_P (TREE_TYPE (*node)))
{
- warning ("%qE attribute ignored", name);
+ warning (0, "%qE attribute ignored", name);
*no_add_attrs = true;
}
if (!params)
{
- warning ("%qE attribute requires prototypes with named arguments", name);
+ warning (0, "%qE attribute requires prototypes with named arguments", name);
*no_add_attrs = true;
}
else
if (VOID_TYPE_P (TREE_VALUE (params)))
{
- warning ("%qE attribute only applies to variadic functions", name);
+ warning (0, "%qE attribute only applies to variadic functions", name);
*no_add_attrs = true;
}
}
{
tree position = TREE_VALUE (args);
- STRIP_NOPS (position);
if (TREE_CODE (position) != INTEGER_CST)
{
- warning ("requested position is not an integer constant");
+ warning (0, "requested position is not an integer constant");
*no_add_attrs = true;
}
else
{
if (tree_int_cst_lt (position, integer_zero_node))
{
- warning ("requested position is less than zero");
+ warning (0, "requested position is less than zero");
*no_add_attrs = true;
}
}
/* Extract the argument number, which was previously checked
to be valid. */
format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
- while (TREE_CODE (format_num_expr) == NOP_EXPR
- || TREE_CODE (format_num_expr) == CONVERT_EXPR
- || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
- format_num_expr = TREE_OPERAND (format_num_expr, 0);
gcc_assert (TREE_CODE (format_num_expr) == INTEGER_CST
&& !TREE_INT_CST_HIGH (format_num_expr));
if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
{
if (fdecl)
- warning ("%Hignoring return value of %qD, "
+ warning (0, "%Hignoring return value of %qD, "
"declared with attribute warn_unused_result",
EXPR_LOCUS (t), fdecl);
else
- warning ("%Hignoring return value of function "
+ warning (0, "%Hignoring return value of function "
"declared with attribute warn_unused_result",
EXPR_LOCUS (t));
}
return convert (size_type_node, fold_offsetof_1 (expr));
}
-/* Return nonzero if REF is an lvalue valid for this language;
- otherwise, print an error message and return zero. USE says
+/* Print an error message for an invalid lvalue. USE says
how the lvalue is being used and so selects the error message. */
+void
+lvalue_error (enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ error ("invalid lvalue in assignment");
+ break;
+ case lv_increment:
+ error ("invalid lvalue in increment");
+ break;
+ case lv_decrement:
+ error ("invalid lvalue in decrement");
+ break;
+ case lv_addressof:
+ error ("invalid lvalue in unary %<&%>");
+ break;
+ case lv_asm:
+ error ("invalid lvalue in asm statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+\f
+/* *PTYPE is an incomplete array. Complete it with a domain based on
+ INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT
+ is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
+ 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */
+
int
-lvalue_or_else (tree ref, enum lvalue_use use)
+complete_array_type (tree *ptype, tree initial_value, bool do_default)
{
- int win = lvalue_p (ref);
+ tree maxindex, type, main_type, elt, unqual_elt;
+ int failure = 0, quals;
- if (!win)
+ maxindex = size_zero_node;
+ if (initial_value)
{
- switch (use)
+ if (TREE_CODE (initial_value) == STRING_CST)
{
- case lv_assign:
- error ("invalid lvalue in assignment");
- break;
- case lv_increment:
- error ("invalid lvalue in increment");
- break;
- case lv_decrement:
- error ("invalid lvalue in decrement");
- break;
- case lv_addressof:
- error ("invalid lvalue in unary %<&%>");
- break;
- case lv_asm:
- error ("invalid lvalue in asm statement");
- break;
- default:
- gcc_unreachable ();
+ int eltsize
+ = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+ maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
+ }
+ else if (TREE_CODE (initial_value) == CONSTRUCTOR)
+ {
+ tree elts = CONSTRUCTOR_ELTS (initial_value);
+
+ if (elts == NULL)
+ {
+ if (pedantic)
+ failure = 3;
+ maxindex = integer_minus_one_node;
+ }
+ else
+ {
+ tree curindex;
+
+ if (TREE_PURPOSE (elts))
+ maxindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ curindex = maxindex;
+
+ for (elts = TREE_CHAIN (elts); elts; elts = TREE_CHAIN (elts))
+ {
+ if (TREE_PURPOSE (elts))
+ curindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ else
+ curindex = size_binop (PLUS_EXPR, curindex, size_one_node);
+
+ if (tree_int_cst_lt (maxindex, curindex))
+ maxindex = curindex;
+ }
+ }
+ }
+ else
+ {
+ /* Make an error message unless that happened already. */
+ if (initial_value != error_mark_node)
+ failure = 1;
}
}
+ else
+ {
+ failure = 2;
+ if (!do_default)
+ return failure;
+ }
+
+ type = *ptype;
+ elt = TREE_TYPE (type);
+ quals = TYPE_QUALS (strip_array_types (elt));
+ if (quals == 0)
+ unqual_elt = elt;
+ else
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+
+ /* Using build_distinct_type_copy and modifying things afterward instead
+ of using build_array_type to create a new type preserves all of the
+ TYPE_LANG_FLAG_? bits that the front end may have set. */
+ main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TREE_TYPE (main_type) = unqual_elt;
+ TYPE_DOMAIN (main_type) = build_index_type (maxindex);
+ layout_type (main_type);
+
+ if (quals == 0)
+ type = main_type;
+ else
+ type = c_build_qualified_type (main_type, quals);
+
+ *ptype = type;
+ return failure;
+}
- return win;
+\f
+/* Used to help initialize the builtin-types.def table. When a type of
+ the correct size doesn't exist, use error_mark_node instead of NULL.
+ The later results in segfaults even when a decl using the type doesn't
+ get invoked. */
+
+tree
+builtin_type_for_size (int size, bool unsignedp)
+{
+ tree type = lang_hooks.types.type_for_size (size, unsignedp);
+ return type ? type : error_mark_node;
+}
+
+/* A helper function for resolve_overloaded_builtin in resolving the
+ overloaded __sync_ builtins. Returns a positive power of 2 if the
+ first operand of PARAMS is a pointer to a supported data type.
+ Returns 0 if an error is encountered. */
+
+static int
+sync_resolve_size (tree function, tree params)
+{
+ tree type;
+ int size;
+
+ if (params == NULL)
+ {
+ error ("too few arguments to function %qE", function);
+ return 0;
+ }
+
+ type = TREE_TYPE (TREE_VALUE (params));
+ if (TREE_CODE (type) != POINTER_TYPE)
+ goto incompatible;
+
+ type = TREE_TYPE (type);
+ if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
+ goto incompatible;
+
+ size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+ if (size == 1 || size == 2 || size == 4 || size == 8)
+ return size;
+
+ incompatible:
+ error ("incompatible type for argument %d of %qE", 1, function);
+ return 0;
+}
+
+/* A helper function for resolve_overloaded_builtin. Adds casts to
+ PARAMS to make arguments match up with those of FUNCTION. Drops
+ the variadic arguments at the end. Returns false if some error
+ was encountered; true on success. */
+
+static bool
+sync_resolve_params (tree orig_function, tree function, tree params)
+{
+ tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
+ tree ptype;
+ int number;
+
+ /* We've declared the implementation functions to use "volatile void *"
+ as the pointer parameter, so we shouldn't get any complaints from the
+ call to check_function_arguments what ever type the user used. */
+ arg_types = TREE_CHAIN (arg_types);
+ ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ number = 2;
+
+ /* For the rest of the values, we need to cast these to FTYPE, so that we
+ don't get warnings for passing pointer types, etc. */
+ while (arg_types != void_list_node)
+ {
+ tree val;
+
+ params = TREE_CHAIN (params);
+ if (params == NULL)
+ {
+ error ("too few arguments to function %qE", orig_function);
+ return false;
+ }
+
+ /* ??? Ideally for the first conversion we'd use convert_for_assignment
+ so that we get warnings for anything that doesn't match the pointer
+ type. This isn't portable across the C and C++ front ends atm. */
+ val = TREE_VALUE (params);
+ val = convert (ptype, val);
+ val = convert (TREE_VALUE (arg_types), val);
+ TREE_VALUE (params) = val;
+
+ arg_types = TREE_CHAIN (arg_types);
+ number++;
+ }
+
+ /* The definition of these primitives is variadic, with the remaining
+ being "an optional list of variables protected by the memory barrier".
+ No clue what that's supposed to mean, precisely, but we consider all
+ call-clobbered variables to be protected so we're safe. */
+ TREE_CHAIN (params) = NULL;
+
+ return true;
+}
+
+/* A helper function for resolve_overloaded_builtin. Adds a cast to
+ RESULT to make it match the type of the first pointer argument in
+ PARAMS. */
+
+static tree
+sync_resolve_return (tree params, tree result)
+{
+ tree ptype = TREE_TYPE (TREE_TYPE (TREE_VALUE (params)));
+ return convert (ptype, result);
+}
+
+/* Some builtin functions are placeholders for other expressions. This
+ function should be called immediately after parsing the call expression
+ before surrounding code has committed to the type of the expression.
+
+ FUNCTION is the DECL that has been invoked; it is known to be a builtin.
+ PARAMS is the argument list for the call. The return value is non-null
+ when expansion is complete, and null if normal processing should
+ continue. */
+
+tree
+resolve_overloaded_builtin (tree function, tree params)
+{
+ enum built_in_function orig_code = DECL_FUNCTION_CODE (function);
+ switch (DECL_BUILT_IN_CLASS (function))
+ {
+ case BUILT_IN_NORMAL:
+ break;
+ case BUILT_IN_MD:
+ if (targetm.resolve_overloaded_builtin)
+ return targetm.resolve_overloaded_builtin (function, params);
+ else
+ return NULL_TREE;
+ default:
+ return NULL_TREE;
+ }
+
+ /* Handle BUILT_IN_NORMAL here. */
+ switch (orig_code)
+ {
+ case BUILT_IN_FETCH_AND_ADD_N:
+ case BUILT_IN_FETCH_AND_SUB_N:
+ case BUILT_IN_FETCH_AND_OR_N:
+ case BUILT_IN_FETCH_AND_AND_N:
+ case BUILT_IN_FETCH_AND_XOR_N:
+ case BUILT_IN_FETCH_AND_NAND_N:
+ case BUILT_IN_ADD_AND_FETCH_N:
+ case BUILT_IN_SUB_AND_FETCH_N:
+ case BUILT_IN_OR_AND_FETCH_N:
+ case BUILT_IN_AND_AND_FETCH_N:
+ case BUILT_IN_XOR_AND_FETCH_N:
+ case BUILT_IN_NAND_AND_FETCH_N:
+ case BUILT_IN_BOOL_COMPARE_AND_SWAP_N:
+ case BUILT_IN_VAL_COMPARE_AND_SWAP_N:
+ case BUILT_IN_LOCK_TEST_AND_SET_N:
+ case BUILT_IN_LOCK_RELEASE_N:
+ {
+ int n = sync_resolve_size (function, params);
+ tree new_function, result;
+
+ if (n == 0)
+ return error_mark_node;
+
+ new_function = built_in_decls[orig_code + exact_log2 (n) + 1];
+ if (!sync_resolve_params (function, new_function, params))
+ return error_mark_node;
+
+ result = build_function_call (new_function, params);
+ if (orig_code != BUILT_IN_BOOL_COMPARE_AND_SWAP_N
+ && orig_code != BUILT_IN_LOCK_RELEASE_N)
+ result = sync_resolve_return (params, result);
+
+ return result;
+ }
+
+ default:
+ return NULL_TREE;
+ }
}
#include "gt-c-common.h"