This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to implement #include depth checking
- To: egcs-patches at egcs dot cygnus dot com
- Subject: Patch to implement #include depth checking
- From: Nick Clifton <nickc at cygnus dot com>
- Date: Thu, 8 Jul 1999 13:36:11 +0100
Hi Guys,
At the request of a Cygnus customer I have implemented a patch to
issue a warning if the nesting of #include files exceeds a given
number. The idea to help software project management by allowing a
limit to be set on the depth of inclusion nesting. The warnings are
not generated for system header files, and they can be suppressed,
if necessary, on a per header file basis by the use of a #pragma.
The patch works for both cpp and cpplib, and is pretty much self
contained in the preprocessor code.
What do you think - is this patch suitable for inclusion into EGCS ?
Cheers
Nick
Thu Jul 8 13:03:34 1999 Nick Clifton <nickc@cygnus.com>
* cccp.c (warn_if_include_depth_exceeds): New variable.
(print_help): Describe new command-line option
-Winclude-depth-exceeds.
(main): Parse -Winclude-depth-exceeds command-line option.
(finclude): Generate a warning if the inclusion depth exceeds
the limit set by -Winclude-depth-exceeds.
(do_pragma): Accept #pragma include_depth_check_off and
#pragma include_depth_check_on.
* cpp.texi: Document -Winclude-depth-exceeds command-line
option and the #pragmas associated with it.
* invoke.texi: Document -Winclude-depth-exceeds command-line
option and the #pragmas associated with it.
* cpplib.h (struct cpp_options): Define new fields:
warn_if_include_depth_exceeds, depth_warnings_triggered and
saved_warn_depth.
* cppinit.c (cpp_options_init): Initialise new fields in
struct cpp_options.
(cpp_handle_option): Parse -Winclude-depth-exceeds
command-line option.
(print_help): Describe new command-line option
-Winclude-depth-exceeds.
* cpplib.c (do_include): Generate a warning if the inclusion
depth exceeds the limit set by -Winclude-depth-exceeds.
(do_pragma): Accept #pragma include_depth_check_off and
#pragma include_depth_check_on.
* toplev.c (documented_lang_options): Add
-Winclude-depth-exceeds.
Index: cccp.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cccp.c,v
retrieving revision 1.70
diff -p -r1.70 cccp.c
*** cccp.c 1999/05/31 11:44:42 1.70
--- cccp.c 1999/07/08 12:26:19
*************** static int warn_import = 1;
*** 251,256 ****
--- 251,261 ----
static int warnings_are_errors;
+ /* Maximum inclusion nesting depth, before a warning is produced.
+ -1 means do not produce any warnings. This is the default. */
+
+ static int warn_if_include_depth_exceeds = -1;
+
/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */
int traditional;
*************** print_help ()
*** 1159,1164 ****
--- 1164,1170 ----
printf (" -Wno-undef Do not warn about testing undefined macros\n");
printf (" -Wimport Warn about the use of the #import directive\n");
printf (" -Wno-import Do not warn about the use of #import\n");
+ printf (" -Winclude-depth-exceeds=<n> Warn if #include files nest more than <n> levels\n");
printf (" -Werror Treat all warnings as errors\n");
printf (" -Wno-error Do not treat warnings as errors\n");
printf (" -Wall Enable all preprocessor warnings\n");
*************** main (argc, argv)
*** 1524,1529 ****
--- 1530,1545 ----
warnings_are_errors = 1;
else if (!strcmp (argv[i], "-Wno-error"))
warnings_are_errors = 0;
+ else if (!strncmp (argv[i], "-Winclude-depth-exceeds=", 24))
+ {
+ warn_if_include_depth_exceeds = atoi (argv[i] + 24);
+
+ if (warn_if_include_depth_exceeds == 0)
+ {
+ warning ("Bad value for '-Winclude-depth-exceeds' option - ignored");
+ warn_if_include_depth_exceeds = -1;
+ }
+ }
else if (!strcmp (argv[i], "-Wall"))
{
warn_trigraphs = 1;
*************** finclude (f, inc, op, system_header_p, d
*** 5283,5288 ****
--- 5299,5327 ----
indepth++;
input_file_stack_tick++;
+ if (warn_if_include_depth_exceeds != -1
+ && ! system_header_p)
+ {
+ /* In order to prevent a recursive inclusion loop from producing
+ reams of warnings, once we have produced a warning we disable
+ further warnings until the nesting depth drops below the depth
+ that triggered it. */
+ static int depth_warnings_triggered = -1;
+
+ if (depth_warnings_triggered != -1)
+ {
+ if (indepth < depth_warnings_triggered)
+ depth_warnings_triggered = -1;
+ }
+ else if (indepth > warn_if_include_depth_exceeds)
+ {
+ warning ("Inclusion depth (%d) exceeds limit set on command line (%d)",
+ indepth, warn_if_include_depth_exceeds);
+
+ depth_warnings_triggered = indepth;
+ }
+ }
+
if (!no_trigraphs)
trigraph_pcp (fp);
*************** do_pragma (buf, limit, op, keyword)
*** 7075,7112 ****
struct directive *keyword ATTRIBUTE_UNUSED;
{
SKIP_WHITE_SPACE (buf);
! if (!strncmp ((char *) buf, "once", 4)) {
! /* Allow #pragma once in system headers, since that's not the user's
! fault. */
! if (!instack[indepth].system_header_p)
! warning ("`#pragma once' is obsolete");
! do_once ();
! }
!
! if (!strncmp ((char *) buf, "implementation", 14)) {
! /* Be quiet about `#pragma implementation' for a file only if it hasn't
! been included yet. */
!
! int h;
! U_CHAR *p = buf + 14, *fname;
! SKIP_WHITE_SPACE (p);
! if (*p != '\"')
! return 0;
! fname = p + 1;
! if ((p = (U_CHAR *) index ((char *) fname, '\"')))
! *p = '\0';
!
! for (h = 0; h < INCLUDE_HASHSIZE; h++) {
! struct include_file *inc;
! for (inc = include_hashtab[h]; inc; inc = inc->next) {
! if (!strcmp (base_name (inc->fname), (char *) fname)) {
! warning ("`#pragma implementation' for \"%s\" appears after its #include",fname);
! return 0;
}
- }
}
}
return 0;
}
--- 7114,7177 ----
struct directive *keyword ATTRIBUTE_UNUSED;
{
SKIP_WHITE_SPACE (buf);
!
! if (!strncmp ((char *) buf, "once", 4))
! {
! /* Allow #pragma once in system headers, since that's not the user's
! fault. */
! if (!instack[indepth].system_header_p)
! warning ("`#pragma once' is obsolete");
! do_once ();
! }
! if (!strncmp ((char *) buf, "implementation", 14))
! {
! /* Be quiet about `#pragma implementation' for a file only if it hasn't
! been included yet. */
!
! int h;
! U_CHAR *p = buf + 14, *fname;
! SKIP_WHITE_SPACE (p);
! if (*p != '\"')
! return 0;
!
! fname = p + 1;
! if ((p = (U_CHAR *) index ((char *) fname, '\"')))
! *p = '\0';
!
! for (h = 0; h < INCLUDE_HASHSIZE; h++)
! {
! struct include_file *inc;
! for (inc = include_hashtab[h]; inc; inc = inc->next)
! {
! if (!strcmp (base_name (inc->fname), (char *) fname))
! {
! warning ("`#pragma implementation' for \"%s\" appears after its #include",fname);
! return 0;
! }
! }
}
}
+
+ {
+ static int saved_warn_depth = -2;
+
+ if (!strncmp ((char *) buf, "include_depth_check_off", 23))
+ {
+ saved_warn_depth = warn_if_include_depth_exceeds;
+ warn_if_include_depth_exceeds = -1;
+ }
+
+ if (!strncmp ((char *) buf, "include_depth_check_on", 22))
+ {
+ if (saved_warn_depth != -2)
+ {
+ warn_if_include_depth_exceeds = saved_warn_depth;
+ saved_warn_depth = -2;
+ }
+ }
}
+
return 0;
}
Index: cpp.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cpp.texi,v
retrieving revision 1.11
diff -p -r1.11 cpp.texi
*** cpp.texi 1999/06/14 17:21:43 1.11
--- cpp.texi 1999/07/08 12:26:20
*************** some old C programs contain such lines.
*** 2461,2468 ****
The ANSI standard specifies that the effect of the @samp{#pragma}
directive is implementation-defined. In the GNU C preprocessor,
@samp{#pragma} directives are not used, except for @samp{#pragma once}
! (@pxref{Once-Only}). However, they are left in the preprocessor output,
! so they are available to the compilation pass.
@findex #ident
The @samp{#ident} directive is supported for compatibility with certain
--- 2461,2469 ----
The ANSI standard specifies that the effect of the @samp{#pragma}
directive is implementation-defined. In the GNU C preprocessor,
@samp{#pragma} directives are not used, except for @samp{#pragma once}
! (@pxref{Once-Only}) and @samp{#pragma include_depth_check_@{on|off@}}.
! However, they are left in the preprocessor output, so they are available
! to the compilation pass.
@findex #ident
The @samp{#ident} directive is supported for compatibility with certain
*************** ANSI C@.
*** 2710,2715 ****
--- 2711,2723 ----
@item -Wundef
@findex -Wundef
Warn if an undefined identifier is evaluated in an @samp{#if} directive.
+
+ @item -Winclude-depth-exceeds=@samp{n}
+ @findex -Winclude-depth-exceeds
+ Warn if the number of nested levels of @samp{#include}d files exceeds
+ @samp{n}. This warning can be suppressed by @samp{#pragma
+ include_depth_check_off} and re-enabled by @samp{#pragma
+ include_depth_check_on}.
@item -I @var{directory}
@findex -I
Index: invoke.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/invoke.texi,v
retrieving revision 1.118
diff -p -r1.118 invoke.texi
*** invoke.texi 1999/07/05 08:44:30 1.118
--- invoke.texi 1999/07/08 12:26:23
*************** Only @samp{#define @var{name}} is includ
*** 2741,2746 ****
--- 2741,2753 ----
@item -trigraphs
Support ANSI C trigraphs. The @samp{-ansi} option also has this effect.
+ @item -Winclude-depth-exceeds=@samp{n}
+ @findex -Winclude-depth-exceeds
+ Warn if the number of nested levels of @samp{#include}d files exceeds
+ @samp{n}. This warning can be suppressed by @samp{#pragma
+ include_depth_check_off} and re-enabled by @samp{#pragma
+ include_depth_check_on}.
+
@item -Wp,@var{option}
Pass @var{option} as an option to the preprocessor. If @var{option}
contains commas, it is split into multiple options at the commas.
Index: cpplib.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cpplib.h,v
retrieving revision 1.38
diff -p -r1.38 cpplib.h
*** cpplib.h 1999/05/10 15:24:35 1.38
--- cpplib.h 1999/07/08 12:26:24
*************** struct cpp_options {
*** 411,416 ****
--- 411,434 ----
char warnings_are_errors;
+ /* Maximum inclusion nesting depth, before a warning is produced.
+ -1 means do not produce any warnings. This is the default. */
+
+ int warn_if_include_depth_exceeds;
+
+ /* In order to prevent a recursive inclusion loop from producing
+ reams of warnings, once we have produced a warning we disable
+ further warnings until the nesting depth drops below the depth
+ that triggered it. */
+
+ int depth_warnings_triggered;
+
+ /* In order to allow the depth warnings to be temporarily suppressed
+ (by a pragma), we need to be able to record the value of
+ warn_if_include_depth_exceeds when the suppresion occurs. */
+
+ int saved_warn_depth;
+
/* Nonzero causes output not to be done,
but directives such as #define that have side effects
are still obeyed. */
Index: cppinit.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cppinit.c,v
retrieving revision 1.14
diff -p -r1.14 cppinit.c
*** cppinit.c 1999/05/10 15:24:34 1.14
--- cppinit.c 1999/07/08 12:26:23
*************** cpp_options_init (opts)
*** 524,530 ****
opts->dollars_in_ident = 1;
opts->cplusplus_comments = 1;
opts->warn_import = 1;
!
opts->pending = (struct cpp_pending *) xmalloc (sizeof (struct cpp_pending));
bzero ((char *) opts->pending, sizeof (struct cpp_pending));
}
--- 524,533 ----
opts->dollars_in_ident = 1;
opts->cplusplus_comments = 1;
opts->warn_import = 1;
! opts->warn_if_include_depth_exceeds = -1;
! opts->depth_warnings_triggered = -1;
! opts->saved_warn_depth = -2;
!
opts->pending = (struct cpp_pending *) xmalloc (sizeof (struct cpp_pending));
bzero ((char *) opts->pending, sizeof (struct cpp_pending));
}
*************** cpp_handle_option (pfile, argc, argv)
*** 1430,1435 ****
--- 1433,1449 ----
opts->warnings_are_errors = 1;
else if (!strcmp (argv[i], "-Wno-error"))
opts->warnings_are_errors = 0;
+ else if (!strncmp (argv[i], "-Winclude-depth-exceeds=", 24))
+ {
+ opts->warn_if_include_depth_exceeds = atoi (argv[i] + 24);
+
+ if (opts->warn_if_include_depth_exceeds == 0)
+ {
+ cpp_warning (pfile, "\
+ Bad value for '-Winclude-depth-exceeds' option - ignored");
+ opts->warn_if_include_depth_exceeds = -1;
+ }
+ }
else if (!strcmp (argv[i], "-Wall"))
{
opts->warn_trigraphs = 1;
*************** Switches:\n\
*** 1749,1754 ****
--- 1763,1769 ----
-Wno-undef Do not warn about testing undefined macros\n\
-Wimport Warn about the use of the #import directive\n\
-Wno-import Do not warn about the use of #import\n\
+ -Winclude-depth-exceeds=<n> Warn if #include files nest more than <n> levels\n\
-Werror Treat all warnings as errors\n\
-Wno-error Do not treat warnings as errors\n\
-Wall Enable all preprocessor warnings\n\
Index: cpplib.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cpplib.c,v
retrieving revision 1.82
diff -p -r1.82 cpplib.c
*** cpplib.c 1999/06/07 10:35:26 1.82
--- cpplib.c 1999/07/08 12:26:24
*************** do_include (pfile, keyword)
*** 983,988 ****
--- 983,1010 ----
"#import is obsolete, use an #ifndef wrapper in the header file");
}
+ if (CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds != -1
+ && ! CPP_BUFFER (pfile)->system_header_p)
+ {
+ if (CPP_OPTIONS (pfile)->depth_warnings_triggered != -1)
+ {
+ if (pfile->buffer_stack_depth
+ < CPP_OPTIONS (pfile)->depth_warnings_triggered)
+ CPP_OPTIONS (pfile)->depth_warnings_triggered = -1;
+ }
+ else if (pfile->buffer_stack_depth
+ > CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds)
+ {
+ cpp_warning (pfile, "\
+ Inclusion depth (%d) exceeds limit set on command line (%d)",
+ pfile->buffer_stack_depth,
+ CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds);
+
+ CPP_OPTIONS (pfile)->depth_warnings_triggered =
+ pfile->buffer_stack_depth;
+ }
+ }
+
pfile->parsing_include_directive++;
token = get_directive_token (pfile);
pfile->parsing_include_directive--;
*************** do_pragma (pfile, keyword)
*** 1516,1521 ****
--- 1538,1558 ----
cpp_warning (pfile,
"`#pragma implementation' for `%s' appears after file is included",
fcopy);
+ }
+
+ if (!strncmp ((char *) buf, "include_depth_check_off", 23))
+ {
+ CPP_OPTIONS (pfile)->saved_warn_depth = CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds;
+ CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds = -1;
+ }
+
+ if (!strncmp ((char *) buf, "include_depth_check_on", 22))
+ {
+ if (CPP_OPTIONS (pfile)->saved_warn_depth != -2)
+ {
+ CPP_OPTIONS (pfile)->warn_if_include_depth_exceeds = CPP_OPTIONS (pfile)->saved_warn_depth;
+ CPP_OPTIONS (pfile)->saved_warn_depth = -2;
+ }
}
return 0;
Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.186
diff -p -r1.186 toplev.c
*** toplev.c 1999/05/20 10:37:00 1.186
--- toplev.c 1999/07/08 12:26:26
*************** documented_lang_options[] =
*** 1061,1066 ****
--- 1061,1067 ----
{ "-Wimplicit", "" },
{ "-Wno-implicit", "" },
{ "-Wimport", "Warn about the use of the #import directive" },
+ { "-Winclude-depth-exceeds", "Warn if #include files nest more than N levels" },
{ "-Wno-import", "" },
{ "-Wlong-long","" },
{ "-Wno-long-long", "Do not warn about using 'long long' when -pedantic" },