Commit cd7fe53b by DJ Delorie Committed by DJ Delorie

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
parent fa188ff0
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> 2010-06-21 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.c (add_linkage_name): New function. Don't add * dwarf2out.c (add_linkage_name): New function. Don't add
......
...@@ -706,12 +706,6 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)) ...@@ -706,12 +706,6 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
diagnostic_t kind; diagnostic_t kind;
tree x; tree x;
if (cfun)
{
error ("#pragma GCC diagnostic not allowed inside functions");
return;
}
token = pragma_lex (&x); token = pragma_lex (&x);
if (token != CPP_NAME) if (token != CPP_NAME)
GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>"); GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
...@@ -722,8 +716,18 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)) ...@@ -722,8 +716,18 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
kind = DK_WARNING; kind = DK_WARNING;
else if (strcmp (kind_string, "ignored") == 0) else if (strcmp (kind_string, "ignored") == 0)
kind = DK_IGNORED; 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 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); token = pragma_lex (&x);
if (token != CPP_STRING) if (token != CPP_STRING)
...@@ -733,7 +737,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)) ...@@ -733,7 +737,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
if (strcmp (cl_options[option_index].opt_text, option_string) == 0) if (strcmp (cl_options[option_index].opt_text, option_string) == 0)
{ {
/* This overrides -Werror, for example. */ /* 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. */ /* This makes sure the option is enabled, like -Wfoo would do. */
if (cl_options[option_index].var_type == CLVC_BOOLEAN if (cl_options[option_index].var_type == CLVC_BOOLEAN
&& cl_options[option_index].flag_var && cl_options[option_index].flag_var
......
...@@ -32,7 +32,10 @@ typedef enum ...@@ -32,7 +32,10 @@ typedef enum
#define DEFINE_DIAGNOSTIC_KIND(K, msgid) K, #define DEFINE_DIAGNOSTIC_KIND(K, msgid) K,
#include "diagnostic.def" #include "diagnostic.def"
#undef DEFINE_DIAGNOSTIC_KIND #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; } diagnostic_t;
extern const char *progname; extern const char *progname;
......
...@@ -306,7 +306,8 @@ default_diagnostic_finalizer (diagnostic_context *context, ...@@ -306,7 +306,8 @@ default_diagnostic_finalizer (diagnostic_context *context,
diagnostic_t diagnostic_t
diagnostic_classify_diagnostic (diagnostic_context *context, diagnostic_classify_diagnostic (diagnostic_context *context,
int option_index, int option_index,
diagnostic_t new_kind) diagnostic_t new_kind,
location_t where)
{ {
diagnostic_t old_kind; diagnostic_t old_kind;
...@@ -316,10 +317,66 @@ diagnostic_classify_diagnostic (diagnostic_context *context, ...@@ -316,10 +317,66 @@ diagnostic_classify_diagnostic (diagnostic_context *context,
return DK_UNSPECIFIED; return DK_UNSPECIFIED;
old_kind = context->classify_diagnostic[option_index]; 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; 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 /* Report a diagnostic message (an error or a warning) as specified by
DC. This function is *the* subroutine in terms of which front-ends DC. This function is *the* subroutine in terms of which front-ends
should implement their specific diagnostic handling modules. The should implement their specific diagnostic handling modules. The
...@@ -374,13 +431,41 @@ diagnostic_report_diagnostic (diagnostic_context *context, ...@@ -374,13 +431,41 @@ diagnostic_report_diagnostic (diagnostic_context *context,
if (diagnostic->option_index) if (diagnostic->option_index)
{ {
diagnostic_t diag_class = DK_UNSPECIFIED;
/* This tests if the user provided the appropriate -Wfoo or /* This tests if the user provided the appropriate -Wfoo or
-Wno-foo option. */ -Wno-foo option. */
if (! context->option_enabled (diagnostic->option_index)) if (! context->option_enabled (diagnostic->option_index))
return false; 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 /* This tests if the user provided the appropriate -Werror=foo
option. */ 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]; diagnostic->kind = context->classify_diagnostic[diagnostic->option_index];
} }
......
...@@ -41,6 +41,16 @@ typedef struct diagnostic_info ...@@ -41,6 +41,16 @@ typedef struct diagnostic_info
int option_index; int option_index;
} diagnostic_info; } 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. */ /* Forward declarations. */
typedef struct diagnostic_context diagnostic_context; typedef struct diagnostic_context diagnostic_context;
typedef void (*diagnostic_starter_fn) (diagnostic_context *, typedef void (*diagnostic_starter_fn) (diagnostic_context *,
...@@ -76,6 +86,20 @@ struct diagnostic_context ...@@ -76,6 +86,20 @@ struct diagnostic_context
all. */ all. */
diagnostic_t *classify_diagnostic; 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 /* True if we should print the command line option which controls
each diagnostic, if known. */ each diagnostic, if known. */
bool show_option_requested; bool show_option_requested;
...@@ -228,7 +252,10 @@ extern void diagnostic_report_current_module (diagnostic_context *); ...@@ -228,7 +252,10 @@ extern void diagnostic_report_current_module (diagnostic_context *);
/* Force diagnostics controlled by OPTIDX to be kind KIND. */ /* Force diagnostics controlled by OPTIDX to be kind KIND. */
extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *, extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *,
int /* optidx */, 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 *, extern bool diagnostic_report_diagnostic (diagnostic_context *,
diagnostic_info *); diagnostic_info *);
#ifdef ATTRIBUTE_GCC_DIAG #ifdef ATTRIBUTE_GCC_DIAG
......
...@@ -12590,15 +12590,30 @@ option. ...@@ -12590,15 +12590,30 @@ option.
#pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat"
@end example @end example
Note that these pragmas override any command-line options. Also, Note that these pragmas override any command-line options. GCC keeps
while it is syntactically valid to put these pragmas anywhere in your track of the location of each pragma, and issues diagnostics according
sources, the only supported location for them is before any data or to the state as of that point in the source file. Thus, pragmas occurring
functions are defined. Doing otherwise may result in unpredictable after a line do not affect diagnostics caused by that line.
results depending on how the optimizer manages your sources. If the
same option is listed multiple times, the last one specified is the @item #pragma GCC diagnostic push
one that is in effect. This pragma is not intended to be a general @itemx #pragma GCC diagnostic pop
purpose replacement for command-line options, but for implementing
strict control over project policies. 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 @end table
......
...@@ -2396,7 +2396,8 @@ set_option (int opt_index, int value, const char *arg, int kind) ...@@ -2396,7 +2396,8 @@ set_option (int opt_index, int value, const char *arg, int kind)
} }
if ((diagnostic_t)kind != DK_UNSPECIFIED) 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) ...@@ -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; 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) if (kind == DK_ERROR)
{ {
const struct cl_option * const option = cl_options + option_index; const struct cl_option * const option = cl_options + option_index;
......
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> 2010-06-21 H.J. Lu <hongjiu.lu@intel.com>
PR target/44615 PR target/44615
......
/* { 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" } */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment