OSDN Git Service

PR c/18624
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Apr 2010 20:33:36 +0000 (20:33 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Apr 2010 20:33:36 +0000 (20:33 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158086 138bc75d-0d04-0410-961f-82ee72b054a4

20 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/c-parser.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/common.opt
gcc/doc/invoke.texi
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wunused-parm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wunused-var-6.c [new file with mode: 0644]
gcc/toplev.c
gcc/tree.h

index 1f32f76..9db02bc 100644 (file)
@@ -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
index 7daba6b..32dc21e 100644 (file)
@@ -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);
index b6ff3f4..bc90fdd 100644 (file)
@@ -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;
index bf66a58..27f0b81 100644 (file)
@@ -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);
index dab9d39..3681ed7 100644 (file)
@@ -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);
index 89e534a..2296cbe 100644 (file)
@@ -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);
     }
index 49eb453..d5f00a0 100644 (file)
@@ -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
index d356daa..67a1b60 100644 (file)
@@ -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
index 3063af9..4307001 100644 (file)
@@ -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
index f5b754b..9e5fdb5 100644 (file)
@@ -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);
 
index b7fb0c5..d4ea278 100644 (file)
@@ -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 (file)
index 0000000..bddbd83
--- /dev/null
@@ -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 (file)
index 0000000..bee34d8
--- /dev/null
@@ -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 (file)
index 0000000..2818259
--- /dev/null
@@ -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 (file)
index 0000000..9b1fce7
--- /dev/null
@@ -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 (file)
index 0000000..d60dd70
--- /dev/null
@@ -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 (file)
index 0000000..747f58d
--- /dev/null
@@ -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 (file)
index 0000000..b5a22f8
--- /dev/null
@@ -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);
+}
index 68a1b8c..798f0d4 100644 (file)
@@ -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;
 
index 4a0fb5e..96c9575 100644 (file)
@@ -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;