From ebfbbdc556443d1ea95923b596f59411256bd9b5 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek <jakub@redhat.com> Date: Wed, 7 Apr 2010 22:33:36 +0200 Subject: [PATCH] re PR c/18624 (GCC does not detect local variable set but never used) PR c/18624 * tree.h (DECL_READ_P): Define. (struct tree_decl_common): Add decl_read_flag. * c-decl.c (pop_scope): If TREE_USED but !DECL_READ_P, issue a set but not used warning. (merge_decls): Merge DECL_READ_P flag. (finish_decl, build_compound_literal): Set DECL_READ_P flag. (finish_function): Issue -Wunused-but-set-parameter diagnostics. * c-common.c (handle_used_attribute, handle_unused_attribute): Likewise. * c-tree.h (default_function_array_read_conversion, mark_exp_read): New prototypes. * c-typeck.c (default_function_array_read_conversion, mark_exp_read): New functions. (default_conversion, c_process_expr_stmt): Call mark_exp_read. * c-parser.c (c_parser_initializer, c_parser_expr_no_commas, c_parser_binary_expression, c_parser_cast_expression, c_parser_expr_list, c_parser_omp_atomic, c_parser_omp_for_loop): Call default_function_array_read_conversion instead of default_function_array_conversion where needed. (c_parser_unary_expression, c_parser_conditional_expression, c_parser_postfix_expression_after_primary, c_parser_initelt): Likewise. Call mark_exp_read where needed. (c_parser_statement_after_labels, c_parser_asm_operands, c_parser_typeof_specifier, c_parser_sizeof_expression, c_parser_alignof_expression, c_parser_initval): Call mark_exp_read where needed. * common.opt (Wunused-but-set-variable, Wunused-but-set-parameter): New. * toplev.c (warn_unused_but_set_variable): Default to warn_unused. (warn_unused_but_set_parameter): Default to warn_unused && extra_warnings. * doc/invoke.texi: Document -Wunused-but-set-variable and -Wunused-but-set-parameter. * objc-act.c (finish_var_decl, objc_begin_catch_clause, really_start_method, get_super_receiver, handle_class_ref): Set DECL_READ_P in addition to TREE_USED. * gcc.dg/Wunused-var-1.c: New test. * gcc.dg/Wunused-var-2.c: New test. * gcc.dg/Wunused-var-3.c: New test. * gcc.dg/Wunused-var-4.c: New test. * gcc.dg/Wunused-var-5.c: New test. * gcc.dg/Wunused-var-6.c: New test. * gcc.dg/Wunused-parm-1.c: New test. From-SVN: r158086 --- gcc/ChangeLog | 35 +++++ gcc/c-common.c | 9 +- gcc/c-decl.c | 39 +++++- gcc/c-parser.c | 77 ++++++----- gcc/c-tree.h | 7 +- gcc/c-typeck.c | 38 ++++++ gcc/common.opt | 8 ++ gcc/doc/invoke.texi | 30 ++++- gcc/objc/ChangeLog | 7 + gcc/objc/objc-act.c | 9 +- gcc/testsuite/ChangeLog | 9 ++ gcc/testsuite/gcc.dg/Wunused-parm-1.c | 29 +++++ gcc/testsuite/gcc.dg/Wunused-var-1.c | 179 ++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Wunused-var-2.c | 20 +++ gcc/testsuite/gcc.dg/Wunused-var-3.c | 37 ++++++ gcc/testsuite/gcc.dg/Wunused-var-4.c | 26 ++++ gcc/testsuite/gcc.dg/Wunused-var-5.c | 33 +++++ gcc/testsuite/gcc.dg/Wunused-var-6.c | 19 +++ gcc/toplev.c | 6 + gcc/tree.h | 9 +- 20 files changed, 586 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wunused-parm-1.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-1.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-2.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-3.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-4.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-5.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-var-6.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1f32f76d46f4..9db02bcfc60e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,40 @@ 2010-04-07 Jakub Jelinek <jakub@redhat.com> + PR c/18624 + * tree.h (DECL_READ_P): Define. + (struct tree_decl_common): Add decl_read_flag. + * c-decl.c (pop_scope): If TREE_USED but !DECL_READ_P, issue + a set but not used warning. + (merge_decls): Merge DECL_READ_P flag. + (finish_decl, build_compound_literal): Set DECL_READ_P flag. + (finish_function): Issue -Wunused-but-set-parameter diagnostics. + * c-common.c (handle_used_attribute, handle_unused_attribute): + Likewise. + * c-tree.h (default_function_array_read_conversion, mark_exp_read): + New prototypes. + * c-typeck.c (default_function_array_read_conversion, mark_exp_read): + New functions. + (default_conversion, c_process_expr_stmt): Call mark_exp_read. + * c-parser.c (c_parser_initializer, c_parser_expr_no_commas, + c_parser_binary_expression, c_parser_cast_expression, + c_parser_expr_list, c_parser_omp_atomic, c_parser_omp_for_loop): + Call default_function_array_read_conversion instead of + default_function_array_conversion where needed. + (c_parser_unary_expression, c_parser_conditional_expression, + c_parser_postfix_expression_after_primary, c_parser_initelt): + Likewise. Call mark_exp_read where needed. + (c_parser_statement_after_labels, c_parser_asm_operands, + c_parser_typeof_specifier, c_parser_sizeof_expression, + c_parser_alignof_expression, c_parser_initval): Call mark_exp_read + where needed. + * common.opt (Wunused-but-set-variable, Wunused-but-set-parameter): + New. + * toplev.c (warn_unused_but_set_variable): Default to warn_unused. + (warn_unused_but_set_parameter): Default to warn_unused + && extra_warnings. + * doc/invoke.texi: Document -Wunused-but-set-variable and + -Wunused-but-set-parameter. + * tree-ssa-pre.c (my_rev_post_order_compute): Remove set but not used count variable. * genemit.c (gen_expand, gen_split): Avoid set but not used warnings diff --git a/gcc/c-common.c b/gcc/c-common.c index 7daba6bfea13..32dc21e93af0 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -6121,6 +6121,8 @@ handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), { TREE_USED (node) = 1; DECL_PRESERVE_P (node) = 1; + if (TREE_CODE (node) == VAR_DECL) + DECL_READ_P (node) = 1; } else { @@ -6147,7 +6149,12 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), || TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == LABEL_DECL || TREE_CODE (decl) == TYPE_DECL) - TREE_USED (decl) = 1; + { + TREE_USED (decl) = 1; + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + DECL_READ_P (decl) = 1; + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index b6ff3f476e6f..bc90fdd38ddf 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1164,14 +1164,21 @@ pop_scope (void) case VAR_DECL: /* Warnings for unused variables. */ - if (!TREE_USED (p) + if ((!TREE_USED (p) || !DECL_READ_P (p)) && !TREE_NO_WARNING (p) && !DECL_IN_SYSTEM_HEADER (p) && DECL_NAME (p) && !DECL_ARTIFICIAL (p) && scope != file_scope && scope != external_scope) - warning (OPT_Wunused_variable, "unused variable %q+D", p); + { + if (!TREE_USED (p)) + warning (OPT_Wunused_variable, "unused variable %q+D", p); + else if (DECL_CONTEXT (p) == current_function_decl) + warning_at (DECL_SOURCE_LOCATION (p), + OPT_Wunused_but_set_variable, + "variable %qD set but not used", p); + } if (b->inner_comp) { @@ -2387,6 +2394,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) TREE_USED (newdecl) = 1; else if (TREE_USED (newdecl)) TREE_USED (olddecl) = 1; + if (TREE_CODE (olddecl) == VAR_DECL || TREE_CODE (olddecl) == PARM_DECL) + DECL_READ_P (newdecl) |= DECL_READ_P (olddecl); if (DECL_PRESERVE_P (olddecl)) DECL_PRESERVE_P (newdecl) = 1; else if (DECL_PRESERVE_P (newdecl)) @@ -4232,7 +4241,10 @@ finish_decl (tree decl, location_t init_loc, tree init, } if (TREE_USED (type)) - TREE_USED (decl) = 1; + { + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + } } /* If this is a function and an assembler name is specified, reset DECL_RTL @@ -4380,6 +4392,7 @@ finish_decl (tree decl, location_t init_loc, tree init, /* Don't warn about decl unused; the cleanup uses it. */ TREE_USED (decl) = 1; TREE_USED (cleanup_decl) = 1; + DECL_READ_P (decl) = 1; push_cleanup (decl, cleanup, false); } @@ -4472,6 +4485,7 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const) TREE_STATIC (decl) = (current_scope == file_scope); DECL_CONTEXT (decl) = current_function_decl; TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; TREE_TYPE (decl) = type; TREE_READONLY (decl) = TYPE_READONLY (type); store_init_value (loc, decl, init, NULL_TREE); @@ -8060,6 +8074,25 @@ finish_function (void) TREE_NO_WARNING (fndecl) = 1; } + /* Complain about parameters that are only set, but never otherwise used. */ + if (warn_unused_but_set_parameter) + { + tree decl; + + for (decl = DECL_ARGUMENTS (fndecl); + decl; + decl = TREE_CHAIN (decl)) + if (TREE_USED (decl) + && TREE_CODE (decl) == PARM_DECL + && !DECL_READ_P (decl) + && DECL_NAME (decl) + && !DECL_ARTIFICIAL (decl) + && !TREE_NO_WARNING (decl)) + warning_at (DECL_SOURCE_LOCATION (decl), + OPT_Wunused_but_set_parameter, + "parameter %qD set but not used", decl); + } + /* Store the end of the function, so that we get good line number info for the epilogue. */ cfun->function_end_locus = input_location; diff --git a/gcc/c-parser.c b/gcc/c-parser.c index bf66a584ba8e..27f0b819880c 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -1,6 +1,6 @@ /* Parser for C and Objective-C. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Parser actions based on the old Bison parser; structure somewhat @@ -2171,6 +2171,7 @@ c_parser_typeof_specifier (c_parser *parser) if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) error_at (here, "%<typeof%> applied to a bit-field"); + mark_exp_read (expr.value); ret.spec = TREE_TYPE (expr.value); was_vm = variably_modified_type_p (ret.spec, NULL_TREE); /* This is returned with the type so that when the type is @@ -3073,7 +3074,7 @@ c_parser_initializer (c_parser *parser) ret = c_parser_expr_no_commas (parser, NULL); if (TREE_CODE (ret.value) != STRING_CST && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) - ret = default_function_array_conversion (loc, ret); + ret = default_function_array_read_conversion (loc, ret); return ret; } } @@ -3229,6 +3230,7 @@ c_parser_initelt (c_parser *parser) goto parse_message_args; } first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); if (c_parser_next_token_is (parser, CPP_ELLIPSIS) || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) goto array_desig_after_first; @@ -3244,7 +3246,8 @@ c_parser_initelt (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; next = c_parser_expr_no_commas (parser, NULL); - next = default_function_array_conversion (exp_loc, next); + next = default_function_array_read_conversion (exp_loc, + next); rec = build_compound_expr (comma_loc, rec, next.value); } parse_message_args: @@ -3264,12 +3267,14 @@ c_parser_initelt (c_parser *parser) } c_parser_consume_token (parser); first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); array_desig_after_first: if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { ellipsis_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); second = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (second); } else second = NULL_TREE; @@ -3337,7 +3342,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after) if (init.value != NULL_TREE && TREE_CODE (init.value) != STRING_CST && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) - init = default_function_array_conversion (loc, init); + init = default_function_array_read_conversion (loc, init); } process_init_element (init, false); } @@ -3840,6 +3845,7 @@ c_parser_statement_after_labels (c_parser *parser) else { struct c_expr expr = c_parser_expression_conv (parser); + mark_exp_read (expr.value); stmt = c_finish_return (loc, expr.value, expr.original_type); goto expect_semicolon; } @@ -4455,6 +4461,7 @@ c_parser_asm_operands (c_parser *parser, bool convert_p) } loc = c_parser_peek_token (parser)->location; expr = c_parser_expression (parser); + mark_exp_read (expr.value); if (convert_p) expr = default_function_array_conversion (loc, expr); expr.value = c_fully_fold (expr.value, false, NULL); @@ -4605,7 +4612,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) c_parser_consume_token (parser); exp_location = c_parser_peek_token (parser)->location; rhs = c_parser_expr_no_commas (parser, NULL); - rhs = default_function_array_conversion (exp_location, rhs); + rhs = default_function_array_read_conversion (exp_location, rhs); ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, code, exp_location, rhs.value, rhs.original_type); @@ -4647,7 +4654,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; cond_loc = c_parser_peek_token (parser)->location; - cond = default_function_array_conversion (cond_loc, cond); + cond = default_function_array_read_conversion (cond_loc, cond); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COLON)) { @@ -4674,6 +4681,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) (cond_loc, default_conversion (cond.value)); c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; exp1 = c_parser_expression_conv (parser); + mark_exp_read (exp1.value); c_inhibit_evaluation_warnings += ((cond.value == truthvalue_true_node) - (cond.value == truthvalue_false_node)); @@ -4691,7 +4699,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) { location_t exp2_loc = c_parser_peek_token (parser)->location; exp2 = c_parser_conditional_expression (parser, NULL); - exp2 = default_function_array_conversion (exp2_loc, exp2); + exp2 = default_function_array_read_conversion (exp2_loc, exp2); } c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; ret.value = build_conditional_expr (colon_loc, cond.value, @@ -4844,10 +4852,11 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) break; \ } \ stack[sp - 1].expr \ - = default_function_array_conversion (stack[sp - 1].loc, \ - stack[sp - 1].expr); \ + = default_function_array_read_conversion (stack[sp - 1].loc, \ + stack[sp - 1].expr); \ stack[sp].expr \ - = default_function_array_conversion (stack[sp].loc, stack[sp].expr); \ + = default_function_array_read_conversion (stack[sp].loc, \ + stack[sp].expr); \ stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ stack[sp].op, \ stack[sp - 1].expr, \ @@ -4952,8 +4961,8 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) { case TRUTH_ANDIF_EXPR: stack[sp].expr - = default_function_array_conversion (stack[sp].loc, - stack[sp].expr); + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (stack[sp].loc, default_conversion (stack[sp].expr.value)); c_inhibit_evaluation_warnings += (stack[sp].expr.value @@ -4961,8 +4970,8 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) break; case TRUTH_ORIF_EXPR: stack[sp].expr - = default_function_array_conversion (stack[sp].loc, - stack[sp].expr); + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (stack[sp].loc, default_conversion (stack[sp].expr.value)); c_inhibit_evaluation_warnings += (stack[sp].expr.value @@ -5032,7 +5041,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) { location_t expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_cast_expression (parser, NULL); - expr = default_function_array_conversion (expr_loc, expr); + expr = default_function_array_read_conversion (expr_loc, expr); } ret.value = c_cast_expr (cast_loc, type_name, expr.value); ret.original_code = ERROR_MARK; @@ -5085,23 +5094,24 @@ c_parser_unary_expression (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); case CPP_MINUS_MINUS: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: c_parser_consume_token (parser); - return parser_build_unary_op (op_loc, ADDR_EXPR, - c_parser_cast_expression (parser, NULL)); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); case CPP_MULT: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR); return ret; case CPP_PLUS: @@ -5112,25 +5122,25 @@ c_parser_unary_expression (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, CONVERT_EXPR, op); case CPP_MINUS: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, NEGATE_EXPR, op); case CPP_COMPL: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); case CPP_NOT: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); case CPP_AND_AND: /* Refer to the address of a label as a pointer. */ @@ -5230,6 +5240,7 @@ c_parser_sizeof_expression (c_parser *parser) sizeof_expr: c_inhibit_evaluation_warnings--; in_sizeof--; + mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) error_at (expr_loc, "%<sizeof%> applied to a bit-field"); @@ -5290,6 +5301,7 @@ c_parser_alignof_expression (c_parser *parser) struct c_expr ret; expr = c_parser_unary_expression (parser); alignof_expr: + mark_exp_read (expr.value); c_inhibit_evaluation_warnings--; in_alignof--; ret.value = c_alignof_expr (loc, expr.value); @@ -5495,6 +5507,7 @@ c_parser_postfix_expression (c_parser *parser) break; } e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); e1.value = c_fully_fold (e1.value, false, NULL); if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { @@ -5639,6 +5652,8 @@ c_parser_postfix_expression (c_parser *parser) tree c; c = e1.value; + mark_exp_read (e2.value); + mark_exp_read (e3.value); if (TREE_CODE (c) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (c))) error_at (loc, @@ -5883,6 +5898,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); orig_expr = expr; + mark_exp_read (expr.value); /* FIXME diagnostics: Ideally we want the FUNCNAME, not the "(" after the FUNCNAME, which is what we have now. */ expr.value = build_function_call_vec (op_loc, expr.value, exprlist, @@ -5965,7 +5981,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_PLUS_PLUS: /* Postincrement. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr_loc, expr); + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; @@ -5974,7 +5990,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_MINUS_MINUS: /* Postdecrement. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr_loc, expr); + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; @@ -6052,7 +6068,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) - expr = default_function_array_conversion (loc, expr); + expr = default_function_array_read_conversion (loc, expr); if (fold_p) expr.value = c_fully_fold (expr.value, false, NULL); VEC_quick_push (tree, ret, expr.value); @@ -6064,7 +6080,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, loc = c_parser_peek_token (parser)->location; expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) - expr = default_function_array_conversion (loc, expr); + expr = default_function_array_read_conversion (loc, expr); if (fold_p) expr.value = c_fully_fold (expr.value, false, NULL); VEC_safe_push (tree, gc, ret, expr.value); @@ -7887,7 +7903,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { location_t rhs_loc = c_parser_peek_token (parser)->location; rhs_expr = c_parser_expression (parser); - rhs_expr = default_function_array_conversion (rhs_loc, rhs_expr); + rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); } rhs = rhs_expr.value; rhs = c_fully_fold (rhs, false, NULL); @@ -8034,7 +8050,8 @@ c_parser_omp_for_loop (location_t loc, init_loc = c_parser_peek_token (parser)->location; init_exp = c_parser_expr_no_commas (parser, NULL); - init_exp = default_function_array_conversion (init_loc, init_exp); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); init = build_modify_expr (init_loc, decl, decl_exp.original_type, NOP_EXPR, init_loc, init_exp.value, init_exp.original_type); diff --git a/gcc/c-tree.h b/gcc/c-tree.h index dab9d39175ec..3681ed7dfec1 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -1,6 +1,6 @@ /* Definitions for C parsing and type checking. Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -511,7 +511,10 @@ extern bool c_mark_addressable (tree); extern void c_incomplete_type_error (const_tree, const_tree); extern tree c_type_promotes_to (tree); extern struct c_expr default_function_array_conversion (location_t, - struct c_expr); + struct c_expr); +extern struct c_expr default_function_array_read_conversion (location_t, + struct c_expr); +extern void mark_exp_read (tree); extern tree composite_type (tree, tree); extern tree build_component_ref (location_t, tree, tree); extern tree build_array_ref (location_t, tree, tree); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 89e534aa0b3f..2296cbe2f932 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1763,6 +1763,35 @@ function_to_pointer_conversion (location_t loc, tree exp) return build_unary_op (loc, ADDR_EXPR, exp, 0); } +/* Mark EXP as read, not just set, for set but not used -Wunused + warning purposes. */ + +void +mark_exp_read (tree exp) +{ + switch (TREE_CODE (exp)) + { + case VAR_DECL: + case PARM_DECL: + DECL_READ_P (exp) = 1; + break; + case ARRAY_REF: + case COMPONENT_REF: + case MODIFY_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + CASE_CONVERT: + case ADDR_EXPR: + mark_exp_read (TREE_OPERAND (exp, 0)); + break; + case COMPOUND_EXPR: + mark_exp_read (TREE_OPERAND (exp, 1)); + break; + default: + break; + } +} + /* Perform the default conversion of arrays and functions to pointers. Return the result of converting EXP. For any other expression, just return EXP. @@ -1818,6 +1847,12 @@ default_function_array_conversion (location_t loc, struct c_expr exp) return exp; } +struct c_expr +default_function_array_read_conversion (location_t loc, struct c_expr exp) +{ + mark_exp_read (exp.value); + return default_function_array_conversion (loc, exp); +} /* EXP is an expression of integer type. Apply the integer promotions to it and return the promoted value. */ @@ -1879,6 +1914,8 @@ default_conversion (tree exp) enum tree_code code = TREE_CODE (type); tree promoted_type; + mark_exp_read (exp); + /* Functions and arrays have been converted during parsing. */ gcc_assert (code != FUNCTION_TYPE); if (code == ARRAY_TYPE) @@ -8793,6 +8830,7 @@ c_process_expr_stmt (location_t loc, tree expr) number, wrap the thing in a no-op NOP_EXPR. */ if (DECL_P (expr) || CONSTANT_CLASS_P (expr)) { + mark_exp_read (expr); expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr); SET_EXPR_LOCATION (expr, loc); } diff --git a/gcc/common.opt b/gcc/common.opt index 49eb453f2a7e..d5f00a0bd9ad 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -212,6 +212,14 @@ Wunused Common Var(warn_unused) Init(0) Warning Enable all -Wunused- warnings +Wunused-but-set-parameter +Common Var(warn_unused_but_set_parameter) Init(-1) Warning +Warn when a function parameter is only set, otherwise unused + +Wunused-but-set-variable +Common Var(warn_unused_but_set_variable) Init(-1) Warning +Warn when a variable is only set, otherwise unused + Wunused-function Common Var(warn_unused_function) Init(-1) Warning Warn when a function is unused diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d356daaf0215..67a1b60d15ca 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -262,7 +262,7 @@ Objective-C and Objective-C++ Dialects}. -Wunknown-pragmas -Wno-pragmas @gol -Wunsuffixed-float-constants -Wunused -Wunused-function @gol -Wunused-label -Wunused-parameter -Wno-unused-result -Wunused-value -Wunused-variable @gol --Wvariadic-macros -Wvla @gol +-Wunused-but-set-parameter -Wunused-but-set-variable -Wvariadic-macros -Wvla @gol -Wvolatile-register-var -Wwrite-strings} @item C and Objective-C-only Warning Options @@ -2926,7 +2926,8 @@ name is still supported, but the newer name is more descriptive.) -Wsign-compare @gol -Wtype-limits @gol -Wuninitialized @gol --Wunused-parameter @r{(only with} @option{-Wunused} @r{or} @option{-Wall}@r{)} @gol +-Wunused-parameter @r{(only with} @option{-Wunused} @r{or} @option{-Wall}@r{)} @gol +-Wunused-but-set-parameter @r{(only with} @option{-Wunused} @r{or} @option{-Wall}@r{)} @gol } The option @option{-Wextra} also prints warning messages for the @@ -3321,6 +3322,31 @@ Warn if any trigraphs are encountered that might change the meaning of the program (trigraphs within comments are not warned about). This warning is enabled by @option{-Wall}. +@item -Wunused-but-set-parameter +@opindex Wunused-but-set-parameter +@opindex Wno-unused-but-set-parameter +Warn whenever a function parameter is assigned to, but otherwise unused +(aside from its declaration). + +To suppress this warning use the @samp{unused} attribute +(@pxref{Variable Attributes}). + +This warning is also enabled by @option{-Wunused} together with +@option{-Wextra}. + +@item -Wunused-but-set-variable +@opindex Wunused-but-set-variable +@opindex Wno-unused-but-set-variable +Warn whenever a local variable is assigned to, but otherwise unused +(aside from its declaration). +This warning is enabled by @option{-Wall}. + +To suppress this warning use the @samp{unused} attribute +(@pxref{Variable Attributes}). + +This warning is also enabled by @option{-Wunused}, which is enabled +by @option{-Wall}. + @item -Wunused-function @opindex Wunused-function @opindex Wno-unused-function diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 3063af9f3af2..4307001dffca 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,10 @@ +2010-04-07 Jakub Jelinek <jakub@redhat.com> + + PR c/18624 + * objc-act.c (finish_var_decl, objc_begin_catch_clause, + really_start_method, get_super_receiver, handle_class_ref): Set + DECL_READ_P in addition to TREE_USED. + 2010-04-07 Iain Sandoe <iains@gcc.gnu.org> PR objc/35996 diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index f5b754be7239..9e5fdb515f78 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1,6 +1,7 @@ /* Implement classes and message passing for Objective C. Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Steve Naroff. This file is part of GCC. @@ -1531,6 +1532,7 @@ finish_var_decl (tree var, tree initializer) mark_decl_referenced (var); /* Mark the decl to avoid "defined but not used" warning. */ TREE_USED (var) = 1; + DECL_READ_P (var) = 1; /* We reserve the right for the runtime to use/modify these variables in ways that are opaque to us. */ DECL_PRESERVE_P (var) = 1; @@ -3867,6 +3869,7 @@ objc_begin_catch_clause (tree decl) /* ??? As opposed to __attribute__((unused))? Anyway, this appears to be what the previous objc implementation did. */ TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; /* Verify that the type of the catch is valid. It must be a pointer to an Objective-C class, or "id" (which is catch-all). */ @@ -8722,7 +8725,9 @@ really_start_method (tree method, /* Suppress unused warnings. */ TREE_USED (self_decl) = 1; + DECL_READ_P (self_decl) = 1; TREE_USED (TREE_CHAIN (self_decl)) = 1; + DECL_READ_P (TREE_CHAIN (self_decl)) = 1; #ifdef OBJCPLUS pop_lang_context (); #endif @@ -8799,6 +8804,7 @@ get_super_receiver (void) objc_super_template); /* This prevents `unused variable' warnings when compiling with -Wall. */ TREE_USED (UOBJC_SUPER_decl) = 1; + DECL_READ_P (UOBJC_SUPER_decl) = 1; lang_hooks.decls.pushdecl (UOBJC_SUPER_decl); finish_decl (UOBJC_SUPER_decl, input_location, NULL_TREE, NULL_TREE, NULL_TREE); @@ -9422,6 +9428,7 @@ handle_class_ref (tree chain) DECL_INITIAL (decl) = exp; TREE_STATIC (decl) = 1; TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; /* Force the output of the decl as this forces the reference of the class. */ mark_decl_referenced (decl); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b7fb0c5b2ec1..d4ea27875680 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,14 @@ 2010-04-07 Jakub Jelinek <jakub@redhat.com> + PR c/18624 + * gcc.dg/Wunused-var-1.c: New test. + * gcc.dg/Wunused-var-2.c: New test. + * gcc.dg/Wunused-var-3.c: New test. + * gcc.dg/Wunused-var-4.c: New test. + * gcc.dg/Wunused-var-5.c: New test. + * gcc.dg/Wunused-var-6.c: New test. + * gcc.dg/Wunused-parm-1.c: New test. + * gcc.dg/builtin-choose-expr.c: Avoid set but not used warnings. * gcc.dg/trunc-1.c: Likewise. * gcc.dg/vla-9.c: Likewise. diff --git a/gcc/testsuite/gcc.dg/Wunused-parm-1.c b/gcc/testsuite/gcc.dg/Wunused-parm-1.c new file mode 100644 index 000000000000..bddbd83a63c6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-parm-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused -W" } */ + +long +f1 (unsigned long long x) +{ + unsigned long long a = 1; + const union { unsigned long long l; unsigned int p[2]; } b = { .l = x }; + const union { unsigned long long l; unsigned int p[2]; } c = { .l = a }; + return b.p[0] + c.p[0]; +} + +int +f2 (int x, int y) +{ + int a = 1; + int b[] = { 1, 2, x, a, 3, 4 }; + return b[y]; +} + +int +f3 (int a, /* { dg-warning "unused parameter" } */ + int b, /* { dg-warning "set but not used" } */ + int c) +{ + b = 1; + c = 1; + return c; +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-1.c b/gcc/testsuite/gcc.dg/Wunused-var-1.c new file mode 100644 index 000000000000..bee34d880310 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-1.c @@ -0,0 +1,179 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +void +f1 (void) +{ + int a; /* { dg-warning "set but not used" } */ + int b; + int c; + c = 1; + a = b = c; +} + +void +f2 (int x) +{ + int a; /* { dg-warning "set but not used" } */ + int b; + int c; /* { dg-warning "set but not used" } */ + c = (a = x, b = x); +} + +int +f3 (int x) +{ + int a; + return a = x; +} + +int +f4 (int x) +{ + int a; + a = x; + return a; +} + +void +f5 (int x) +{ + int a[2]; /* { dg-warning "set but not used" } */ + int b; + int *c, d[2]; + c = d; + b = x; + a[b] = 1; + c[b] = 1; +} + +int +f6 (int x) +{ + int a[2]; + int b; + b = x; + a[b] = 1; + return a[b]; +} + +void +f7 (int x, int *p) +{ + int *a[2]; + a[x] = p; + a[x][x] = x; +} + +struct S { int i; }; + +void +f8 (void) +{ + struct S s; /* { dg-warning "set but not used" } */ + s.i = 6; +} + +int +f9 (void) +{ + struct S s; + s.i = 6; + return s.i; +} + +struct S +f10 (void) +{ + struct S s; + s.i = 6; + return s; +} + +extern int foo11 (int *); + +void +f11 (void) +{ + int a[2]; + foo11 (a); +} + +void +f12 (void) +{ + int a; + a = 1; + a; /* { dg-warning "statement with no effect" } */ +} + +void +f13 (void (*x) (void)) +{ + void (*a) (void); + a = x; + a (); +} + +void +f14 (void (*x) (void)) +{ + void (*a) (void); /* { dg-warning "set but not used" } */ + a = x; +} + +extern void foo15 (int *); + +void +f15 (void) +{ + int a[10]; + int *b = a + 2; + foo15 (b); +} + +extern void foo16 (int **); + +void +f16 (void) +{ + int a[10]; + int *b[] = { a, a + 2 }; + foo16 (b); +} + +void +f17 (int x) +{ + long a; /* { dg-warning "set but not used" } */ + int b; + a = b = x; +} + +void +f18 (int x) +{ + int a; /* { dg-warning "set but not used" } */ + int b; + a = (char) (b = x); +} + +int +f19 (int x, int y, int z) +{ + int a; + int b; + a = x; + b = y; + return z ? a : b; +} + +int * +f20 (int x) +{ + static int a[] = { 3, 4, 5, 6 }; + static int b[] = { 4, 5, 6, 7 }; + static int c[] = { 5, 6, 7, 8 }; /* { dg-warning "set but not used" } */ + c[1] = 1; + return x ? a : b; +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-2.c b/gcc/testsuite/gcc.dg/Wunused-var-2.c new file mode 100644 index 000000000000..281825900b52 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +int +f1 (void) +{ + int c = ({ + int a; + a = 1; + a; }); + return c; +} + +void +f2 (void) +{ + int f; + f = 0; + __asm__ __volatile__ ("" : "+r" (f)); +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-3.c b/gcc/testsuite/gcc.dg/Wunused-var-3.c new file mode 100644 index 000000000000..9b1fce77ad3a --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-3.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +void +f1 (void) +{ + _Complex int a; /* { dg-warning "set but not used" } */ + _Complex double b; /* { dg-warning "set but not used" } */ + __real__ a = 1; + __imag__ a = 2; + __real__ b = 3.0; + __imag__ b = 4.0; +} + +int +f2 (void) +{ + _Complex int a; + _Complex double b; + __real__ a = 1; + __imag__ a = 2; + __real__ b = 3.0; + __imag__ b = 4.0; + return __real__ a + __imag__ b; +} + +_Complex double +f3 (void) +{ + _Complex int a; + _Complex double b; + __real__ a = 1; + __imag__ a = 2; + __real__ b = 3.0; + __imag__ b = 4.0; + return a + b; +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-4.c b/gcc/testsuite/gcc.dg/Wunused-var-4.c new file mode 100644 index 000000000000..d60dd70e5734 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-4.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +int +f1 (void) +{ + int a; + int foo (void) + { + return a; + } + a = 1; + return foo (); +} + +void +f2 (void) +{ + int a; /* { dg-warning "set but not used" } */ + void foo (void) + { + a = 2; + } + a = 1; + foo (); +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-5.c b/gcc/testsuite/gcc.dg/Wunused-var-5.c new file mode 100644 index 000000000000..747f58d04c09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-5.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +void +f1 (void) +{ + extern int extvari; + extvari = 1; +} + +int extvarj; + +void +f2 (void) +{ + extern int extvarj; + extvarj = 1; +} + +static int extvark; + +void +f3 (void) +{ + extern int extvark; + extvark = 1; +} + +int +f4 (void) +{ + return extvark; +} diff --git a/gcc/testsuite/gcc.dg/Wunused-var-6.c b/gcc/testsuite/gcc.dg/Wunused-var-6.c new file mode 100644 index 000000000000..b5a22f86545c --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-var-6.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +int +f1 (void) +{ + int a; + int b; + int c; + int d; + int e; + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + return sizeof (a) + ((__typeof (b)) 1) + __alignof__ (c) + + __builtin_choose_expr (1, d, e); +} diff --git a/gcc/toplev.c b/gcc/toplev.c index 68a1b8c15ed1..798f0d493c61 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1796,6 +1796,12 @@ process_options (void) warn_unused_parameter = (warn_unused && extra_warnings); if (warn_unused_variable == -1) warn_unused_variable = warn_unused; + /* Wunused-but-set-parameter is enabled if both -Wunused -Wextra are + enabled. */ + if (warn_unused_but_set_parameter == -1) + warn_unused_but_set_parameter = (warn_unused && extra_warnings); + if (warn_unused_but_set_variable == -1) + warn_unused_but_set_variable = warn_unused; if (warn_unused_value == -1) warn_unused_value = warn_unused; diff --git a/gcc/tree.h b/gcc/tree.h index 4a0fb5e6405a..96c95758dd9a 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1317,6 +1317,9 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, (TREE_CHECK3 (NODE, VAR_DECL, PARM_DECL, \ RESULT_DECL)->decl_common.decl_restricted_flag) +#define DECL_READ_P(NODE) \ + (TREE_CHECK2 (NODE, VAR_DECL, PARM_DECL)->decl_common.decl_read_flag) + /* In a CALL_EXPR, means that the call is the jump from a thunk to the thunked-to function. */ #define CALL_FROM_THUNK_P(NODE) (CALL_EXPR_CHECK (NODE)->base.protected_flag) @@ -2691,8 +2694,12 @@ struct GTY(()) tree_decl_common { /* In VAR_DECL, PARM_DECL and RESULT_DECL, this is DECL_RESTRICTED_P. */ unsigned decl_restricted_flag : 1; + /* In VAR_DECL and PARM_DECL set when the decl has been used except for + being set. */ + unsigned decl_read_flag : 1; + /* Padding so that 'off_align' can be on a 32-bit boundary. */ - unsigned decl_common_unused : 2; + unsigned decl_common_unused : 1; /* DECL_OFFSET_ALIGN, used only for FIELD_DECLs. */ unsigned int off_align : 8; -- GitLab