mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-15 12:41:03 +08:00
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:
parent
fa188ff0f2
commit
cd7fe53b72
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
21
gcc/testsuite/gcc.dg/pragma-diag-1.c
Normal file
21
gcc/testsuite/gcc.dg/pragma-diag-1.c
Normal 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" } */
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user