cppexp.c (parse_defined): Mark macro used.
authorNeil Booth <neil@daikokuya.co.uk>
Tue, 23 Jul 2002 22:57:49 +0000 (22:57 +0000)
committerNeil Booth <neil@gcc.gnu.org>
Tue, 23 Jul 2002 22:57:49 +0000 (22:57 +0000)
* cppexp.c (parse_defined): Mark macro used.
* cpphash.h (struct cpp_macro): New member "used".
(_cpp_mark_macro_used, _cpp_warn_if_unused_macro): New.
(struct cpp_reader): New member.
* cppinit.c (cpp_finish_options): Set first_unused_line.
(cpp_finish): Warn of unused macros if requested.
(OPT_TABLE): New switches.
(cpp_handle_option): Handle them.
* cpplib.c (do_undef): Warn if macro unused.
(do_ifdef, do_ifndef): Mark macro used.
* cpplib.h (struct cpp_options): New member.
* cppmacro.c (_cpp_warn_if_unused_macro): New.
(enter_macro_context): Mark macro used.
(_cpp_create_definition): Mark macro unused; warn if unused
when redefined.
* cpptrad.c (scan_out_logcial_line, push_replacement_text):
Mark macros used.
* doc/cppopts.texi: Update.
testsuite:
* gcc.dg/cpp/trad/Wunused.c, gcc.dg/cpp/trad/Wunused.h,
gcc.dg/cpp/Wunused.c, gcc.dg/cpp/Wunused.h: New tests.

From-SVN: r55692

14 files changed:
gcc/ChangeLog
gcc/cppexp.c
gcc/cpphash.h
gcc/cppinit.c
gcc/cpplib.c
gcc/cpplib.h
gcc/cppmacro.c
gcc/cpptrad.c
gcc/doc/cppopts.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/Wunused.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/Wunused.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/trad/Wunused.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/trad/Wunused.h [new file with mode: 0644]

index 15020ff..95afea0 100644 (file)
@@ -1,3 +1,24 @@
+2002-07-24  Neil Booth  <neil@daikokuya.co.uk>
+
+       * cppexp.c (parse_defined): Mark macro used.
+       * cpphash.h (struct cpp_macro): New member "used".
+       (_cpp_mark_macro_used, _cpp_warn_if_unused_macro): New.
+       (struct cpp_reader): New member.
+       * cppinit.c (cpp_finish_options): Set first_unused_line.
+       (cpp_finish): Warn of unused macros if requested.
+       (OPT_TABLE): New switches.
+       (cpp_handle_option): Handle them.
+       * cpplib.c (do_undef): Warn if macro unused.
+       (do_ifdef, do_ifndef): Mark macro used.
+       * cpplib.h (struct cpp_options): New member.
+       * cppmacro.c (_cpp_warn_if_unused_macro): New.
+       (enter_macro_context): Mark macro used.
+       (_cpp_create_definition): Mark macro unused; warn if unused
+       when redefined.
+       * cpptrad.c (scan_out_logcial_line, push_replacement_text):
+       Mark macros used.
+       * doc/cppopts.texi: Update.
+
 2002-07-23  Neil Booth  <neil@daikokuya.co.uk>
 
        * dwarf2out.c (SECTION_ASM_OP,
index b66fea9..5690436 100644 (file)
@@ -501,6 +501,8 @@ parse_defined (pfile)
        cpp_error (pfile, DL_WARNING,
                   "this use of \"defined\" may not be portable");
 
+      _cpp_mark_macro_used (node);
+
       /* A possible controlling macro of the form #if !defined ().
         _cpp_parse_expr checks there was no other junk on the line.  */
       pfile->mi_ind_cmacro = node;
index 133c9b9..5e69c85 100644 (file)
@@ -98,8 +98,15 @@ struct cpp_macro
 
   /* If macro defined in system header.  */
   unsigned int syshdr   : 1;
+
+  /* Non-zero if it has been expanded or had its existence tested.  */
+  unsigned int used     : 1;
 };
 
