/* Language-independent diagnostic subroutines for the GNU Compiler Collection
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file implements the language independent aspect of diagnostic
#include "langhooks.h"
#include "langhooks-def.h"
#include "opts.h"
+#include "plugin.h"
+#define pedantic_warning_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING)
+#define permissive_error_kind() (flag_permissive ? DK_WARNING : DK_ERROR)
/* Prototypes. */
static char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1;
diagnostic_info *);
static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
-static bool diagnostic_count_diagnostic (diagnostic_context *,
- diagnostic_info *);
+
static void diagnostic_action_after_output (diagnostic_context *,
diagnostic_info *);
static void real_abort (void) ATTRIBUTE_NORETURN;
/* A diagnostic_context surrogate for stderr. */
static diagnostic_context global_diagnostic_context;
diagnostic_context *global_dc = &global_diagnostic_context;
+
\f
/* Return a malloc'd string containing MSG formatted a la printf. The
caller is responsible for freeing the memory. */
{
/* Allocate a basic pretty-printer. Clients will replace this a
much more elaborated pretty-printer if they wish. */
- context->printer = xmalloc (sizeof (pretty_printer));
+ context->printer = XNEW (pretty_printer);
pp_construct (context->printer, NULL, 0);
/* By default, diagnostics are sent to stderr. */
context->printer->buffer->stream = stderr;
memset (context->diagnostic_count, 0, sizeof context->diagnostic_count);
context->issue_warnings_are_errors_message = true;
context->warning_as_error_requested = false;
+ memset (context->classify_diagnostic, DK_UNSPECIFIED,
+ sizeof context->classify_diagnostic);
context->show_option_requested = false;
context->abort_on_error = false;
context->internal_error = NULL;
diagnostic->message.args_ptr = args;
diagnostic->message.format_spec = msg;
diagnostic->location = location;
+ diagnostic->override_column = 0;
diagnostic->kind = kind;
diagnostic->option_index = 0;
}
};
const char *text = _(diagnostic_kind_text[diagnostic->kind]);
expanded_location s = expand_location (diagnostic->location);
+ if (diagnostic->override_column)
+ s.column = diagnostic->override_column;
gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
return
(s.file == NULL
? build_message_string ("%s: %s", progname, text)
-#ifdef USE_MAPPED_LOCATION
- : flag_show_column && s.column != 0
+ : flag_show_column
? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text)
-#endif
: build_message_string ("%s:%d: %s", s.file, s.line, text));
}
-/* Count a diagnostic. Return true if the message should be printed. */
-static bool
-diagnostic_count_diagnostic (diagnostic_context *context,
- diagnostic_info *diagnostic)
-{
- diagnostic_t kind = diagnostic->kind;
- switch (kind)
- {
- default:
- gcc_unreachable ();
-
- case DK_ICE:
-#ifndef ENABLE_CHECKING
- /* When not checking, ICEs are converted to fatal errors when an
- error has already occurred. This is counteracted by
- abort_on_error. */
- if ((diagnostic_kind_count (context, DK_ERROR) > 0
- || diagnostic_kind_count (context, DK_SORRY) > 0)
- && !context->abort_on_error)
- {
- expanded_location s = expand_location (diagnostic->location);
- fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
- s.file, s.line);
- exit (FATAL_EXIT_CODE);
- }
-#endif
- if (context->internal_error)
- (*context->internal_error) (diagnostic->message.format_spec,
- diagnostic->message.args_ptr);
- /* Fall through. */
-
- case DK_FATAL: case DK_SORRY:
- case DK_ANACHRONISM: case DK_NOTE:
- ++diagnostic_kind_count (context, kind);
- break;
-
- case DK_WARNING:
- if (!diagnostic_report_warnings_p ())
- return false;
-
- if (!context->warning_as_error_requested)
- {
- ++diagnostic_kind_count (context, DK_WARNING);
- break;
- }
- else if (context->issue_warnings_are_errors_message)
- {
- pp_verbatim (context->printer,
- "%s: warnings being treated as errors\n", progname);
- context->issue_warnings_are_errors_message = false;
- }
-
- /* And fall through. */
- case DK_ERROR:
- ++diagnostic_kind_count (context, DK_ERROR);
- break;
- }
-
- return true;
-}
-
/* Take any action which is expected to happen after the diagnostic
is written out. This function does not always return. */
static void
fnotice (stderr, "Please submit a full bug report,\n"
"with preprocessed source if appropriate.\n"
"See %s for instructions.\n", bug_report_url);
- exit (FATAL_EXIT_CODE);
+ exit (ICE_EXIT_CODE);
case DK_FATAL:
if (context->abort_on_error)
/* Prints out, if necessary, the name of the current function
that caused an error. Called from all error and warning functions. */
void
-diagnostic_report_current_function (diagnostic_context *context)
+diagnostic_report_current_function (diagnostic_context *context,
+ diagnostic_info *diagnostic)
{
diagnostic_report_current_module (context);
- lang_hooks.print_error_function (context, input_filename);
+ lang_hooks.print_error_function (context, input_filename, diagnostic);
}
void
diagnostic_report_current_module (diagnostic_context *context)
{
- struct file_stack *p;
+ const struct line_map *map;
if (pp_needs_newline (context->printer))
{
pp_needs_newline (context->printer) = false;
}
- p = input_file_stack;
- if (p && diagnostic_last_module_changed (context))
+ if (input_location <= BUILTINS_LOCATION)
+ return;
+
+ map = linemap_lookup (line_table, input_location);
+ if (map && diagnostic_last_module_changed (context, map))
{
- expanded_location xloc = expand_location (p->location);
- pp_verbatim (context->printer,
- "In file included from %s:%d",
- xloc.file, xloc.line);
- while ((p = p->next) != NULL)
+ diagnostic_set_last_module (context, map);
+ if (! MAIN_FILE_P (map))
{
- xloc = expand_location (p->location);
- pp_verbatim (context->printer,
- ",\n from %s:%d",
- xloc.file, xloc.line);
+ map = INCLUDED_FROM (line_table, map);
+ if (flag_show_column)
+ pp_verbatim (context->printer,
+ "In file included from %s:%d:%d",
+ map->to_file,
+ LAST_SOURCE_LINE (map), LAST_SOURCE_COLUMN (map));
+ else
+ pp_verbatim (context->printer,
+ "In file included from %s:%d",
+ map->to_file, LAST_SOURCE_LINE (map));
+ while (! MAIN_FILE_P (map))
+ {
+ map = INCLUDED_FROM (line_table, map);
+ pp_verbatim (context->printer,
+ ",\n from %s:%d",
+ map->to_file, LAST_SOURCE_LINE (map));
+ }
+ pp_verbatim (context->printer, ":");
+ pp_newline (context->printer);
}
- pp_verbatim (context->printer, ":");
- diagnostic_set_last_module (context);
- pp_newline (context->printer);
}
}
default_diagnostic_starter (diagnostic_context *context,
diagnostic_info *diagnostic)
{
- diagnostic_report_current_function (context);
+ diagnostic_report_current_function (context, diagnostic);
pp_set_prefix (context->printer, diagnostic_build_prefix (diagnostic));
}
pp_destroy_prefix (context->printer);
}
+/* 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 old_kind;
+
+ if (option_index <= 0
+ || option_index >= 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;
+ return old_kind;
+}
+
/* 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. */
+ in the documentation of output_format.
+ Return true if a diagnostic was printed, false otherwise. */
-void
+bool
diagnostic_report_diagnostic (diagnostic_context *context,
diagnostic_info *diagnostic)
{
+ location_t location = diagnostic->location;
+ bool maybe_print_warnings_as_errors_message = false;
+ const char *saved_format_spec;
+
+ /* Give preference to being able to inhibit warnings, before they
+ get reclassified to something else. */
+ if ((diagnostic->kind == DK_WARNING || diagnostic->kind == DK_PEDWARN)
+ && !diagnostic_report_warnings_p (location))
+ return false;
+
+ if (diagnostic->kind == DK_PEDWARN)
+ diagnostic->kind = pedantic_warning_kind ();
+
if (context->lock > 0)
{
/* If we're reporting an ICE in the middle of some other error,
error_recursion (context);
}
- if (diagnostic->option_index
- && ! option_enabled (diagnostic->option_index))
- return;
+ /* If the user requested that warnings be treated as errors, so be
+ it. Note that we do this before the next block so that
+ individual warnings can be overridden back to warnings with
+ -Wno-error=*. */
+ if (context->warning_as_error_requested
+ && diagnostic->kind == DK_WARNING)
+ {
+ diagnostic->kind = DK_ERROR;
+ maybe_print_warnings_as_errors_message = true;
+ }
+
+ if (diagnostic->option_index)
+ {
+ /* This tests if the user provided the appropriate -Wfoo or
+ -Wno-foo option. */
+ if (! option_enabled (diagnostic->option_index))
+ return false;
+ /* This tests if the user provided the appropriate -Werror=foo
+ option. */
+ if (context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED)
+ {
+ diagnostic->kind = context->classify_diagnostic[diagnostic->option_index];
+ maybe_print_warnings_as_errors_message = false;
+ }
+ /* This allows for future extensions, like temporarily disabling
+ warnings for ranges of source code. */
+ if (diagnostic->kind == DK_IGNORED)
+ return false;
+ }
+
+ /* If we changed the kind due to -Werror, and didn't override it, we
+ need to print this message. */
+ if (context->issue_warnings_are_errors_message
+ && maybe_print_warnings_as_errors_message)
+ {
+ pp_verbatim (context->printer,
+ "%s: warnings being treated as errors\n", progname);
+ context->issue_warnings_are_errors_message = false;
+ }
context->lock++;
- if (diagnostic_count_diagnostic (context, diagnostic))
+ if (diagnostic->kind == DK_ICE && plugins_active_p ())
{
- const char *saved_format_spec = diagnostic->message.format_spec;
-
- if (context->show_option_requested && diagnostic->option_index)
- diagnostic->message.format_spec
- = ACONCAT ((diagnostic->message.format_spec,
- " [", cl_options[diagnostic->option_index].opt_text, "]", NULL));
-
- diagnostic->message.locus = &diagnostic->location;
- pp_format (context->printer, &diagnostic->message);
- (*diagnostic_starter (context)) (context, diagnostic);
- pp_output_formatted_text (context->printer);
- (*diagnostic_finalizer (context)) (context, diagnostic);
- pp_flush (context->printer);
- diagnostic_action_after_output (context, diagnostic);
- diagnostic->message.format_spec = saved_format_spec;
+ fnotice (stderr, "*** WARNING *** there are active plugins, do not report"
+ " this as a bug unless you can reproduce it without enabling"
+ " any plugins.\n");
+ dump_active_plugins (stderr);
}
+ if (diagnostic->kind == DK_ICE)
+ {
+#ifndef ENABLE_CHECKING
+ /* When not checking, ICEs are converted to fatal errors when an
+ error has already occurred. This is counteracted by
+ abort_on_error. */
+ if ((diagnostic_kind_count (context, DK_ERROR) > 0
+ || diagnostic_kind_count (context, DK_SORRY) > 0)
+ && !context->abort_on_error)
+ {
+ expanded_location s = expand_location (diagnostic->location);
+ fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
+ s.file, s.line);
+ exit (ICE_EXIT_CODE);
+ }
+#endif
+ if (context->internal_error)
+ (*context->internal_error) (diagnostic->message.format_spec,
+ diagnostic->message.args_ptr);
+ }
+ ++diagnostic_kind_count (context, diagnostic->kind);
+
+ saved_format_spec = diagnostic->message.format_spec;
+ if (context->show_option_requested && diagnostic->option_index)
+ diagnostic->message.format_spec
+ = ACONCAT ((diagnostic->message.format_spec,
+ " [", cl_options[diagnostic->option_index].opt_text, "]", NULL));
+
+ diagnostic->message.locus = &diagnostic->location;
+ diagnostic->message.abstract_origin = &diagnostic->abstract_origin;
+ diagnostic->abstract_origin = NULL;
+ pp_format (context->printer, &diagnostic->message);
+ (*diagnostic_starter (context)) (context, diagnostic);
+ pp_output_formatted_text (context->printer);
+ (*diagnostic_finalizer (context)) (context, diagnostic);
+ pp_flush (context->printer);
+ diagnostic_action_after_output (context, diagnostic);
+ diagnostic->message.format_spec = saved_format_spec;
+ diagnostic->abstract_origin = NULL;
+
context->lock--;
+
+ return true;
}
/* Given a partial pathname as input, return another pathname that
text.args_ptr = ≈
text.format_spec = _(gmsgid);
text.locus = NULL;
+ text.abstract_origin = NULL;
pp_format_verbatim (global_dc->printer, &text);
pp_flush (global_dc->printer);
va_end (ap);
}
-/* An informative note. Use this for additional details on an error
+bool
+emit_diagnostic (diagnostic_t kind, location_t location, int opt,
+ const char *gmsgid, ...)
+{
+ diagnostic_info diagnostic;
+ va_list ap;
+
+ va_start (ap, gmsgid);
+ if (kind == DK_PERMERROR)
+ {
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
+ permissive_error_kind ());
+ diagnostic.option_index = OPT_fpermissive;
+ }
+ else {
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location, kind);
+ if (kind == DK_WARNING || kind == DK_PEDWARN)
+ diagnostic.option_index = opt;
+ }
+ va_end (ap);
+
+ return report_diagnostic (&diagnostic);
+}
+
+/* An informative note at LOCATION. Use this for additional details on an error
message. */
void
-inform (const char *gmsgid, ...)
+inform (location_t location, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
va_start (ap, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_NOTE);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_NOTE);
report_diagnostic (&diagnostic);
va_end (ap);
}
-/* A warning. Use this for code which is correct according to the
- relevant language specification but is likely to be buggy anyway. */
-void
+/* A warning at INPUT_LOCATION. Use this for code which is correct according
+ to the relevant language specification but is likely to be buggy anyway.
+ Returns true if the warning was printed, false if it was inhibited. */
+bool
warning (int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING);
diagnostic.option_index = opt;
- report_diagnostic (&diagnostic);
va_end (ap);
+ return report_diagnostic (&diagnostic);
}
-void
-warning0 (const char *gmsgid, ...)
+/* A warning at LOCATION. Use this for code which is correct according to the
+ relevant language specification but is likely to be buggy anyway.
+ Returns true if the warning was printed, false if it was inhibited. */
+
+bool
+warning_at (location_t location, int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
va_start (ap, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING);
- report_diagnostic (&diagnostic);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_WARNING);
+ diagnostic.option_index = opt;
va_end (ap);
+ return report_diagnostic (&diagnostic);
}
-/* A "pedantic" warning: issues a warning unless -pedantic-errors was
- given on the command line, in which case it issues an error. Use
- this for diagnostics required by the relevant language standard,
- if you have chosen not to make them errors.
+/* A "pedantic" warning at LOCATION: issues a warning unless
+ -pedantic-errors was given on the command line, in which case it
+ issues an error. Use this for diagnostics required by the relevant
+ language standard, if you have chosen not to make them errors.
Note that these diagnostics are issued independent of the setting
of the -pedantic command-line switch. To get a warning enabled
- only with that switch, write "if (pedantic) pedwarn (...);" */
-void
-pedwarn (const char *gmsgid, ...)
+ only with that switch, use either "if (pedantic) pedwarn
+ (OPT_pedantic,...)" or just "pedwarn (OPT_pedantic,..)". To get a
+ pedwarn independently of the -pedantic switch use "pedwarn (0,...)".
+
+ Returns true if the warning was printed, false if it was inhibited. */
+
+bool
+pedwarn (location_t location, int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
va_start (ap, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location,
- pedantic_error_kind ());
- report_diagnostic (&diagnostic);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN);
+ diagnostic.option_index = opt;
+ va_end (ap);
+ return report_diagnostic (&diagnostic);
+}
+
+/* A "permissive" error at LOCATION: issues an error unless
+ -fpermissive was given on the command line, in which case it issues
+ a warning. Use this for things that really should be errors but we
+ want to support legacy code.
+
+ Returns true if the warning was printed, false if it was inhibited. */
+
+bool
+permerror (location_t location, const char *gmsgid, ...)
+{
+ diagnostic_info diagnostic;
+ va_list ap;
+
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
+ permissive_error_kind ());
+ diagnostic.option_index = OPT_fpermissive;
va_end (ap);
+ return report_diagnostic (&diagnostic);
}
/* A hard error: the code is definitely ill-formed, and an object file
va_end (ap);
}
+/* Same as ebove, but use location LOC instead of input_location. */
+void
+error_at (location_t loc, const char *gmsgid, ...)
+{
+ diagnostic_info diagnostic;
+ va_list ap;
+
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, loc, DK_ERROR);
+ report_diagnostic (&diagnostic);
+ va_end (ap);
+}
+
/* "Sorry, not implemented." Use for a language feature which is
required by the relevant specification but not implemented by GCC.
An object file will not be produced. */