From a69cbaac60d73feb37e6c17abd6f84991dc791a0 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Tue, 23 Jul 2002 22:57:49 +0000 Subject: [PATCH] cppexp.c (parse_defined): Mark macro used. * 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 --- gcc/ChangeLog | 21 ++++++++++++++++ gcc/cppexp.c | 2 ++ gcc/cpphash.h | 12 ++++++++++ gcc/cppinit.c | 15 ++++++++++++ gcc/cpplib.c | 20 ++++++++++------ gcc/cpplib.h | 3 +++ gcc/cppmacro.c | 29 ++++++++++++++++++++++ gcc/cpptrad.c | 2 ++ gcc/doc/cppopts.texi | 10 ++++++++ gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.dg/cpp/Wunused.c | 32 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/cpp/Wunused.h | 1 + gcc/testsuite/gcc.dg/cpp/trad/Wunused.c | 31 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/cpp/trad/Wunused.h | 1 + 14 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cpp/Wunused.c create mode 100644 gcc/testsuite/gcc.dg/cpp/Wunused.h create mode 100644 gcc/testsuite/gcc.dg/cpp/trad/Wunused.c create mode 100644 gcc/testsuite/gcc.dg/cpp/trad/Wunused.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 15020fff59c..95afea08c82 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2002-07-24 Neil Booth + + * 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 * dwarf2out.c (SECTION_ASM_OP, diff --git a/gcc/cppexp.c b/gcc/cppexp.c index b66fea925e7..569043651d6 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -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; diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 133c9b93015..5e69c853b98 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -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 *)); diff --git a/gcc/cppinit.c b/gcc/cppinit.c index a6be4aa6736..6a4dd0a53f8 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -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; diff --git a/gcc/cpplib.c b/gcc/cpplib.c index c87572aba12..935a0e0b882 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -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); diff --git a/gcc/cpplib.h b/gcc/cpplib.h index c407321ff43..8902f536902 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -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; diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index 4d807a226ad..c8e2410af61 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -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, diff --git a/gcc/cpptrad.c b/gcc/cpptrad.c index e8b5a1e638d..51b0bfc9cb5 100644 --- a/gcc/cpptrad.c +++ b/gcc/cpptrad.c @@ -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; } diff --git a/gcc/doc/cppopts.texi b/gcc/doc/cppopts.texi index 6fb3b53f157..24c6edd238d 100644 --- a/gcc/doc/cppopts.texi +++ b/gcc/doc/cppopts.texi @@ -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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index df3fa02f844..b3742503184 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-07-24 Neil Booth + + * 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 * 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 index 00000000000..f134f55a159 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/Wunused.c @@ -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 index 00000000000..8b54412bdd4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/Wunused.h @@ -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 index 00000000000..fd81a27ecc7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/trad/Wunused.c @@ -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 index 00000000000..8b54412bdd4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/trad/Wunused.h @@ -0,0 +1 @@ +#define unused_but_ok -- 2.30.2