Message ID | 201006112128.o5BLSUlN026878@greed.delorie.com |
---|---|
State | New |
Headers | show |
The lively conversation came to an abrupt end about a week ago, right after I submitted a revised patch: http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01255.html
On 19 June 2010 02:30, DJ Delorie <dj@redhat.com> wrote: > > The lively conversation came to an abrupt end about a week ago, right > after I submitted a revised patch: > > http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01255.html As far as I see, the only remaining thing is someone with approval-powers to approve the patch. Cheers, Manuel.
On Fri, Jun 18, 2010 at 7:30 PM, DJ Delorie <dj@redhat.com> wrote: > > The lively conversation came to an abrupt end about a week ago, right > after I submitted a revised patch: > > http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01255.html > I wish diagnostic kind enumeration weren't overloaded with DK_POP. But I guess we can worry about that later with the understanding this particular case is not meant to start a competition :-) Patch OK; thanks! -- Gaby
On Sat, Jun 19, 2010 at 7:25 AM, Manuel López-Ibáñez <lopezibanez@gmail.com> wrote: > On 19 June 2010 02:30, DJ Delorie <dj@redhat.com> wrote: >> >> The lively conversation came to an abrupt end about a week ago, right >> after I submitted a revised patch: >> >> http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01255.html > > As far as I see, the only remaining thing is someone with > approval-powers to approve the patch. > thanks for the ping. -- Gaby
> I wish diagnostic kind enumeration weren't overloaded with DK_POP. > But I guess we can worry about that later with the understanding this > particular case is not meant to start a competition :-) Yeah, it was that or add another field to the struct, and I figured there would be a lot of those in the chain if people start abusing the pragma. > Patch OK; thanks! Committed. Whew, another LONG term project done :-)
On 21 June 2010 23:03, DJ Delorie <dj@redhat.com> wrote: > >> I wish diagnostic kind enumeration weren't overloaded with DK_POP. >> But I guess we can worry about that later with the understanding this >> particular case is not meant to start a competition :-) > > Yeah, it was that or add another field to the struct, and I figured > there would be a lot of those in the chain if people start abusing the > pragma. > >> Patch OK; thanks! > > Committed. Whew, another LONG term project done :-) Nice! A note in: http://gcc.gnu.org/gcc-4.6/changes.html would make this new feature more visible to users. Cheers, Manuel.
> http://gcc.gnu.org/gcc-4.6/changes.html > > would make this new feature more visible to users. Try as I might, I could not find anywhere on the gcc web site that said how to commit patches to the gcc web site itself... or even check out the tree so you could *make* patches.
On Mon, Jun 21, 2010 at 11:50 PM, DJ Delorie <dj@redhat.com> wrote: > >> http://gcc.gnu.org/gcc-4.6/changes.html >> >> would make this new feature more visible to users. > > Try as I might, I could not find anywhere on the gcc web site that > said how to commit patches to the gcc web site itself... or even > check out the tree so you could *make* patches. > http://gcc.gnu.org/about.html Ciao! Steven
> http://gcc.gnu.org/about.html
Totally non-obvious! I kept looking under "Contributing..." or
"FAQ..." or "Wiki..." or "SVN write access..."
Why would a link called "The GCC Team" talk about cvs access? Why
would a page called "About" be linked via text that reads "The GCC
Team"?
/me suspects more patches will come of this... ;-)
Thanks for the link, though.
On 21 June 2010 23:58, DJ Delorie <dj@redhat.com> wrote: > >> http://gcc.gnu.org/about.html > > Totally non-obvious! I kept looking under "Contributing..." or > "FAQ..." or "Wiki..." or "SVN write access..." > > Why would a link called "The GCC Team" talk about cvs access? Why > would a page called "About" be linked via text that reads "The GCC > Team"? > > /me suspects more patches will come of this... ;-) > > Thanks for the link, though. Actually, there is: http://gcc.gnu.org/contribute.html#webchanges and if you go a bit down, you find the SVN access link: http://gcc.gnu.org/svn.html which links to: http://gcc.gnu.org/cvs.html An improvement would be to link to the last one from the first one. A better fix would be to convert the CVS repo to SVN. I have heard that this requires updating some scripts but I don't know which scripts or where to find them. Cheers, Manuel.
What happened with this? Manuel. On 11 June 2010 23:28, DJ Delorie <dj@redhat.com> wrote: > >> I forgot to mention: at the very least I think the diagnostic routines >> should take the location as a parameter. If we must use input_location, >> let it be in the callers. > > I did it that way. I assume there are FAR more callers of pragma_lex() > than the three diagnostic*() calls here. > > > * diagnostic.h (diagnostic_classification_change_t): New. > (diagnostic_context): Add history and push/pop list. > (diagnostic_push_diagnostics): Declare. > (diagnostic_pop_diagnostics): Declare. > * diagnostic.c (diagnostic_classify_diagnostic): Store changes > from pragmas in a history chain instead of the global table. > (diagnostic_push_diagnostics): New. > (diagnostic_pop_diagnostics): New. > (diagnostic_report_diagnostic): Scan history chain to find state > of diagnostics as of the diagnostic location. > * opts.c (set_option): Pass UNKNOWN_LOCATION to > diagnostic_classify_diagnostic. > (enable_warning_as_error): Likewise. > * diagnostic-core.h (DK_POP): Add after "real" diagnostics, for > use in the history chain. > * c-family/c-pragma.c (handle_pragma_diagnostic): Add push/pop, > allow these pragmas anywhere. > * doc/extend.texi: Document pragma GCC diagnostic changes. > > * gcc.dg/pragma-diag-1.c: New. > > Index: doc/extend.texi > =================================================================== > --- doc/extend.texi (revision 160588) > +++ doc/extend.texi (working copy) > @@ -12587,21 +12587,36 @@ option. > @example > #pragma GCC diagnostic warning "-Wformat" > #pragma GCC diagnostic error "-Wformat" > #pragma GCC diagnostic ignored "-Wformat" > @end example > > -Note that these pragmas override any command-line options. Also, > -while it is syntactically valid to put these pragmas anywhere in your > -sources, the only supported location for them is before any data or > -functions are defined. Doing otherwise may result in unpredictable > -results depending on how the optimizer manages your sources. If the > -same option is listed multiple times, the last one specified is the > -one that is in effect. This pragma is not intended to be a general > -purpose replacement for command-line options, but for implementing > -strict control over project policies. > +Note that these pragmas override any command-line options. GCC keeps > +track of the location of each pragma, and issues diagnostics according > +to the state as of that point in the source file. Thus, pragmas occurring > +after a line do not affect diagnostics caused by that line. > + > +@item #pragma GCC diagnostic push > +@itemx #pragma GCC diagnostic pop > + > +Causes GCC to remember the state of the diagnostics as of each > +@code{push}, and restore to that point at each @code{pop}. If a > +@code{pop} has no matching @code{push}, the command line options are > +restored. > + > +@example > +#pragma GCC diagnostic error "-Wuninitialized" > + foo(a); /* error is given for this one */ > +#pragma GCC diagnostic push > +#pragma GCC diagnostic ignored "-Wuninitialized" > + foo(b); /* no diagnostic for this one */ > +#pragma GCC diagnostic pop > + foo(c); /* error is given for this one */ > +#pragma GCC diagnostic pop > + foo(d); /* depends on command line options */ > +@end example > > @end table > > GCC also offers a simple mechanism for printing messages during > compilation. > > Index: c-family/c-pragma.c > =================================================================== > --- c-family/c-pragma.c (revision 160588) > +++ c-family/c-pragma.c (working copy) > @@ -703,40 +703,44 @@ handle_pragma_diagnostic(cpp_reader *ARG > const char *kind_string, *option_string; > unsigned int option_index; > enum cpp_ttype token; > diagnostic_t kind; > tree x; > > - if (cfun) > - { > - error ("#pragma GCC diagnostic not allowed inside functions"); > - return; > - } > - > token = pragma_lex (&x); > if (token != CPP_NAME) > GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>"); > kind_string = IDENTIFIER_POINTER (x); > if (strcmp (kind_string, "error") == 0) > kind = DK_ERROR; > else if (strcmp (kind_string, "warning") == 0) > kind = DK_WARNING; > else if (strcmp (kind_string, "ignored") == 0) > kind = DK_IGNORED; > + else if (strcmp (kind_string, "push") == 0) > + { > + diagnostic_push_diagnostics (global_dc, input_location); > + return; > + } > + else if (strcmp (kind_string, "pop") == 0) > + { > + diagnostic_pop_diagnostics (global_dc, input_location); > + return; > + } > else > - GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>"); > + GCC_BAD ("expected [error|warning|ignored|push|pop] after %<#pragma GCC diagnostic%>"); > > token = pragma_lex (&x); > if (token != CPP_STRING) > GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind"); > option_string = TREE_STRING_POINTER (x); > for (option_index = 0; option_index < cl_options_count; option_index++) > if (strcmp (cl_options[option_index].opt_text, option_string) == 0) > { > /* This overrides -Werror, for example. */ > - diagnostic_classify_diagnostic (global_dc, option_index, kind); > + diagnostic_classify_diagnostic (global_dc, option_index, kind, input_location); > /* This makes sure the option is enabled, like -Wfoo would do. */ > if (cl_options[option_index].var_type == CLVC_BOOLEAN > && cl_options[option_index].flag_var > && kind != DK_IGNORED) > *(int *) cl_options[option_index].flag_var = 1; > return; > Index: diagnostic.c > =================================================================== > --- diagnostic.c (revision 160588) > +++ diagnostic.c (working copy) > @@ -303,26 +303,83 @@ default_diagnostic_finalizer (diagnostic > /* Interface to specify diagnostic kind overrides. Returns the > previous setting, or DK_UNSPECIFIED if the parameters are out of > range. */ > diagnostic_t > diagnostic_classify_diagnostic (diagnostic_context *context, > int option_index, > - diagnostic_t new_kind) > + diagnostic_t new_kind, > + location_t where) > { > diagnostic_t old_kind; > > if (option_index <= 0 > || option_index >= context->n_opts > || new_kind >= DK_LAST_DIAGNOSTIC_KIND) > return DK_UNSPECIFIED; > > old_kind = context->classify_diagnostic[option_index]; > - context->classify_diagnostic[option_index] = new_kind; > + > + /* Handle pragmas separately, since we need to keep track of *where* > + the pragmas were. */ > + if (where != UNKNOWN_LOCATION) > + { > + int i; > + > + for (i = context->n_classification_history - 1; i >= 0; i --) > + if (context->classification_history[i].option == option_index) > + { > + old_kind = context->classification_history[i].kind; > + break; > + } > + > + i = context->n_classification_history; > + context->classification_history = > + (diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1) > + * sizeof (diagnostic_classification_change_t)); > + context->classification_history[i].location = where; > + context->classification_history[i].option = option_index; > + context->classification_history[i].kind = new_kind; > + context->n_classification_history ++; > + } > + else > + context->classify_diagnostic[option_index] = new_kind; > + > return old_kind; > } > > +/* Save all diagnostic classifications in a stack. */ > +void > +diagnostic_push_diagnostics (diagnostic_context *context, location_t where ATTRIBUTE_UNUSED) > +{ > + context->push_list = (int *) xrealloc (context->push_list, (context->n_push + 1) * sizeof (int)); > + context->push_list[context->n_push ++] = context->n_classification_history; > +} > + > +/* Restore the topmost classification set off the stack. If the stack > + is empty, revert to the state based on command line parameters. */ > +void > +diagnostic_pop_diagnostics (diagnostic_context *context, location_t where) > +{ > + int jump_to; > + int i; > + > + if (context->n_push) > + jump_to = context->push_list [-- context->n_push]; > + else > + jump_to = 0; > + > + i = context->n_classification_history; > + context->classification_history = > + (diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1) > + * sizeof (diagnostic_classification_change_t)); > + context->classification_history[i].location = where; > + context->classification_history[i].option = jump_to; > + context->classification_history[i].kind = DK_POP; > + context->n_classification_history ++; > +} > + > /* Report a diagnostic message (an error or a warning) as specified by > DC. This function is *the* subroutine in terms of which front-ends > should implement their specific diagnostic handling modules. The > front-end independent format specifiers are exactly those described > in the documentation of output_format. > Return true if a diagnostic was printed, false otherwise. */ > @@ -371,19 +428,47 @@ diagnostic_report_diagnostic (diagnostic > { > diagnostic->kind = DK_ERROR; > } > > if (diagnostic->option_index) > { > + diagnostic_t diag_class = DK_UNSPECIFIED; > + > /* This tests if the user provided the appropriate -Wfoo or > -Wno-foo option. */ > if (! context->option_enabled (diagnostic->option_index)) > return false; > + > + /* This tests for #pragma diagnostic changes. */ > + if (context->n_classification_history > 0) > + { > + int i; > + /* FIXME: Stupid search. Optimize later. */ > + for (i = context->n_classification_history - 1; i >= 0; i --) > + { > + if (context->classification_history[i].location <= location) > + { > + if (context->classification_history[i].kind == (int) DK_POP) > + { > + i = context->classification_history[i].option; > + continue; > + } > + if (context->classification_history[i].option == diagnostic->option_index) > + { > + diag_class = context->classification_history[i].kind; > + if (diag_class != DK_UNSPECIFIED) > + diagnostic->kind = diag_class; > + break; > + } > + } > + } > + } > /* This tests if the user provided the appropriate -Werror=foo > option. */ > - if (context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED) > + if (diag_class == DK_UNSPECIFIED > + && context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED) > { > diagnostic->kind = context->classify_diagnostic[diagnostic->option_index]; > } > /* This allows for future extensions, like temporarily disabling > warnings for ranges of source code. */ > if (diagnostic->kind == DK_IGNORED) > Index: diagnostic.h > =================================================================== > --- diagnostic.h (revision 160588) > +++ diagnostic.h (working copy) > @@ -38,12 +38,22 @@ typedef struct diagnostic_info > /* The kind of diagnostic it is about. */ > diagnostic_t kind; > /* Which OPT_* directly controls this diagnostic. */ > int option_index; > } diagnostic_info; > > +/* Each time a diagnostic's classification is changed with a pragma, > + we record the change and the location of the change in an array of > + these structs. */ > +typedef struct diagnostic_classification_change_t > +{ > + location_t location; > + int option; > + diagnostic_t kind; > +} diagnostic_classification_change_t; > + > /* Forward declarations. */ > typedef struct diagnostic_context diagnostic_context; > typedef void (*diagnostic_starter_fn) (diagnostic_context *, > diagnostic_info *); > typedef diagnostic_starter_fn diagnostic_finalizer_fn; > > @@ -73,12 +83,26 @@ struct diagnostic_context > options), this array may contain a new kind that the diagnostic > should be changed to before reporting, or DK_UNSPECIFIED to leave > it as the reported kind, or DK_IGNORED to not report it at > all. */ > diagnostic_t *classify_diagnostic; > > + /* History of all changes to the classifications above. This list > + is stored in location-order, so we can search it, either > + binary-wise or end-to-front, to find the most recent > + classification for a given diagnostic, given the location of the > + diagnostic. */ > + diagnostic_classification_change_t *classification_history; > + > + /* The size of the above array. */ > + int n_classification_history; > + > + /* For pragma push/pop. */ > + int *push_list; > + int n_push; > + > /* True if we should print the command line option which controls > each diagnostic, if known. */ > bool show_option_requested; > > /* True if we should raise a SIGABRT on errors. */ > bool abort_on_error; > @@ -225,13 +249,16 @@ extern void diagnostic_initialize (diagn > extern void diagnostic_finish (diagnostic_context *); > extern void diagnostic_report_current_module (diagnostic_context *); > > /* Force diagnostics controlled by OPTIDX to be kind KIND. */ > extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *, > int /* optidx */, > - diagnostic_t /* kind */); > + diagnostic_t /* kind */, > + location_t); > +extern void diagnostic_push_diagnostics (diagnostic_context *, location_t); > +extern void diagnostic_pop_diagnostics (diagnostic_context *, location_t); > extern bool diagnostic_report_diagnostic (diagnostic_context *, > diagnostic_info *); > #ifdef ATTRIBUTE_GCC_DIAG > extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *, > location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0); > extern void diagnostic_set_info_translated (diagnostic_info *, const char *, > Index: diagnostic-core.h > =================================================================== > --- diagnostic-core.h (revision 160588) > +++ diagnostic-core.h (working copy) > @@ -29,13 +29,16 @@ along with GCC; see the file COPYING3. > /* Constants used to discriminate diagnostics. */ > typedef enum > { > #define DEFINE_DIAGNOSTIC_KIND(K, msgid) K, > #include "diagnostic.def" > #undef DEFINE_DIAGNOSTIC_KIND > - DK_LAST_DIAGNOSTIC_KIND > + DK_LAST_DIAGNOSTIC_KIND, > + /* This is used for tagging pragma pops in the diagnostic > + classification history chain. */ > + DK_POP > } diagnostic_t; > > extern const char *progname; > > extern const char *trim_filename (const char *); > > Index: testsuite/gcc.dg/pragma-diag-1.c > =================================================================== > --- testsuite/gcc.dg/pragma-diag-1.c (revision 0) > +++ testsuite/gcc.dg/pragma-diag-1.c (revision 0) > @@ -0,0 +1,21 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wuninitialized -O2" } */ > +/* { dg-message "warnings being treated as errors" "" {target "*-*-*"} 0 } */ > + > +main() > +{ > + int a; > + int b; > + int c; > + int d; > + > +#pragma GCC diagnostic error "-Wuninitialized" > + foo(a); /* { dg-error "uninitialized" } */ > +#pragma GCC diagnostic push > +#pragma GCC diagnostic ignored "-Wuninitialized" > + foo(b); > +#pragma GCC diagnostic pop > + foo(c); /* { dg-error "uninitialized" } */ > +#pragma GCC diagnostic pop > + foo(d); /* { dg-warning "uninitialized" } */ > +} > Index: opts.c > =================================================================== > --- opts.c (revision 160588) > +++ opts.c (working copy) > @@ -2473,13 +2473,14 @@ set_option (int opt_index, int value, co > case CLVC_STRING: > *(const char **) option->flag_var = arg; > break; > } > > if ((diagnostic_t)kind != DK_UNSPECIFIED) > - diagnostic_classify_diagnostic (global_dc, opt_index, (diagnostic_t)kind); > + diagnostic_classify_diagnostic (global_dc, opt_index, (diagnostic_t)kind, > + UNKNOWN_LOCATION); > } > > > /* Callback function, called when -Werror= enables a warning. */ > > static void (*warning_as_error_callback) (int) = NULL; > @@ -2511,13 +2512,14 @@ enable_warning_as_error (const char *arg > error ("-Werror=%s: No option -%s", arg, new_option); > } > else > { > const diagnostic_t kind = value ? DK_ERROR : DK_WARNING; > > - diagnostic_classify_diagnostic (global_dc, option_index, kind); > + diagnostic_classify_diagnostic (global_dc, option_index, kind, > + UNKNOWN_LOCATION); > if (kind == DK_ERROR) > { > const struct cl_option * const option = cl_options + option_index; > > /* -Werror=foo implies -Wfoo. */ > if (option->var_type == CLVC_BOOLEAN) >
> What happened with this?
http://gcc.gnu.org/viewcvs?view=revision&revision=161115
On 2 July 2010 17:56, DJ Delorie <dj@redhat.com> wrote: > >> What happened with this? > > http://gcc.gnu.org/viewcvs?view=revision&revision=161115 Oh, I missed that. Sorry for the noise. I think this is worth mentioning in gcc-4.6/changes.html, this is yet another feature where clang cannot longer claim to be superior! ;-) Cheers, Manuel.
Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 160588) +++ doc/extend.texi (working copy) @@ -12587,21 +12587,36 @@ option. @example #pragma GCC diagnostic warning "-Wformat" #pragma GCC diagnostic error "-Wformat" #pragma GCC diagnostic ignored "-Wformat" @end example -Note that these pragmas override any command-line options. Also, -while it is syntactically valid to put these pragmas anywhere in your -sources, the only supported location for them is before any data or -functions are defined. Doing otherwise may result in unpredictable -results depending on how the optimizer manages your sources. If the -same option is listed multiple times, the last one specified is the -one that is in effect. This pragma is not intended to be a general -purpose replacement for command-line options, but for implementing -strict control over project policies. +Note that these pragmas override any command-line options. GCC keeps +track of the location of each pragma, and issues diagnostics according +to the state as of that point in the source file. Thus, pragmas occurring +after a line do not affect diagnostics caused by that line. + +@item #pragma GCC diagnostic push +@itemx #pragma GCC diagnostic pop + +Causes GCC to remember the state of the diagnostics as of each +@code{push}, and restore to that point at each @code{pop}. If a +@code{pop} has no matching @code{push}, the command line options are +restored. + +@example +#pragma GCC diagnostic error "-Wuninitialized" + foo(a); /* error is given for this one */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + foo(b); /* no diagnostic for this one */ +#pragma GCC diagnostic pop + foo(c); /* error is given for this one */ +#pragma GCC diagnostic pop + foo(d); /* depends on command line options */ +@end example @end table GCC also offers a simple mechanism for printing messages during compilation. Index: c-family/c-pragma.c =================================================================== --- c-family/c-pragma.c (revision 160588) +++ c-family/c-pragma.c (working copy) @@ -703,40 +703,44 @@ handle_pragma_diagnostic(cpp_reader *ARG const char *kind_string, *option_string; unsigned int option_index; enum cpp_ttype token; diagnostic_t kind; tree x; - if (cfun) - { - error ("#pragma GCC diagnostic not allowed inside functions"); - return; - } - token = pragma_lex (&x); if (token != CPP_NAME) GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>"); kind_string = IDENTIFIER_POINTER (x); if (strcmp (kind_string, "error") == 0) kind = DK_ERROR; else if (strcmp (kind_string, "warning") == 0) kind = DK_WARNING; else if (strcmp (kind_string, "ignored") == 0) kind = DK_IGNORED; + else if (strcmp (kind_string, "push") == 0) + { + diagnostic_push_diagnostics (global_dc, input_location); + return; + } + else if (strcmp (kind_string, "pop") == 0) + { + diagnostic_pop_diagnostics (global_dc, input_location); + return; + } else - GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>"); + GCC_BAD ("expected [error|warning|ignored|push|pop] after %<#pragma GCC diagnostic%>"); token = pragma_lex (&x); if (token != CPP_STRING) GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind"); option_string = TREE_STRING_POINTER (x); for (option_index = 0; option_index < cl_options_count; option_index++) if (strcmp (cl_options[option_index].opt_text, option_string) == 0) { /* This overrides -Werror, for example. */ - diagnostic_classify_diagnostic (global_dc, option_index, kind); + diagnostic_classify_diagnostic (global_dc, option_index, kind, input_location); /* This makes sure the option is enabled, like -Wfoo would do. */ if (cl_options[option_index].var_type == CLVC_BOOLEAN && cl_options[option_index].flag_var && kind != DK_IGNORED) *(int *) cl_options[option_index].flag_var = 1; return; Index: diagnostic.c =================================================================== --- diagnostic.c (revision 160588) +++ diagnostic.c (working copy) @@ -303,26 +303,83 @@ default_diagnostic_finalizer (diagnostic /* Interface to specify diagnostic kind overrides. Returns the previous setting, or DK_UNSPECIFIED if the parameters are out of range. */ diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *context, int option_index, - diagnostic_t new_kind) + diagnostic_t new_kind, + location_t where) { diagnostic_t old_kind; if (option_index <= 0 || option_index >= context->n_opts || new_kind >= DK_LAST_DIAGNOSTIC_KIND) return DK_UNSPECIFIED; old_kind = context->classify_diagnostic[option_index]; - context->classify_diagnostic[option_index] = new_kind; + + /* Handle pragmas separately, since we need to keep track of *where* + the pragmas were. */ + if (where != UNKNOWN_LOCATION) + { + int i; + + for (i = context->n_classification_history - 1; i >= 0; i --) + if (context->classification_history[i].option == option_index) + { + old_kind = context->classification_history[i].kind; + break; + } + + i = context->n_classification_history; + context->classification_history = + (diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1) + * sizeof (diagnostic_classification_change_t)); + context->classification_history[i].location = where; + context->classification_history[i].option = option_index; + context->classification_history[i].kind = new_kind; + context->n_classification_history ++; + } + else + context->classify_diagnostic[option_index] = new_kind; + return old_kind; } +/* Save all diagnostic classifications in a stack. */ +void +diagnostic_push_diagnostics (diagnostic_context *context, location_t where ATTRIBUTE_UNUSED) +{ + context->push_list = (int *) xrealloc (context->push_list, (context->n_push + 1) * sizeof (int)); + context->push_list[context->n_push ++] = context->n_classification_history; +} + +/* Restore the topmost classification set off the stack. If the stack + is empty, revert to the state based on command line parameters. */ +void +diagnostic_pop_diagnostics (diagnostic_context *context, location_t where) +{ + int jump_to; + int i; + + if (context->n_push) + jump_to = context->push_list [-- context->n_push]; + else + jump_to = 0; + + i = context->n_classification_history; + context->classification_history = + (diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1) + * sizeof (diagnostic_classification_change_t)); + context->classification_history[i].location = where; + context->classification_history[i].option = jump_to; + context->classification_history[i].kind = DK_POP; + context->n_classification_history ++; +} + /* Report a diagnostic message (an error or a warning) as specified by DC. This function is *the* subroutine in terms of which front-ends should implement their specific diagnostic handling modules. The front-end independent format specifiers are exactly those described in the documentation of output_format. Return true if a diagnostic was printed, false otherwise. */ @@ -371,19 +428,47 @@ diagnostic_report_diagnostic (diagnostic { diagnostic->kind = DK_ERROR; } if (diagnostic->option_index) { + diagnostic_t diag_class = DK_UNSPECIFIED; + /* This tests if the user provided the appropriate -Wfoo or -Wno-foo option. */ if (! context->option_enabled (diagnostic->option_index)) return false; + + /* This tests for #pragma diagnostic changes. */ + if (context->n_classification_history > 0) + { + int i; + /* FIXME: Stupid search. Optimize later. */ + for (i = context->n_classification_history - 1; i >= 0; i --) + { + if (context->classification_history[i].location <= location) + { + if (context->classification_history[i].kind == (int) DK_POP) + { + i = context->classification_history[i].option; + continue; + } + if (context->classification_history[i].option == diagnostic->option_index) + { + diag_class = context->classification_history[i].kind; + if (diag_class != DK_UNSPECIFIED) + diagnostic->kind = diag_class; + break; + } + } + } + } /* This tests if the user provided the appropriate -Werror=foo option. */ - if (context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED) + if (diag_class == DK_UNSPECIFIED + && context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED) { diagnostic->kind = context->classify_diagnostic[diagnostic->option_index]; } /* This allows for future extensions, like temporarily disabling warnings for ranges of source code. */ if (diagnostic->kind == DK_IGNORED) Index: diagnostic.h =================================================================== --- diagnostic.h (revision 160588) +++ diagnostic.h (working copy) @@ -38,12 +38,22 @@ typedef struct diagnostic_info /* The kind of diagnostic it is about. */ diagnostic_t kind; /* Which OPT_* directly controls this diagnostic. */ int option_index; } diagnostic_info; +/* Each time a diagnostic's classification is changed with a pragma, + we record the change and the location of the change in an array of + these structs. */ +typedef struct diagnostic_classification_change_t +{ + location_t location; + int option; + diagnostic_t kind; +} diagnostic_classification_change_t; + /* Forward declarations. */ typedef struct diagnostic_context diagnostic_context; typedef void (*diagnostic_starter_fn) (diagnostic_context *, diagnostic_info *); typedef diagnostic_starter_fn diagnostic_finalizer_fn; @@ -73,12 +83,26 @@ struct diagnostic_context options), this array may contain a new kind that the diagnostic should be changed to before reporting, or DK_UNSPECIFIED to leave it as the reported kind, or DK_IGNORED to not report it at all. */ diagnostic_t *classify_diagnostic; + /* History of all changes to the classifications above. This list + is stored in location-order, so we can search it, either + binary-wise or end-to-front, to find the most recent + classification for a given diagnostic, given the location of the + diagnostic. */ + diagnostic_classification_change_t *classification_history; + + /* The size of the above array. */ + int n_classification_history; + + /* For pragma push/pop. */ + int *push_list; + int n_push; + /* True if we should print the command line option which controls each diagnostic, if known. */ bool show_option_requested; /* True if we should raise a SIGABRT on errors. */ bool abort_on_error; @@ -225,13 +249,16 @@ extern void diagnostic_initialize (diagn extern void diagnostic_finish (diagnostic_context *); extern void diagnostic_report_current_module (diagnostic_context *); /* Force diagnostics controlled by OPTIDX to be kind KIND. */ extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *, int /* optidx */, - diagnostic_t /* kind */); + diagnostic_t /* kind */, + location_t); +extern void diagnostic_push_diagnostics (diagnostic_context *, location_t); +extern void diagnostic_pop_diagnostics (diagnostic_context *, location_t); extern bool diagnostic_report_diagnostic (diagnostic_context *, diagnostic_info *); #ifdef ATTRIBUTE_GCC_DIAG extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *, location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0); extern void diagnostic_set_info_translated (diagnostic_info *, const char *, Index: diagnostic-core.h =================================================================== --- diagnostic-core.h (revision 160588) +++ diagnostic-core.h (working copy) @@ -29,13 +29,16 @@ along with GCC; see the file COPYING3. /* Constants used to discriminate diagnostics. */ typedef enum { #define DEFINE_DIAGNOSTIC_KIND(K, msgid) K, #include "diagnostic.def" #undef DEFINE_DIAGNOSTIC_KIND - DK_LAST_DIAGNOSTIC_KIND + DK_LAST_DIAGNOSTIC_KIND, + /* This is used for tagging pragma pops in the diagnostic + classification history chain. */ + DK_POP } diagnostic_t; extern const char *progname; extern const char *trim_filename (const char *); Index: testsuite/gcc.dg/pragma-diag-1.c =================================================================== --- testsuite/gcc.dg/pragma-diag-1.c (revision 0) +++ testsuite/gcc.dg/pragma-diag-1.c (revision 0) @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-Wuninitialized -O2" } */ +/* { dg-message "warnings being treated as errors" "" {target "*-*-*"} 0 } */ + +main() +{ + int a; + int b; + int c; + int d; + +#pragma GCC diagnostic error "-Wuninitialized" + foo(a); /* { dg-error "uninitialized" } */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + foo(b); +#pragma GCC diagnostic pop + foo(c); /* { dg-error "uninitialized" } */ +#pragma GCC diagnostic pop + foo(d); /* { dg-warning "uninitialized" } */ +} Index: opts.c =================================================================== --- opts.c (revision 160588) +++ opts.c (working copy) @@ -2473,13 +2473,14 @@ set_option (int opt_index, int value, co case CLVC_STRING: *(const char **) option->flag_var = arg; break; } if ((diagnostic_t)kind != DK_UNSPECIFIED) - diagnostic_classify_diagnostic (global_dc, opt_index, (diagnostic_t)kind); + diagnostic_classify_diagnostic (global_dc, opt_index, (diagnostic_t)kind, + UNKNOWN_LOCATION); } /* Callback function, called when -Werror= enables a warning. */ static void (*warning_as_error_callback) (int) = NULL; @@ -2511,13 +2512,14 @@ enable_warning_as_error (const char *arg error ("-Werror=%s: No option -%s", arg, new_option); } else { const diagnostic_t kind = value ? DK_ERROR : DK_WARNING; - diagnostic_classify_diagnostic (global_dc, option_index, kind); + diagnostic_classify_diagnostic (global_dc, option_index, kind, + UNKNOWN_LOCATION); if (kind == DK_ERROR) { const struct cl_option * const option = cl_options + option_index; /* -Werror=foo implies -Wfoo. */ if (option->var_type == CLVC_BOOLEAN)