summaryrefslogtreecommitdiff
path: root/gcc/c-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r--gcc/c-common.c619
1 files changed, 441 insertions, 178 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 15d7e686841..9b7206a94c7 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -42,6 +42,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-inline.h"
#include "c-tree.h"
#include "toplev.h"
+#include "tree-iterator.h"
+#include "hashtab.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -681,6 +683,15 @@ tree *ridpointers;
tree (*make_fname_decl) (tree, int);
+/* If non-NULL, the address of a language-specific function that
+ returns 1 for language-specific statement codes. */
+int (*lang_statement_code_p) (enum tree_code);
+
+/* If non-NULL, the address of a language-specific function that does any
+ language-specific gimplification for _STMT nodes and returns 1 iff
+ handled. */
+int (*lang_gimplify_stmt) (tree *, tree *);
+
/* If non-NULL, the address of a language-specific function that takes
any action required right before expand_function_end is called. */
void (*lang_expand_function_end) (void);
@@ -918,7 +929,7 @@ c_expand_end_cond (void)
if_stack_pointer--;
if (if_stack[if_stack_pointer].needs_warning)
warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
- &if_stack[if_stack_pointer].locus);
+ &if_stack[if_stack_pointer].locus);
last_expr_type = NULL_TREE;
}
@@ -1183,6 +1194,7 @@ fix_string_type (tree value)
build_index_type (build_int_2 (nchars - 1, 0)));
TREE_CONSTANT (value) = 1;
+ TREE_INVARIANT (value) = 1;
TREE_READONLY (value) = 1;
TREE_STATIC (value) = 1;
return value;
@@ -1315,7 +1327,7 @@ convert_and_check (tree type, tree expr)
|| TYPE_UNSIGNED (type)
|| ! constant_fits_type_p (expr,
c_common_unsigned_type (type)))
- && skip_evaluation == 0)
+ && skip_evaluation == 0)
warning ("overflow in implicit constant conversion");
}
else
@@ -1851,7 +1863,7 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (widest_integer_literal_type_node))
return unsignedp ? widest_unsigned_literal_type_node
- : widest_integer_literal_type_node;
+ : widest_integer_literal_type_node;
if (mode == QImode)
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
@@ -2473,9 +2485,6 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
{
tree size_exp;
- tree result;
- tree folded;
-
/* The result is a pointer of the same type that is being added. */
tree result_type = TREE_TYPE (ptrop);
@@ -2549,13 +2558,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
-
- result = build (resultcode, result_type, ptrop, intop);
-
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
- return folded;
+ return fold (build (resultcode, result_type, ptrop, intop));
}
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
@@ -2796,6 +2799,49 @@ c_apply_type_quals_to_decl (int type_quals, tree decl)
}
}
+/* Hash function for the problem of multiple type definitions in
+ different files. This must hash all types that will compare
+ equal via comptypes to the same value. In practice it hashes
+ on some of the simple stuff and leaves the details to comptypes. */
+
+static hashval_t
+c_type_hash (const void *p)
+{
+ int i = 0;
+ int shift, size;
+ tree t = (tree)p;
+ tree t2;
+ switch (TREE_CODE (t))
+ {
+ /* For pointers, hash on pointee type plus some swizzling. */
+ case POINTER_TYPE:
+ return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
+ /* Hash on number of elements and total size. */
+ case ENUMERAL_TYPE:
+ shift = 3;
+ t2 = TYPE_VALUES (t);
+ break;
+ case RECORD_TYPE:
+ shift = 0;
+ t2 = TYPE_FIELDS (t);
+ break;
+ case QUAL_UNION_TYPE:
+ shift = 1;
+ t2 = TYPE_FIELDS (t);
+ break;
+ case UNION_TYPE:
+ shift = 2;
+ t2 = TYPE_FIELDS (t);
+ break;
+ default:
+ abort ();
+ }
+ for (; t2; t2 = TREE_CHAIN (t2))
+ i++;
+ size = TREE_INT_CST_LOW (TYPE_SIZE (t));
+ return ((size << 24) | (i << shift));
+}
+
/* Return the typed-based alias set for T, which may be an expression
or a type. Return -1 if we don't do anything special. */
@@ -2803,6 +2849,8 @@ HOST_WIDE_INT
c_common_get_alias_set (tree t)
{
tree u;
+ PTR *slot;
+ static htab_t type_hash_table;
/* Permit type-punning when accessing a union, provided the access
is directly through the union. For example, this code does not
@@ -2859,14 +2907,14 @@ c_common_get_alias_set (tree t)
technically, an `int **' and `const int **' cannot point at
the same thing.
- But, the standard is wrong. In particular, this code is
+ But, the standard is wrong. In particular, this code is
legal C++:
int *ip;
int **ipp = &ip;
const int* const* cipp = ipp;
- And, it doesn't make sense for that to be legal unless you
+ And, it doesn't make sense for that to be legal unless you
can dereference IPP and CIPP. So, we ignore cv-qualifiers on
the pointed-to types. This issue has been reported to the
C++ committee. */
@@ -2875,6 +2923,63 @@ c_common_get_alias_set (tree t)
return get_alias_set (t1);
}
+ /* Handle the case of multiple type nodes referring to "the same" type,
+ which occurs with IMA. These share an alias set. FIXME: Currently only
+ C90 is handled. (In C99 type compatibility is not transitive, which
+ complicates things mightily. The alias set splay trees can theoretically
+ represent this, but insertion is tricky when you consider all the
+ different orders things might arrive in.) */
+
+ if (c_language != clk_c || flag_isoc99)
+ return -1;
+
+ /* Save time if there's only one input file. */
+ if (!current_file_decl || TREE_CHAIN (current_file_decl) == NULL_TREE)
+ return -1;
+
+ /* Pointers need special handling if they point to any type that
+ needs special handling (below). */
+ if (TREE_CODE (t) == POINTER_TYPE)
+ {
+ tree t2;
+ /* Find bottom type under any nested POINTERs. */
+ for (t2 = TREE_TYPE (t);
+ TREE_CODE (t2) == POINTER_TYPE;
+ t2 = TREE_TYPE (t2))
+ ;
+ if (TREE_CODE (t2) != RECORD_TYPE
+ && TREE_CODE (t2) != ENUMERAL_TYPE
+ && TREE_CODE (t2) != QUAL_UNION_TYPE
+ && TREE_CODE (t2) != UNION_TYPE)
+ return -1;
+ if (TYPE_SIZE (t2) == 0)
+ return -1;
+ }
+ /* These are the only cases that need special handling. */
+ if (TREE_CODE (t) != RECORD_TYPE
+ && TREE_CODE (t) != ENUMERAL_TYPE
+ && TREE_CODE (t) != QUAL_UNION_TYPE
+ && TREE_CODE (t) != UNION_TYPE
+ && TREE_CODE (t) != POINTER_TYPE)
+ return -1;
+ /* Undefined? */
+ if (TYPE_SIZE (t) == 0)
+ return -1;
+
+ /* Look up t in hash table. Only one of the compatible types within each
+ alias set is recorded in the table. */
+ if (!type_hash_table)
+ type_hash_table = htab_create (1021, c_type_hash,
+ (htab_eq) lang_hooks.types_compatible_p,
+ NULL);
+ slot = htab_find_slot (type_hash_table, t, INSERT);
+ if (*slot != NULL)
+ return TYPE_ALIAS_SET ((tree)*slot);
+ else
+ /* Our caller will assign and record (in t) a new alias set; all we need
+ to do is remember t in the hash table. */
+ *slot = t;
+
return -1;
}
@@ -3413,7 +3518,7 @@ c_common_nodes_and_builtins (void)
\
built_in_decls[(int) ENUM] = decl; \
if (IMPLICIT) \
- implicit_built_in_decls[(int) ENUM] = decl; \
+ implicit_built_in_decls[(int) ENUM] = decl; \
}
#include "builtins.def"
#undef DEF_BUILTIN
@@ -3843,19 +3948,12 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
splay_tree_node node;
/* Create the LABEL_DECL itself. */
- label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- DECL_CONTEXT (label) = current_function_decl;
+ label = create_artificial_label ();
/* If there was an error processing the switch condition, bail now
before we get more confused. */
if (!cond || cond == error_mark_node)
- {
- /* Add a label anyhow so that the back-end doesn't think that
- the beginning of the switch is unreachable. */
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
- return error_mark_node;
- }
+ goto error_out;
if ((low_value && TREE_TYPE (low_value)
&& POINTER_TYPE_P (TREE_TYPE (low_value)))
@@ -3881,11 +3979,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
/* If an error has occurred, bail out now. */
if (low_value == error_mark_node || high_value == error_mark_node)
- {
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
- return error_mark_node;
- }
+ goto error_out;
/* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
really a case range, even though it was written that way. Remove
@@ -3958,8 +4052,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
error ("multiple default labels in one switch");
error ("%Jthis is the first default label", duplicate);
}
- if (!cases->root)
- add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+ goto error_out;
}
/* Add a CASE_LABEL to the statement-tree. */
@@ -3970,6 +4063,160 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
(splay_tree_value) case_label);
return case_label;
+
+ error_out:
+ /* Add a label so that the back-end doesn't think that the beginning o
+ 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. */
+ if (!cases->root)
+ {
+ tree t = create_artificial_label ();
+ add_stmt (build_stmt (LABEL_STMT, t));
+ }
+ return error_mark_node;
+}
+
+/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach.
+ Used to verify that case values match up with enumerator values. */
+
+static void
+match_case_to_enum_1 (tree key, tree type, tree label)
+{
+ char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1];
+
+ /* ??? Not working too hard to print the double-word value.
+ Should perhaps be done with %lwd in the diagnostic routines? */
+ if (TREE_INT_CST_HIGH (key) == 0)
+ snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED,
+ TREE_INT_CST_LOW (key));
+ else if (!TYPE_UNSIGNED (type)
+ && TREE_INT_CST_HIGH (key) == -1
+ && TREE_INT_CST_LOW (key) != 0)
+ snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED,
+ -TREE_INT_CST_LOW (key));
+ else
+ snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+ TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key));
+
+ if (TYPE_NAME (type) == 0)
+ warning ("%Jcase value `%s' not in enumerated type",
+ CASE_LABEL_DECL (label), buf);
+ else
+ warning ("%Jcase value `%s' not in enumerated type `%T'",
+ CASE_LABEL_DECL (label), buf, type);
+}
+
+static int
+match_case_to_enum (splay_tree_node node, void *data)
+{
+ tree label = (tree) node->value;
+ tree type = data;
+
+ /* Skip default case. */
+ if (!CASE_LOW (label))
+ return 0;
+
+ /* If TREE_ADDRESSABLE is not set, that means CASE_LOW did not appear
+ when we did our enum->case scan. Reset our scratch bit after. */
+ if (!TREE_ADDRESSABLE (label))
+ match_case_to_enum_1 (CASE_LOW (label), type, label);
+ else
+ TREE_ADDRESSABLE (label) = 0;
+
+ /* If CASE_HIGH is non-null, we have a range. Here we must search.
+ Note that the old code in stmt.c did not check for the values in
+ the range either, just the endpoints. */
+ if (CASE_HIGH (label))
+ {
+ tree chain, key = CASE_HIGH (label);
+
+ for (chain = TYPE_VALUES (type);
+ chain && !tree_int_cst_equal (key, TREE_VALUE (chain));
+ chain = TREE_CHAIN (chain))
+ continue;
+ if (!chain)
+ match_case_to_enum_1 (key, type, label);
+ }
+
+ 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 datastructure,
+ 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,
+ so the point is moot. */
+
+void
+c_do_switch_warnings (splay_tree cases, tree switch_stmt)
+{
+ splay_tree_node default_node;
+ location_t *switch_locus;
+ tree type;
+
+ if (!warn_switch && !warn_switch_enum && !warn_switch_default)
+ return;
+
+ switch_locus = EXPR_LOCUS (switch_stmt);
+ if (!switch_locus)
+ switch_locus = &input_location;
+ type = SWITCH_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_locus);
+
+ /* If the switch expression was an enumerated type, check that
+ exactly all enumeration literals are covered by the cases.
+ The check is made when -Wswitch was specified and there is no
+ 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_COND (switch_stmt)) != INTEGER_CST)
+ {
+ tree chain;
+
+ /* The time complexity here is O(N*lg(N)) worst case, but for the
+ common case of monotonically increasing enumerators, it is
+ O(N), since the nature of the splay tree will keep the next
+ element adjacent to the root at all times. */
+
+ for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
+ {
+ splay_tree_node node
+ = splay_tree_lookup (cases, (splay_tree_key) TREE_VALUE (chain));
+
+ if (node)
+ {
+ /* Mark the CASE_LOW part of the case entry as seen, so
+ that we save time later. Choose TREE_ADDRESSABLE
+ randomly as a bit that won't have been set to-date. */
+ tree label = (tree) node->value;
+ TREE_ADDRESSABLE (label) = 1;
+ }
+ else
+ {
+ /* Warn if there are enumerators that don't correspond to
+ case expressions. */
+ warning ("%Henumeration value `%E' not handled in switch",
+ switch_locus, TREE_PURPOSE (chain));
+ }
+ }
+
+ /* Warn if there are case expressions that don't correspond to
+ enumerators. This can occur since C and C++ don't enforce
+ type-checking of assignments to enumeration variables.
+
+ The time complexity here is O(N**2) worst case, since we've
+ not sorted the enumeration values. However, in the absence
+ of case ranges this is O(N), since all single cases that
+ corresponded to enumerations have been marked above. */
+
+ splay_tree_foreach (cases, match_case_to_enum, type);
+ }
}
/* Finish an expression taking the address of LABEL (an
@@ -3993,7 +4240,6 @@ finish_label_address_expr (tree label)
{
TREE_USED (label) = 1;
result = build1 (ADDR_EXPR, ptr_type_node, label);
- TREE_CONSTANT (result) = 1;
/* The current function in not necessarily uninlinable.
Computed gotos are incompatible with inlining, but the value
here could be used only in a diagnostic, for example. */
@@ -4003,6 +4249,9 @@ finish_label_address_expr (tree label)
}
/* Hook used by expand_expr to expand language-specific tree codes. */
+/* The only things that should go here are bits needed to expand
+ constant initalizers. Everything else should be handled by the
+ gimplification routines. */
rtx
c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
@@ -4011,88 +4260,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
{
switch (TREE_CODE (exp))
{
- case STMT_EXPR:
- {
- tree rtl_expr;
- rtx result;
- bool preserve_result = false;
-
- if (STMT_EXPR_WARN_UNUSED_RESULT (exp) && target == const0_rtx)
- {
- tree stmt = STMT_EXPR_STMT (exp);
- tree scope;
-
- for (scope = COMPOUND_BODY (stmt);
- scope && TREE_CODE (scope) != SCOPE_STMT;
- scope = TREE_CHAIN (scope));
-
- if (scope && SCOPE_STMT_BLOCK (scope))
- warning ("%Hignoring return value of `%D', "
- "declared with attribute warn_unused_result",
- &expr_wfl_stack->location,
- BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope)));
- else
- warning ("%Hignoring return value of function "
- "declared with attribute warn_unused_result",
- &expr_wfl_stack->location);
- }
-
- /* Since expand_expr_stmt calls free_temp_slots after every
- expression statement, we must call push_temp_slots here.
- Otherwise, any temporaries in use now would be considered
- out-of-scope after the first EXPR_STMT from within the
- STMT_EXPR. */
- push_temp_slots ();
- rtl_expr = expand_start_stmt_expr (!STMT_EXPR_NO_SCOPE (exp));
-
- /* If we want the result of this expression, find the last
- EXPR_STMT in the COMPOUND_STMT and mark it as addressable. */
- if (target != const0_rtx
- && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT
- && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT)
- {
- tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp));
- tree last = TREE_CHAIN (expr);
-
- while (TREE_CHAIN (last))
- {
- expr = last;
- last = TREE_CHAIN (last);
- }
-
- if (TREE_CODE (last) == SCOPE_STMT
- && TREE_CODE (expr) == EXPR_STMT)
- {
- /* Otherwise, note that we want the value from the last
- expression. */
- TREE_ADDRESSABLE (expr) = 1;
- preserve_result = true;
- }
- }
-
- expand_stmt (STMT_EXPR_STMT (exp));
- expand_end_stmt_expr (rtl_expr);
-
- result = expand_expr_real (rtl_expr, target, tmode, modifier, alt_rtl);
- if (preserve_result && GET_CODE (result) == MEM)
- {
- if (GET_MODE (result) != BLKmode)
- result = copy_to_reg (result);
- else
- preserve_temp_slots (result);
- }
-
- /* If the statment-expression does not have a scope, then the
- new temporaries we created within it must live beyond the
- statement-expression. */
- if (STMT_EXPR_NO_SCOPE (exp))
- preserve_temp_slots (NULL_RTX);
-
- pop_temp_slots ();
- return result;
- }
- break;
-
case COMPOUND_LITERAL_EXPR:
{
/* Initialize the anonymous variable declared in the compound
@@ -4105,9 +4272,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode,
default:
abort ();
}
-
- abort ();
- return NULL;
}
/* Hook used by safe_from_p to handle language-specific tree codes. */
@@ -4684,7 +4848,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
&& ! TREE_STATIC (decl))
{
error ("%Jsection attribute cannot be specified for "
- "local variables", decl);
+ "local variables", decl);
*no_add_attrs = true;
}
@@ -4695,7 +4859,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
{
error ("%Jsection of '%D' conflicts with previous declaration",
- *node, *node);
+ *node, *node);
*no_add_attrs = true;
}
else
@@ -4848,7 +5012,10 @@ handle_alias_attribute (tree *node, tree name, tree args,
if (TREE_CODE (decl) == FUNCTION_DECL)
DECL_INITIAL (decl) = error_mark_node;
else
- DECL_EXTERNAL (decl) = 0;
+ {
+ DECL_EXTERNAL (decl) = 0;
+ TREE_STATIC (decl) = 1;
+ }
}
else
{
@@ -5191,7 +5358,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
if (! TYPE_ARG_TYPES (type))
{
error ("nonnull attribute without arguments on a non-prototype");
- *no_add_attrs = true;
+ *no_add_attrs = true;
}
return NULL_TREE;
}
@@ -5201,7 +5368,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
{
tree argument;
- unsigned HOST_WIDE_INT arg_num, ck_num;
+ unsigned HOST_WIDE_INT arg_num = 0, ck_num;
if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
{
@@ -5221,7 +5388,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
argument = TREE_CHAIN (argument);
}
- if (! argument
+ if (! argument
|| TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
{
error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)",
@@ -5230,7 +5397,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
return NULL_TREE;
}
- if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
+ if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
{
error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
@@ -5256,22 +5423,22 @@ check_function_nonnull (tree attrs, tree params)
{
if (is_attribute_p ("nonnull", TREE_PURPOSE (a)))
{
- args = TREE_VALUE (a);
+ args = TREE_VALUE (a);
- /* Walk the argument list. If we encounter an argument number we
- should check for non-null, do it. If the attribute has no args,
- then every pointer argument is checked (in which case the check
+ /* Walk the argument list. If we encounter an argument number we
+ should check for non-null, do it. If the attribute has no args,
+ then every pointer argument is checked (in which case the check
for pointer type is done in check_nonnull_arg). */
- for (param = params, param_num = 1; ;
- param_num++, param = TREE_CHAIN (param))
- {
- if (! param)
+ for (param = params, param_num = 1; ;
+ param_num++, param = TREE_CHAIN (param))
+ {
+ if (! param)
break;
- if (! args || nonnull_check_p (args, param_num))
+ if (! args || nonnull_check_p (args, param_num))
check_function_arguments_recurse (check_nonnull_arg, NULL,
TREE_VALUE (param),
param_num);
- }
+ }
}
}
}
@@ -5283,12 +5450,12 @@ check_function_nonnull (tree attrs, tree params)
static bool
nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
{
- unsigned HOST_WIDE_INT arg_num;
+ unsigned HOST_WIDE_INT arg_num = 0;
for (; args; args = TREE_CHAIN (args))
{
if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
- abort ();
+ abort ();
if (arg_num == param_num)
return true;
@@ -5313,7 +5480,7 @@ check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param,
if (integer_zerop (param))
warning ("null argument where non-null required (arg %lu)",
- (unsigned long) param_num);
+ (unsigned long) param_num);
}
/* Helper for nonnull attribute handling; fetch the operand number
@@ -5447,7 +5614,7 @@ check_function_arguments_recurse (void (*callback)
{
/* Strip coercion. */
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 0), param_num);
+ TREE_OPERAND (param, 0), param_num);
return;
}
@@ -5509,15 +5676,74 @@ check_function_arguments_recurse (void (*callback)
{
/* Check both halves of the conditional expression. */
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 1), param_num);
+ TREE_OPERAND (param, 1), param_num);
check_function_arguments_recurse (callback, ctx,
- TREE_OPERAND (param, 2), param_num);
+ TREE_OPERAND (param, 2), param_num);
return;
}
(*callback) (ctx, param, param_num);
}
+/* C implementation of lang_hooks.tree_inlining.walk_subtrees. Tracks the
+ locus from EXPR_LOCUS and handles DECL_STMT specially. */
+
+tree
+c_walk_subtrees (tree *tp, int *walk_subtrees_p ATTRIBUTE_UNUSED,
+ walk_tree_fn func, void *data, void *htab)
+{
+ enum tree_code code = TREE_CODE (*tp);
+ location_t save_locus;
+ tree result;
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ result = walk_tree (&(NODE), func, data, htab); \
+ if (result) goto out; \
+ } \
+ while (0)
+
+ if (code != DECL_STMT)
+ return NULL_TREE;
+
+ /* Set input_location here so we get the right instantiation context
+ if we call instantiate_decl from inlinable_function_p. */
+ save_locus = input_location;
+ if (EXPR_LOCUS (*tp))
+ input_location = *EXPR_LOCUS (*tp);
+
+ /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk
+ into declarations that are just mentioned, rather than
+ declared; they don't really belong to this part of the tree.
+ And, we can see cycles: the initializer for a declaration can
+ refer to the declaration itself. */
+ WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp)));
+ WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp)));
+ WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp)));
+ WALK_SUBTREE (TREE_CHAIN (*tp));
+ *walk_subtrees_p = 0;
+
+ /* We didn't find what we were looking for. */
+ out:
+ input_location = save_locus;
+ return result;
+
+#undef WALK_SUBTREE
+}
+
+/* C implementation of lang_hooks.tree_inlining.tree_chain_matters_p.
+ Apart from TREE_LISTs, the only trees whose TREE_CHAIN we care about are
+ _STMT nodes. */
+
+int
+c_tree_chain_matters_p (tree t)
+{
+ /* For statements, we also walk the chain so that we cover the
+ entire statement tree. */
+ return STATEMENT_CODE_P (TREE_CODE (t));
+}
+
/* Function to help qsort sort FIELD_DECLs by name order. */
int
@@ -5573,15 +5799,15 @@ resort_field_decl_cmp (const void *x_p, const void *y_p)
void
resort_sorted_fields (void *obj,
- void *orig_obj ATTRIBUTE_UNUSED ,
- gt_pointer_operator new_value,
- void *cookie)
+ void *orig_obj ATTRIBUTE_UNUSED ,
+ gt_pointer_operator new_value,
+ void *cookie)
{
struct sorted_fields_type *sf = obj;
resort_data.new_value = new_value;
resort_data.cookie = cookie;
qsort (&sf->elts[0], sf->len, sizeof (tree),
- resort_field_decl_cmp);
+ resort_field_decl_cmp);
}
/* Used by estimate_num_insns. Estimate number of instructions seen
@@ -5675,14 +5901,12 @@ c_estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case EXIT_EXPR:
case LABELED_BLOCK_EXPR:
case EXIT_BLOCK_EXPR:
- case EXPR_WITH_FILE_LOCATION:
case EXPR_STMT:
case COMPOUND_STMT:
case RETURN_STMT:
case LABEL_STMT:
case SCOPE_STMT:
- case FILE_STMT:
case CASE_LABEL:
case STMT_EXPR:
case CLEANUP_STMT:
@@ -5711,37 +5935,6 @@ c_estimate_num_insns (tree decl)
return num;
}
-/* Used by c_decl_uninit to find where expressions like x = x + 1; */
-
-static tree
-c_decl_uninit_1 (tree *t, int *walk_sub_trees, void *x)
-{
- /* If x = EXP(&x)EXP, then do not warn about the use of x. */
- if (TREE_CODE (*t) == ADDR_EXPR && TREE_OPERAND (*t, 0) == x)
- {
- *walk_sub_trees = 0;
- return NULL_TREE;
- }
- if (*t == x)
- return *t;
- return NULL_TREE;
-}
-
-/* Find out if a variable is uninitialized based on DECL_INITIAL. */
-
-bool
-c_decl_uninit (tree t)
-{
- /* int x = x; is GCC extension to turn off this warning, only if warn_init_self is zero. */
- if (DECL_INITIAL (t) == t)
- return warn_init_self ? true : false;
-
- /* Walk the trees looking for the variable itself. */
- if (walk_tree_without_duplicates (&DECL_INITIAL (t), c_decl_uninit_1, t))
- return true;
- return false;
-}
-
/* Issue the error given by MSGID, indicating that it occurred before
TOKEN, which had the associated VALUE. */
@@ -5774,4 +5967,74 @@ c_parse_error (const char *msgid, enum cpp_ttype token, tree value)
error ("%s", string);
}
+/* Walk a gimplified function and warn for functions whose return value is
+ ignored and attribute((warn_unused_result)) is set. This is done before
+ inlining, so we don't have to worry about that. */
+
+void
+c_warn_unused_result (tree *top_p)
+{
+ tree t = *top_p;
+ tree_stmt_iterator i;
+ tree fdecl, ftype;
+
+ switch (TREE_CODE (t))
+ {
+ case STATEMENT_LIST:
+ for (i = tsi_start (*top_p); !tsi_end_p (i); tsi_next (&i))
+ c_warn_unused_result (tsi_stmt_ptr (i));
+ break;
+
+ case COND_EXPR:
+ c_warn_unused_result (&COND_EXPR_THEN (t));
+ c_warn_unused_result (&COND_EXPR_ELSE (t));
+ break;
+ case BIND_EXPR:
+ c_warn_unused_result (&BIND_EXPR_BODY (t));
+ break;
+ case TRY_FINALLY_EXPR:
+ case TRY_CATCH_EXPR:
+ c_warn_unused_result (&TREE_OPERAND (t, 0));
+ c_warn_unused_result (&TREE_OPERAND (t, 1));
+ break;
+ case CATCH_EXPR:
+ c_warn_unused_result (&CATCH_BODY (t));
+ break;
+ case EH_FILTER_EXPR:
+ c_warn_unused_result (&EH_FILTER_FAILURE (t));
+ break;
+
+ case CALL_EXPR:
+ /* This is a naked call, as opposed to a CALL_EXPR nested inside
+ a MODIFY_EXPR. All calls whose value is ignored should be
+ represented like this. Look for the attribute. */
+ fdecl = get_callee_fndecl (t);
+ if (fdecl)
+ ftype = TREE_TYPE (fdecl);
+ else
+ {
+ ftype = TREE_TYPE (TREE_OPERAND (t, 0));
+ /* Look past pointer-to-function to the function type itself. */
+ ftype = TREE_TYPE (ftype);
+ }
+
+ if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
+ {
+ if (fdecl)
+ warning ("%Hignoring return value of `%D', "
+ "declared with attribute warn_unused_result",
+ EXPR_LOCUS (t), fdecl);
+ else
+ warning ("%Hignoring return value of function "
+ "declared with attribute warn_unused_result",
+ EXPR_LOCUS (t));
+ }
+ break;
+
+ default:
+ /* Not a container, not a call, or a call whose value is used. */
+ break;
+ }
+}
+
#include "gt-c-common.h"