+#define _cpp_mark_macro_used(NODE) do {                                        \
+  if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN))     \
+    (NODE)->value.macro->used = 1; } while (0)
+
 /* A generic memory buffer, and operations on it.  */
 typedef struct _cpp_buff _cpp_buff;
 struct _cpp_buff
@@ -370,6 +377,9 @@ struct cpp_reader
      for include files.  (Altered as we get more of them.)  */
   unsigned int max_include_len;
 
+  /* Macros on or after this line are warned about if unused.  */
+  unsigned int first_unused_line;
+
   /* Date and time text.  Calculated together if either is requested.  */
   const uchar *date;
   const uchar *time;
@@ -477,6 +487,8 @@ extern bool _cpp_arguments_ok               PARAMS ((cpp_reader *, cpp_macro *,
                                                 unsigned int));
 extern const uchar *_cpp_builtin_macro_text PARAMS ((cpp_reader *,
                                                     cpp_hashnode *));
+int _cpp_warn_if_unused_macro          PARAMS ((cpp_reader *, cpp_hashnode *,
+                                                void *));
 /* In cpphash.c */
 extern void _cpp_init_hashtable                PARAMS ((cpp_reader *, hash_table *));
 extern void _cpp_destroy_hashtable     PARAMS ((cpp_reader *));
index a6be4aa..6a4dd0a 100644 (file)
@@ -1009,6 +1009,8 @@ cpp_finish_options (pfile)
       _cpp_maybe_push_include_file (pfile);
     }
 
+  pfile->first_unused_line = pfile->line;
+
   free_chain (CPP_OPTION (pfile, pending)->imacros_head);
   free_chain (CPP_OPTION (pfile, pending)->directive_head);
 }
