diagnostic.h (diagnostic_classification_change_t): New.

* 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.

From-SVN: r161115
This commit is contained in:
DJ Delorie 2010-06-21 16:58:57 -04:00 committed by DJ Delorie
parent fa188ff0f2
commit cd7fe53b72
9 changed files with 206 additions and 24 deletions

View File

@ -1,3 +1,24 @@
2010-06-21 DJ Delorie <dj@redhat.com>
* 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.
2010-06-21 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.c (add_linkage_name): New function. Don't add

View File

@ -706,12 +706,6 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
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%>");
@ -722,8 +716,18 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
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)
@ -733,7 +737,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
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

View File

@ -32,7 +32,10 @@ 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;

View File

@ -306,7 +306,8 @@ default_diagnostic_finalizer (diagnostic_context *context,
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;
@ -316,10 +317,66 @@ diagnostic_classify_diagnostic (diagnostic_context *context,
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
@ -374,13 +431,41 @@ diagnostic_report_diagnostic (diagnostic_context *context,
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];
}

View File

@ -41,6 +41,16 @@ typedef struct diagnostic_info
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 *,
@ -76,6 +86,20 @@ struct diagnostic_context
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;
@ -228,7 +252,10 @@ 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

View File

@ -12590,15 +12590,30 @@ option.
#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

View File

@ -2396,7 +2396,8 @@ set_option (int opt_index, int value, const char *arg, int kind)
}
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);
}
@ -2434,7 +2435,8 @@ enable_warning_as_error (const char *arg, int value, unsigned int lang_mask)
{
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;

View File

@ -1,3 +1,7 @@
2010-06-21 DJ Delorie <dj@redhat.com>
* gcc.dg/pragma-diag-1.c: New.
2010-06-21 H.J. Lu <hongjiu.lu@intel.com>
PR target/44615

View File

@ -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" } */
}