@@ -1081,6 +1083,10 @@ void
 cpp_finish (pfile)
      cpp_reader *pfile;
 {
+  /* Warn about unused macros before popping the final buffer.  */
+  if (CPP_OPTION (pfile, warn_unused_macros))
+    cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
+
   /* cpplex.c leaves the final buffer on the stack.  This it so that
      it returns an unending stream of CPP_EOFs to the client.  If we
      popped the buffer, we'd dereference a NULL buffer pointer and
@@ -1165,10 +1171,12 @@ new_pending_directive (pend, text, handler)
   DEF_OPT("Wno-traditional",          0,      OPT_Wno_traditional)            \
   DEF_OPT("Wno-trigraphs",            0,      OPT_Wno_trigraphs)              \
   DEF_OPT("Wno-undef",                0,      OPT_Wno_undef)                  \
+  DEF_OPT("Wno-unused-macros",        0,      OPT_Wno_unused_macros)          \
   DEF_OPT("Wsystem-headers",          0,      OPT_Wsystem_headers)            \
   DEF_OPT("Wtraditional",             0,      OPT_Wtraditional)               \
   DEF_OPT("Wtrigraphs",               0,      OPT_Wtrigraphs)                 \
   DEF_OPT("Wundef",                   0,      OPT_Wundef)                     \
+  DEF_OPT("Wunused-macros",           0,      OPT_Wunused_macros)             \
   DEF_OPT("d",                        no_arg, OPT_d)                          \
   DEF_OPT("fno-operator-names",       0,      OPT_fno_operator_names)         \
   DEF_OPT("fno-preprocessed",         0,      OPT_fno_preprocessed)           \
@@ -1692,6 +1700,13 @@ cpp_handle_option (pfile, argc, argv)
          CPP_OPTION (pfile, warn_comments) = 0;
          break;
 
+       case OPT_Wunused_macros:
+         CPP_OPTION (pfile, warn_unused_macros) = 1;
+         break;
+       case OPT_Wno_unused_macros:
+         CPP_OPTION (pfile, warn_unused_macros) = 0;
+         break;
+
        case OPT_Wundef:
          CPP_OPTION (pfile, warn_undef) = 1;
          break;
index c87572a..935a0e0 100644 (file)
@@ -545,6 +545,9 @@ do_undef (pfile)
       if (node->flags & NODE_WARN)
        cpp_error (pfile, DL_WARNING, "undefining \"%s\"", NODE_NAME (node));
 
+      if (CPP_OPTION (pfile, warn_unused_macros))
+       _cpp_warn_if_unused_macro (pfile, node, NULL);
+
       _cpp_free_definition (node);
     }
   check_eol (pfile);
@@ -1331,10 +1334,11 @@ do_ifdef (pfile)
       const cpp_hashnode *node = lex_macro_node (pfile);
 
       if (node)
-       skip = node->type != NT_MACRO;
-
-      if (node)
-       check_eol (pfile);
+       {
+         skip = node->type != NT_MACRO;
+         _cpp_mark_macro_used (node);
+         check_eol (pfile);
+       }
     }
 
   push_conditional (pfile, skip, T_IFDEF, 0);
@@ -1351,11 +1355,13 @@ do_ifndef (pfile)
   if (! pfile->state.skipping)
     {
       node = lex_macro_node (pfile);
-      if (node)
-       skip = node->type == NT_MACRO;
 
       if (node)
-       check_eol (pfile);
+       {
+         skip = node->type == NT_MACRO;
+         _cpp_mark_macro_used (node);
+         check_eol (pfile);
+       }
     }
 
   push_conditional (pfile, skip, T_IFNDEF, node);
index c407321..8902f53 100644 (file)
@@ -361,6 +361,9 @@ struct cpp_options
   /* Nonzero means warn if undefined identifiers are evaluated in an #if.  */
   unsigned char warn_undef;
 
+  /* Nonzero means warn of unused macros from the main file.  */
+  unsigned char warn_unused_macros;
+
   /* Nonzero for the 1999 C Standard, including corrigenda and amendments.  */
   unsigned char c99;
 
index 4d807a2..c8e2410 100644 (file)
@@ -74,6 +74,29 @@ static void check_trad_stringification PARAMS ((cpp_reader *,
                                                const cpp_macro *,
                                                const cpp_string *));
 
+/* Emits a warning if NODE is a macro defined in the main file that
+   has not been used.  */
+int
+_cpp_warn_if_unused_macro (pfile, node, v)
+     cpp_reader *pfile;
+     cpp_hashnode *node;
+     void *v ATTRIBUTE_UNUSED;
+{
+  if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
+    {
+      cpp_macro *macro = node->value.macro;
+
+      if (!macro->used
+         /* Skip front-end built-ins and command line macros.  */
+         && macro->line >= pfile->first_unused_line
+         && MAIN_FILE_P (lookup_line (&pfile->line_maps, macro->line)))
+       cpp_error_with_line (pfile, DL_WARNING, macro->line, 0,
+                            "macro \"%s\" is not used", NODE_NAME (node));
+    }
+
+  return 1;
+}
+
 /* Allocates and returns a CPP_STRING token, containing TEXT of length
    LEN, after null-terminating it.  TEXT must be in permanent storage.  */
 static const cpp_token *
@@ -728,6 +751,8 @@ enter_macro_context (pfile, node)
       /* Disable the macro within its expansion.  */
       node->flags |= NODE_DISABLED;
 
+      macro->used = 1;
+
       if (macro->paramc == 0)
        push_token_context (pfile, node, macro->exp.tokens, macro->count);
 
@@ -1488,6 +1513,7 @@ _cpp_create_definition (pfile, node)
   macro->params = 0;
   macro->paramc = 0;
   macro->variadic = 0;
+  macro->used = 0;
   macro->count = 0;
   macro->fun_like = 0;
   /* To suppress some diagnostics.  */
@@ -1523,6 +1549,9 @@ _cpp_create_definition (pfile, node)
 
   if (node->type != NT_VOID)
     {
+      if (CPP_OPTION (pfile, warn_unused_macros))
+       _cpp_warn_if_unused_macro (pfile, node, NULL);
+
       if (warn_of_redefinition (pfile, node, macro))
        {
          cpp_error_with_line (pfile, DL_PEDWARN, pfile->directive_line, 0,
index e8b5a1e..51b0bfc 100644 (file)
@@ -655,6 +655,7 @@ scan_out_logical_line (pfile, macro)
                {
                  cpp_macro *m = fmacro.node->value.macro;
 
+                 m->used = 1;
                  lex_state = ls_none;
                  save_argument (&fmacro, out - pfile->out.base);
 
@@ -789,6 +790,7 @@ push_replacement_text (pfile, node)
   else
     {
       cpp_macro *macro = node->value.macro;
+      macro->used = 1;
       text = macro->exp.text;
       len = macro->count;
     }
index 6fb3b53..24c6edd 100644 (file)
@@ -110,6 +110,16 @@ Warn whenever an identifier which is not a macro is encountered in an
 @samp{#if} directive, outside of @samp{defined}.  Such identifiers are
 replaced with zero.
 
+@item -Wunused-macros
+@opindex Wunused-macros
+Warn about macros defined in the main file that are unused.  A macro
+is @dfn{used} if it is expanded or tested for existence at least once.
+The preprocessor will also warn if the macro has not been used at the
+time it is redefined or undefined.
+
+Built-in macros, macros defined on the command line, and macros
+defined in include files are not warned about.
+
 @item -Wendif-labels
 @opindex Wendif-labels
 Warn whenever an @samp{#else} or an @samp{#endif} are followed by text.
index df3fa02..b374250 100644 (file)
@@ -1,3 +1,8 @@
+2002-07-24  Neil Booth  <neil@daikokuya.co.uk>
+
+       * gcc.dg/cpp/trad/Wunused.c, gcc.dg/cpp/trad/Wunused.h,
+       gcc.dg/cpp/Wunused.c, gcc.dg/cpp/Wunused.h: New tests.
+
 2002-07-23  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * gcc.c-torture/execute/va-arg-15.x, va-arg-16.x, va-arg-17.x:
diff --git a/gcc/testsuite/gcc.dg/cpp/Wunused.c b/gcc/testsuite/gcc.dg/cpp/Wunused.c
new file mode 100644 (file)
index 0000000..f134f55
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options -Wunused-macros } */
+
+/* Test everything related to -Wunused-macros.
+
+   Source: Neil Booth, 23 Jul 2002.  */
+
+#include "Wunused.h"
+
+#define used1                  /* { dg-bogus "used" } */
+#define used2                  /* { dg-bogus "used" } */
+#define used3                  /* { dg-bogus "used" } */
+#define used4 used4            /* { dg-bogus "used" } */
+
+#define unused5                        /* { dg-warning "used" } */
+#define unused6                        /* { dg-warning "used" } */
+#define unused7()              /* { dg-warning "used" } */
+
+#if defined used1
+#endif
+#ifdef used2
+#endif
+#ifndef used3
+#endif
+used4
+
+unused7
+#undef unused5
+#define unused6
+unused6
diff --git a/gcc/testsuite/gcc.dg/cpp/Wunused.h b/gcc/testsuite/gcc.dg/cpp/Wunused.h
new file mode 100644 (file)
index 0000000..8b54412
--- /dev/null
@@ -0,0 +1 @@
+#define unused_but_ok
diff --git a/gcc/testsuite/gcc.dg/cpp/trad/Wunused.c b/gcc/testsuite/gcc.dg/cpp/trad/Wunused.c
new file mode 100644 (file)
index 0000000..fd81a27
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-Wunused-macros -traditional-cpp" } */
+
+/* Test everything related to -Wunused-macros.
+
+   Source: Neil Booth, 23 Jul 2002.  */
+
+#include "Wunused.h"
+
+#define used1                  /* { dg-bogus "used" } */
+#define used2                  /* { dg-bogus "used" } */
+#define used3                  /* { dg-bogus "used" } */
+#define used4 something                /* { dg-bogus "used" } */
+
+#define unused5                        /* { dg-warning "used" } */
+#define unused6                        /* { dg-warning "used" } */
+#define unused7()              /* { dg-warning "used" } */
+
+#if defined used1
+#endif
+#ifdef used2
+#endif
+#ifndef used3
+#endif
+used4
+
+#undef unused5
+#define unused6
+unused6
diff --git a/gcc/testsuite/gcc.dg/cpp/trad/Wunused.h b/gcc/testsuite/gcc.dg/cpp/trad/Wunused.h
new file mode 100644 (file)
index 0000000..8b54412
--- /dev/null
@@ -0,0 +1 @@
+#define unused_but_ok