X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gcc%2Fdiagnostic.c;fp=gcc%2Fdiagnostic.c;h=f323f363ae59dfec1076c44901a5c30534fbf548;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=4ff157d7ecb0ca47a61eb61952333358303a9256;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 4ff157d7..f323f363 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -1,12 +1,13 @@ -/* Language-independent diagnostic subroutines for the GNU C compiler - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +/* Language-independent diagnostic subroutines for the GNU Compiler Collection + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. Contributed by Gabriel Dos Reis 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 @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file implements the language independent aspect of diagnostic @@ -27,1352 +27,653 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #undef FLOAT /* This is for hpux. They should change hpux. */ #undef FFS /* Some systems define this in param.h. */ #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" +#include "version.h" #include "tm_p.h" #include "flags.h" #include "input.h" #include "toplev.h" #include "intl.h" #include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "opts.h" -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free +#define pedantic_warning_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING) +#define permissive_error_kind() (flag_permissive ? DK_WARNING : DK_ERROR) -#define output_formatted_integer(BUFFER, FORMAT, INTEGER) \ - do { \ - sprintf ((BUFFER)->digit_buffer, FORMAT, INTEGER); \ - output_add_string (BUFFER, (BUFFER)->digit_buffer); \ - } while (0) +/* Prototypes. */ +static char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; -#define output_text_length(BUFFER) (BUFFER)->line_length -#define is_starting_newline(BUFFER) (output_text_length (BUFFER) == 0) -#define output_prefix(BUFFER) (BUFFER)->state.prefix -#define line_wrap_cutoff(BUFFER) (BUFFER)->state.maximum_length -#define prefix_was_emitted_for(BUFFER) (BUFFER)->state.emitted_prefix_p -#define output_buffer_ptr_to_format_args(BUFFER) (BUFFER)->state.format_args +static void default_diagnostic_starter (diagnostic_context *, + diagnostic_info *); +static void default_diagnostic_finalizer (diagnostic_context *, + diagnostic_info *); -#define diagnostic_args output_buffer_ptr_to_format_args (diagnostic_buffer) -#define diagnostic_msg output_buffer_text_cursor (diagnostic_buffer) +static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN; -/* Prototypes. */ -static void diagnostic_finish PARAMS ((output_buffer *)); -static void output_do_verbatim PARAMS ((output_buffer *, - const char *, va_list *)); -static void output_buffer_to_stream PARAMS ((output_buffer *)); -static void output_format PARAMS ((output_buffer *)); -static void output_indent PARAMS ((output_buffer *)); - -static char *vbuild_message_string PARAMS ((const char *, va_list)) - ATTRIBUTE_PRINTF (1, 0); -static char *build_message_string PARAMS ((const char *, ...)) - ATTRIBUTE_PRINTF_1; -static void output_do_printf PARAMS ((output_buffer *, const char *)) - ATTRIBUTE_PRINTF (2, 0); -static void format_with_decl PARAMS ((output_buffer *, tree)); -static void diagnostic_for_decl PARAMS ((tree, const char *, va_list *, int)); -static void set_real_maximum_length PARAMS ((output_buffer *)); - -static void output_unsigned_decimal PARAMS ((output_buffer *, unsigned int)); -static void output_long_decimal PARAMS ((output_buffer *, long int)); -static void output_long_unsigned_decimal PARAMS ((output_buffer *, - long unsigned int)); -static void output_octal PARAMS ((output_buffer *, unsigned int)); -static void output_long_octal PARAMS ((output_buffer *, unsigned long int)); -static void output_hexadecimal PARAMS ((output_buffer *, unsigned int)); -static void output_long_hexadecimal PARAMS ((output_buffer *, - unsigned long int)); -static void output_append_r PARAMS ((output_buffer *, const char *, int)); -static void wrap_text PARAMS ((output_buffer *, const char *, const char *)); -static void maybe_wrap_text PARAMS ((output_buffer *, const char *, - const char *)); -static void clear_diagnostic_info PARAMS ((output_buffer *)); - -static void default_diagnostic_starter PARAMS ((output_buffer *, - diagnostic_context *)); -static void default_diagnostic_finalizer PARAMS ((output_buffer *, - diagnostic_context *)); - -static void error_recursion PARAMS ((void)) ATTRIBUTE_NORETURN; - -extern int rtl_dump_and_exit; -extern int warnings_are_errors; +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; -/* This will be removed shortly. */ -output_buffer *diagnostic_buffer = &global_diagnostic_context.buffer; - -/* Function of last error message; - more generally, function such that if next error message is in it - then we don't have to mention the function name. */ -static tree last_error_function = NULL; - -/* Used to detect when input_file_stack has changed since last described. */ -static int last_error_tick; - -/* Called by report_error_function to print out function name. - Default may be overridden by language front-ends. */ - -void (*print_error_function) PARAMS ((diagnostic_context *, const char *)) - = default_print_error_function; - -/* Prevent recursion into the error handler. */ -static int diagnostic_lock; - -/* Return truthvalue if current input file is different from the most recent - file involved in a diagnostic message. */ - -int -error_module_changed () +/* Return a malloc'd string containing MSG formatted a la printf. The + caller is responsible for freeing the memory. */ +static char * +build_message_string (const char *msg, ...) { - return last_error_tick != input_file_stack_tick; -} + char *str; + va_list ap; -/* Remember current file as being the most recent file involved in a - diagnostic message. */ + va_start (ap, msg); + vasprintf (&str, msg, ap); + va_end (ap); -void -record_last_error_module () -{ - last_error_tick = input_file_stack_tick; + return str; } -/* Same as error_module_changed, but for function. */ - -int -error_function_changed () +/* Same as diagnostic_build_prefix, but only the source FILE is given. */ +char * +file_name_as_prefix (const char *f) { - return last_error_function != current_function_decl; + return build_message_string ("%s: ", f); } -/* Same as record_last_error_module, but for function. */ - -void -record_last_error_function () -{ - last_error_function = current_function_decl; -} + /* Initialize the diagnostic message outputting machinery. */ - void -diagnostic_initialize (context) - diagnostic_context *context; +diagnostic_initialize (diagnostic_context *context) { - memset (context, 0, sizeof *context); - obstack_init (&context->buffer.obstack); - + /* Allocate a basic pretty-printer. Clients will replace this a + much more elaborated pretty-printer if they wish. */ + context->printer = XNEW (pretty_printer); + pp_construct (context->printer, NULL, 0); /* By default, diagnostics are sent to stderr. */ - output_buffer_attached_stream (&context->buffer) = stderr; - + context->printer->buffer->stream = stderr; /* By default, we emit prefixes once per message. */ - diagnostic_prefixing_rule (context) = DIAGNOSTICS_SHOW_PREFIX_ONCE; - + context->printer->wrapping.rule = DIAGNOSTICS_SHOW_PREFIX_ONCE; + + 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_starter (context) = default_diagnostic_starter; diagnostic_finalizer (context) = default_diagnostic_finalizer; + context->last_module = 0; + context->last_function = NULL; + context->lock = 0; } -/* Returns true if BUFFER is in line-wrapping mode. */ - -int -output_is_line_wrapping (buffer) - output_buffer *buffer; -{ - return diagnostic_line_cutoff (buffer) > 0; -} - -/* Return BUFFER's prefix. */ - -const char * -output_get_prefix (buffer) - const output_buffer *buffer; -{ - return output_prefix (buffer); -} - -/* Subroutine of output_set_maximum_length. Set up BUFFER's - internal maximum characters per line. */ - -static void -set_real_maximum_length (buffer) - output_buffer *buffer; -{ - /* If we're told not to wrap lines then do the obvious thing. In case - we'll emit prefix only once per diagnostic message, it is appropriate - not to increase unnecessarily the line-length cut-off. */ - if (! output_is_line_wrapping (buffer) - || diagnostic_prefixing_rule (buffer) == DIAGNOSTICS_SHOW_PREFIX_ONCE - || diagnostic_prefixing_rule (buffer) == DIAGNOSTICS_SHOW_PREFIX_NEVER) - line_wrap_cutoff (buffer) = diagnostic_line_cutoff (buffer); - else - { - int prefix_length = - output_prefix (buffer) ? strlen (output_prefix (buffer)) : 0; - /* If the prefix is ridiculously too long, output at least - 32 characters. */ - if (diagnostic_line_cutoff (buffer) - prefix_length < 32) - line_wrap_cutoff (buffer) = diagnostic_line_cutoff (buffer) + 32; - else - line_wrap_cutoff (buffer) = diagnostic_line_cutoff (buffer); - } -} - -/* Sets the number of maximum characters per line BUFFER can output - in line-wrapping mode. A LENGTH value 0 suppresses line-wrapping. */ - +/* Initialize DIAGNOSTIC, where the message MSG has already been + translated. */ void -output_set_maximum_length (buffer, length) - output_buffer *buffer; - int length; +diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg, + va_list *args, location_t location, + diagnostic_t kind) { - diagnostic_line_cutoff (buffer) = length; - set_real_maximum_length (buffer); + diagnostic->message.err_no = errno; + diagnostic->message.args_ptr = args; + diagnostic->message.format_spec = msg; + diagnostic->location = location; + diagnostic->kind = kind; + diagnostic->option_index = 0; } -/* Sets BUFFER's PREFIX. */ - +/* Initialize DIAGNOSTIC, where the message GMSGID has not yet been + translated. */ void -output_set_prefix (buffer, prefix) - output_buffer *buffer; - const char *prefix; +diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid, + va_list *args, location_t location, + diagnostic_t kind) { - output_prefix (buffer) = prefix; - set_real_maximum_length (buffer); - prefix_was_emitted_for (buffer) = 0; - output_indentation (buffer) = 0; -} - -/* Return a pointer to the last character emitted in the output - BUFFER area. A NULL pointer means no character available. */ -const char * -output_last_position (buffer) - const output_buffer *buffer; -{ - const char *p = NULL; - - if (obstack_base (&buffer->obstack) != obstack_next_free (&buffer->obstack)) - p = ((const char *) obstack_next_free (&buffer->obstack)) - 1; - return p; + diagnostic_set_info_translated (diagnostic, _(gmsgid), args, location, kind); } -/* Free BUFFER's prefix, a previously malloc'd string. */ - -void -output_destroy_prefix (buffer) - output_buffer *buffer; -{ - if (output_prefix (buffer) != NULL) - { - free ((char *) output_prefix (buffer)); - output_prefix (buffer) = NULL; - } -} - -/* Zero out any text output so far in BUFFER. */ - -void -output_clear_message_text (buffer) - output_buffer *buffer; -{ - obstack_free (&buffer->obstack, obstack_base (&buffer->obstack)); - output_text_length (buffer) = 0; -} - -/* Zero out any diagnostic data used so far by BUFFER. */ - +/* Return a malloc'd string describing a location. The caller is + responsible for freeing the memory. */ +char * +diagnostic_build_prefix (diagnostic_info *diagnostic) +{ + static const char *const diagnostic_kind_text[] = { +#define DEFINE_DIAGNOSTIC_KIND(K, T) (T), +#include "diagnostic.def" +#undef DEFINE_DIAGNOSTIC_KIND + "must-not-happen" + }; + const char *text = _(diagnostic_kind_text[diagnostic->kind]); + expanded_location s = expand_location (diagnostic->location); + gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND); + + return + (s.file == NULL + ? build_message_string ("%s: %s", progname, text) + : flag_show_column && s.column != 0 + ? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text) + : build_message_string ("%s:%d: %s", s.file, s.line, text)); +} + +/* Take any action which is expected to happen after the diagnostic + is written out. This function does not always return. */ static void -clear_diagnostic_info (buffer) - output_buffer *buffer; -{ - output_buffer_text_cursor (buffer) = NULL; - output_buffer_ptr_to_format_args (buffer) = NULL; - prefix_was_emitted_for (buffer) = 0; - output_indentation (buffer) = 0; -} - -/* Construct an output BUFFER with PREFIX and of MAXIMUM_LENGTH - characters per line. */ - -void -init_output_buffer (buffer, prefix, maximum_length) - output_buffer *buffer; - const char *prefix; - int maximum_length; -{ - memset (buffer, 0, sizeof (output_buffer)); - obstack_init (&buffer->obstack); - output_buffer_attached_stream (buffer) = stderr; - diagnostic_line_cutoff (buffer) = maximum_length; - diagnostic_prefixing_rule (buffer) = diagnostic_prefixing_rule (global_dc); - output_set_prefix (buffer, prefix); - output_text_length (buffer) = 0; - clear_diagnostic_info (buffer); -} - -/* Reinitialize BUFFER. */ - -void -output_clear (buffer) - output_buffer *buffer; +diagnostic_action_after_output (diagnostic_context *context, + diagnostic_info *diagnostic) { - output_clear_message_text (buffer); - clear_diagnostic_info (buffer); -} - -/* Finishes constructing a NULL-terminated character string representing - the BUFFERed message. */ - -const char * -output_finalize_message (buffer) - output_buffer *buffer; -{ - obstack_1grow (&buffer->obstack, '\0'); - return output_message_text (buffer); -} - -void -flush_diagnostic_buffer () -{ - output_buffer_to_stream (diagnostic_buffer); - fflush (output_buffer_attached_stream (diagnostic_buffer)); -} - -/* Return the amount of characters BUFFER can accept to - make a full line. */ - -int -output_space_left (buffer) - const output_buffer *buffer; -{ - return line_wrap_cutoff (buffer) - output_text_length (buffer); -} - -/* Write out BUFFER's prefix. */ - -void -output_emit_prefix (buffer) - output_buffer *buffer; -{ - if (output_prefix (buffer) != NULL) + switch (diagnostic->kind) { - switch (diagnostic_prefixing_rule (buffer)) - { - default: - case DIAGNOSTICS_SHOW_PREFIX_NEVER: - break; - - case DIAGNOSTICS_SHOW_PREFIX_ONCE: - if (prefix_was_emitted_for (buffer)) - { - output_indent (buffer); - break; - } - output_indentation (buffer) += 3; - /* Fall through. */ - - case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE: - { - int prefix_length = strlen (output_prefix (buffer)); - output_append_r (buffer, output_prefix (buffer), prefix_length); - prefix_was_emitted_for (buffer) = 1; - } - break; - } - } -} - -/* Have BUFFER start a new line. */ + case DK_DEBUG: + case DK_NOTE: + case DK_ANACHRONISM: + case DK_WARNING: + break; + + case DK_ERROR: + case DK_SORRY: + if (context->abort_on_error) + real_abort (); + if (flag_fatal_errors) + { + fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n"); + exit (FATAL_EXIT_CODE); + } + break; -void -output_add_newline (buffer) - output_buffer *buffer; -{ - obstack_1grow (&buffer->obstack, '\n'); - output_text_length (buffer) = 0; -} + case DK_ICE: + if (context->abort_on_error) + real_abort (); -/* Appends a character to BUFFER. */ + fnotice (stderr, "Please submit a full bug report,\n" + "with preprocessed source if appropriate.\n" + "See %s for instructions.\n", bug_report_url); + exit (ICE_EXIT_CODE); -void -output_add_character (buffer, c) - output_buffer *buffer; - int c; -{ - if (output_is_line_wrapping (buffer) && output_space_left (buffer) <= 0) - output_add_newline (buffer); - obstack_1grow (&buffer->obstack, c); - ++output_text_length (buffer); -} + case DK_FATAL: + if (context->abort_on_error) + real_abort (); -/* Adds a space to BUFFER. */ + fnotice (stderr, "compilation terminated.\n"); + exit (FATAL_EXIT_CODE); -void -output_add_space (buffer) - output_buffer *buffer; -{ - if (output_is_line_wrapping (buffer) && output_space_left (buffer) <= 0) - { - output_add_newline (buffer); - return; + default: + gcc_unreachable (); } - obstack_1grow (&buffer->obstack, ' '); - ++output_text_length (buffer); } -/* These functions format an INTEGER into BUFFER as suggested by their - names. */ - +/* Prints out, if necessary, the name of the current function + that caused an error. Called from all error and warning functions. */ void -output_decimal (buffer, i) - output_buffer *buffer; - int i; +diagnostic_report_current_function (diagnostic_context *context, + diagnostic_info *diagnostic) { - output_formatted_integer (buffer, "%d", i); + diagnostic_report_current_module (context); + lang_hooks.print_error_function (context, input_filename, diagnostic); } -static void -output_long_decimal (buffer, i) - output_buffer *buffer; - long int i; -{ - output_formatted_integer (buffer, "%ld", i); -} - -static void -output_unsigned_decimal (buffer, i) - output_buffer *buffer; - unsigned int i; -{ - output_formatted_integer (buffer, "%u", i); -} - -static void -output_long_unsigned_decimal (buffer, i) - output_buffer *buffer; - long unsigned int i; -{ - output_formatted_integer (buffer, "%lu", i); -} - -static void -output_octal (buffer, i) - output_buffer *buffer; - unsigned int i; -{ - output_formatted_integer (buffer, "%o", i); -} - -static void -output_long_octal (buffer, i) - output_buffer *buffer; - unsigned long int i; -{ - output_formatted_integer (buffer, "%lo", i); -} - -static void -output_hexadecimal (buffer, i) - output_buffer *buffer; - unsigned int i; -{ - output_formatted_integer (buffer, "%x", i); -} - -static void -output_long_hexadecimal (buffer, i) - output_buffer *buffer; - unsigned long int i; -{ - output_formatted_integer (buffer, "%lx", i); -} - -/* Append to BUFFER a string specified by its STARTING character - and LENGTH. */ - -static void -output_append_r (buffer, start, length) - output_buffer *buffer; - const char *start; - int length; -{ - obstack_grow (&buffer->obstack, start, length); - output_text_length (buffer) += length; -} - -/* Append a string deliminated by START and END to BUFFER. No wrapping is - done. However, if beginning a new line then emit output_prefix (BUFFER) - and skip any leading whitespace if appropriate. The caller must ensure - that it is safe to do so. */ - void -output_append (buffer, start, end) - output_buffer *buffer; - const char *start; - const char *end; +diagnostic_report_current_module (diagnostic_context *context) { - /* Emit prefix and skip whitespace if we're starting a new line. */ - if (is_starting_newline (buffer)) + const struct line_map *map; + + if (pp_needs_newline (context->printer)) { - output_emit_prefix (buffer); - if (output_is_line_wrapping (buffer)) - while (start != end && *start == ' ') - ++start; + pp_newline (context->printer); + pp_needs_newline (context->printer) = false; } - output_append_r (buffer, start, end - start); -} -static void -output_indent (buffer) - output_buffer *buffer; -{ - int n = output_indentation (buffer); - int i; - - for (i = 0; i < n; ++i) - output_add_character (buffer, ' '); -} - -/* Wrap a text delimited by START and END into BUFFER. */ + if (input_location <= BUILTINS_LOCATION) + return; -static void -wrap_text (buffer, start, end) - output_buffer *buffer; - const char *start; - const char *end; -{ - int is_wrapping = output_is_line_wrapping (buffer); - - while (start != end) + map = linemap_lookup (line_table, input_location); + if (map && diagnostic_last_module_changed (context, map)) { - /* Dump anything bordered by whitespaces. */ - { - const char *p = start; - while (p != end && *p != ' ' && *p != '\n') - ++p; - if (is_wrapping && p - start >= output_space_left (buffer)) - output_add_newline (buffer); - output_append (buffer, start, p); - start = p; - } - - if (start != end && *start == ' ') - { - output_add_space (buffer); - ++start; - } - if (start != end && *start == '\n') - { - output_add_newline (buffer); - ++start; - } + diagnostic_set_last_module (context, map); + if (! MAIN_FILE_P (map)) + { + map = INCLUDED_FROM (line_table, map); + 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); + } } } -/* Same as wrap_text but wrap text only when in line-wrapping mode. */ - static void -maybe_wrap_text (buffer, start, end) - output_buffer *buffer; - const char *start; - const char *end; +default_diagnostic_starter (diagnostic_context *context, + diagnostic_info *diagnostic) { - if (output_is_line_wrapping (buffer)) - wrap_text (buffer, start, end); - else - output_append (buffer, start, end); + diagnostic_report_current_function (context, diagnostic); + pp_set_prefix (context->printer, diagnostic_build_prefix (diagnostic)); } - -/* Append a STRING to BUFFER; the STRING might be line-wrapped if in - appropriate mode. */ - -void -output_add_string (buffer, str) - output_buffer *buffer; - const char *str; -{ - maybe_wrap_text (buffer, str, str + (str ? strlen (str) : 0)); -} - -/* Flush the content of BUFFER onto the attached stream, - and reinitialize. */ - static void -output_buffer_to_stream (buffer) - output_buffer *buffer; +default_diagnostic_finalizer (diagnostic_context *context, + diagnostic_info *diagnostic ATTRIBUTE_UNUSED) { - const char *text = output_finalize_message (buffer); - fputs (text, output_buffer_attached_stream (buffer)); - output_clear_message_text (buffer); + pp_destroy_prefix (context->printer); } -/* Format a message pointed to by output_buffer_text_cursor (BUFFER) using - output_buffer_format_args (BUFFER) as appropriate. The following format - specifiers are recognized as being language independent: - %d, %i: (signed) integer in base ten. - %u: unsigned integer in base ten. - %o: unsigned integer in base eight. - %x: unsigned integer in base sixteen. - %ld, %li, %lo, %lu, %lx: long versions of the above. - %c: character. - %s: string. - %%: `%'. - %*.s: a substring the length of which is specified by an integer. */ - -static void -output_format (buffer) - output_buffer *buffer; +/* 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) { - for (; *output_buffer_text_cursor (buffer); - ++output_buffer_text_cursor (buffer)) - { - int long_integer = 0; - - /* Ignore text. */ - { - const char *p = output_buffer_text_cursor (buffer); - while (*p && *p != '%') - ++p; - wrap_text (buffer, output_buffer_text_cursor (buffer), p); - output_buffer_text_cursor (buffer) = p; - } - - if (!*output_buffer_text_cursor (buffer)) - break; - - /* We got a '%'. Let's see what happens. Record whether we're - parsing a long integer format specifier. */ - if (*++output_buffer_text_cursor (buffer) == 'l') - { - long_integer = 1; - ++output_buffer_text_cursor (buffer); - } - - /* Handle %c, %d, %i, %ld, %li, %lo, %lu, %lx, %o, %s, %u, - %x, %.*s; %%. And nothing else. Front-ends should install - printers to grok language specific format specifiers. */ - switch (*output_buffer_text_cursor (buffer)) - { - case 'c': - output_add_character - (buffer, va_arg (output_buffer_format_args (buffer), int)); - break; - - case 'd': - case 'i': - if (long_integer) - output_long_decimal - (buffer, va_arg (output_buffer_format_args (buffer), long int)); - else - output_decimal - (buffer, va_arg (output_buffer_format_args (buffer), int)); - break; - - case 'o': - if (long_integer) - output_long_octal (buffer, - va_arg (output_buffer_format_args (buffer), - unsigned long int)); - else - output_octal (buffer, - va_arg (output_buffer_format_args (buffer), - unsigned int)); - break; - - case 's': - output_add_string (buffer, - va_arg (output_buffer_format_args (buffer), - const char *)); - break; - - case 'u': - if (long_integer) - output_long_unsigned_decimal - (buffer, va_arg (output_buffer_format_args (buffer), - long unsigned int)); - else - output_unsigned_decimal - (buffer, va_arg (output_buffer_format_args (buffer), - unsigned int)); - break; - - case 'x': - if (long_integer) - output_long_hexadecimal - (buffer, va_arg (output_buffer_format_args (buffer), - unsigned long int)); - else - output_hexadecimal - (buffer, va_arg (output_buffer_format_args (buffer), - unsigned int)); - break; - - case '%': - output_add_character (buffer, '%'); - break; - - case '.': - { - int n; - const char *s; - /* We handle no precision specifier but `%.*s'. */ - if (*++output_buffer_text_cursor (buffer) != '*') - abort (); - else if (*++output_buffer_text_cursor (buffer) != 's') - abort (); - n = va_arg (output_buffer_format_args (buffer), int); - s = va_arg (output_buffer_format_args (buffer), const char *); - output_append (buffer, s, s + n); - } - break; - - default: - if (!buffer->format_decoder || !(*buffer->format_decoder) (buffer)) - { - /* Hmmm. The front-end failed to install a format translator - but called us with an unrecognized format. Sorry. */ - abort (); - } - } - } -} + diagnostic_t old_kind; -static char * -vbuild_message_string (msg, ap) - const char *msg; - va_list ap; -{ - char *str; + if (option_index <= 0 + || option_index >= N_OPTS + || new_kind >= DK_LAST_DIAGNOSTIC_KIND) + return DK_UNSPECIFIED; - vasprintf (&str, msg, ap); - return str; + old_kind = context->classify_diagnostic[option_index]; + context->classify_diagnostic[option_index] = new_kind; + return old_kind; } -/* Return a malloc'd string containing MSG formatted a la - printf. The caller is responsible for freeing the memory. */ +/* 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. */ -static char * -build_message_string VPARAMS ((const char *msg, ...)) +bool +diagnostic_report_diagnostic (diagnostic_context *context, + diagnostic_info *diagnostic) { - char *str; - - VA_OPEN (ap, msg); - VA_FIXEDARG (ap, const char *, msg); + location_t location = diagnostic->location; + bool maybe_print_warnings_as_errors_message = false; + const char *saved_format_spec; - str = vbuild_message_string (msg, ap); + /* 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; - VA_CLOSE (ap); - - return str; -} - -/* Return a malloc'd string describing a location. The caller is - responsible for freeing the memory. */ - -char * -context_as_prefix (file, line, warn) - const char *file; - int line; - int warn; -{ - if (file) - { - if (warn) - return build_message_string (_("%s:%d: warning: "), file, line); - else - return build_message_string ("%s:%d: ", file, line); - } - else + if (diagnostic->kind == DK_PEDWARN) + diagnostic->kind = pedantic_warning_kind (); + + if (context->lock > 0) { - if (warn) - return build_message_string (_("%s: warning: "), progname); + /* If we're reporting an ICE in the middle of some other error, + try to flush out the previous error, then let this one + through. Don't do this more than once. */ + if (diagnostic->kind == DK_ICE && context->lock == 1) + pp_flush (context->printer); else - return build_message_string ("%s: ", progname); + error_recursion (context); } -} - -/* Same as context_as_prefix, but only the source FILE is given. */ - -char * -file_name_as_prefix (f) - const char *f; -{ - return build_message_string ("%s: ", f); -} - -/* Format a MESSAGE into BUFFER. Automatically wrap lines. */ - -static void -output_do_printf (buffer, msg) - output_buffer *buffer; - const char *msg; -{ - char *message = vbuild_message_string (msg, - output_buffer_format_args (buffer)); - wrap_text (buffer, message, message + strlen (message)); - free (message); -} - - -/* Format a message into BUFFER a la printf. */ - -void -output_printf VPARAMS ((struct output_buffer *buffer, const char *msgid, ...)) -{ - va_list *old_args; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, output_buffer *, buffer); - VA_FIXEDARG (ap, const char *, msgid); - - old_args = output_buffer_ptr_to_format_args (buffer); - output_buffer_ptr_to_format_args (buffer) = ≈ - output_do_printf (buffer, _(msgid)); - output_buffer_ptr_to_format_args (buffer) = old_args; - VA_CLOSE (ap); -} - -/* Print a message relevant to the given DECL. */ - -static void -format_with_decl (buffer, decl) - output_buffer *buffer; - tree decl; -{ - const char *p; - - /* Do magic to get around lack of varargs support for insertion - of arguments into existing list. We know that the decl is first; - we ass_u_me that it will be printed with "%s". */ - for (p = output_buffer_text_cursor (buffer); *p; ++p) + /* 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) { - if (*p == '%') - { - if (*(p + 1) == '%') - ++p; - else if (*(p + 1) != 's') - abort (); - else - break; - } + diagnostic->kind = DK_ERROR; + maybe_print_warnings_as_errors_message = true; } - - /* Print the left-hand substring. */ - maybe_wrap_text (buffer, output_buffer_text_cursor (buffer), p); - if (*p == '%') /* Print the name. */ + if (diagnostic->option_index) { - const char *const n = (DECL_NAME (decl) - ? (*decl_printable_name) (decl, 2) - : _("((anonymous))")); - output_add_string (buffer, n); - while (*p) + /* 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) { - ++p; - if (ISALPHA (*(p - 1) & 0xFF)) - break; + 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 (*p) /* Print the rest of the message. */ + /* 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) { - output_buffer_text_cursor (buffer) = p; - output_format (buffer); + pp_verbatim (context->printer, + "%s: warnings being treated as errors\n", progname); + context->issue_warnings_are_errors_message = false; } -} + context->lock++; -/* Report a diagnostic MESSAGE at the declaration DECL. - MSG is a format string which uses %s to substitute the declaration - name; subsequent substitutions are a la output_format. */ - -static void -diagnostic_for_decl (decl, msgid, args_ptr, warn) - tree decl; - const char *msgid; - va_list *args_ptr; - int warn; -{ - output_state os; - - if (diagnostic_lock++) - error_recursion (); - - if (count_error (warn)) + if (diagnostic->kind == DK_ICE) { - os = output_buffer_state (diagnostic_buffer); - report_error_function (DECL_SOURCE_FILE (decl)); - output_set_prefix - (diagnostic_buffer, context_as_prefix - (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl), warn)); - output_buffer_ptr_to_format_args (diagnostic_buffer) = args_ptr; - output_buffer_text_cursor (diagnostic_buffer) = _(msgid); - format_with_decl (diagnostic_buffer, decl); - diagnostic_finish ((output_buffer *) global_dc); - output_destroy_prefix (diagnostic_buffer); - - output_buffer_state (diagnostic_buffer) = os; - } - diagnostic_lock--; -} - - -/* Count an error or warning. Return 1 if the message should be printed. */ - -int -count_error (warningp) - int warningp; -{ - if (warningp && !diagnostic_report_warnings_p ()) - return 0; - - if (warningp && !warnings_are_errors) - warningcount++; - else - { - static int warning_message = 0; - - if (warningp && !warning_message) +#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) { - verbatim ("%s: warnings being treated as errors\n", progname); - warning_message = 1; + 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); } - errorcount++; +#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; - return 1; -} - -/* Print a diagnostic MSGID on FILE. This is just fprintf, except it - runs its second argument through gettext. */ - -void -fnotice VPARAMS ((FILE *file, const char *msgid, ...)) -{ - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, FILE *, file); - VA_FIXEDARG (ap, const char *, msgid); + context->lock--; - vfprintf (file, _(msgid), ap); - VA_CLOSE (ap); + return true; } +/* Given a partial pathname as input, return another pathname that + shares no directory elements with the pathname of __FILE__. This + is used by fancy_abort() to print `Internal compiler error in expr.c' + instead of `Internal compiler error in ../../GCC/gcc/expr.c'. */ -/* Print a fatal I/O error message. Argument are like printf. - Also include a system error message based on `errno'. */ - -void -fatal_io_error VPARAMS ((const char *msgid, ...)) +const char * +trim_filename (const char *name) { - output_state os; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); - - os = output_buffer_state (diagnostic_buffer); - - output_printf (diagnostic_buffer, "%s: %s: ", progname, xstrerror (errno)); - output_buffer_ptr_to_format_args (diagnostic_buffer) = ≈ - output_buffer_text_cursor (diagnostic_buffer) = _(msgid); - output_format (diagnostic_buffer); - diagnostic_finish ((output_buffer *) global_dc); - output_buffer_state (diagnostic_buffer) = os; - VA_CLOSE (ap); - exit (FATAL_EXIT_CODE); -} - -/* Issue a pedantic warning MSGID. */ + static const char this_file[] = __FILE__; + const char *p = name, *q = this_file; -void -pedwarn VPARAMS ((const char *msgid, ...)) -{ - diagnostic_context dc; + /* First skip any "../" in each filename. This allows us to give a proper + reference to a file in a subdirectory. */ + while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2])) + p += 3; - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); + while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2])) + q += 3; - set_diagnostic_context - (&dc, msgid, &ap, input_filename, lineno, !flag_pedantic_errors); - report_diagnostic (&dc); - VA_CLOSE (ap); -} + /* Now skip any parts the two filenames have in common. */ + while (*p == *q && *p != 0 && *q != 0) + p++, q++; -/* Issue a pedantic waring about DECL. */ + /* Now go backwards until the previous directory separator. */ + while (p > name && !IS_DIR_SEPARATOR (p[-1])) + p--; -void -pedwarn_with_decl VPARAMS ((tree decl, const char *msgid, ...)) -{ - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, tree, decl); - VA_FIXEDARG (ap, const char *, msgid); - - /* We don't want -pedantic-errors to cause the compilation to fail from - "errors" in system header files. Sometimes fixincludes can't fix what's - broken (eg: unsigned char bitfields - fixing it may change the alignment - which will cause programs to mysteriously fail because the C library - or kernel uses the original layout). There's no point in issuing a - warning either, it's just unnecessary noise. */ - if (!DECL_IN_SYSTEM_HEADER (decl)) - diagnostic_for_decl (decl, msgid, &ap, !flag_pedantic_errors); - VA_CLOSE (ap); + return p; } + +/* Standard error reporting routines in increasing order of severity. + All of these take arguments like printf. */ -/* Same as above but within the context FILE and LINE. */ - +/* Text to be emitted verbatim to the error message stream; this + produces no prefix and disables line-wrapping. Use rarely. */ void -pedwarn_with_file_and_line VPARAMS ((const char *file, int line, - const char *msgid, ...)) +verbatim (const char *gmsgid, ...) { - diagnostic_context dc; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, file); - VA_FIXEDARG (ap, int, line); - VA_FIXEDARG (ap, const char *, msgid); - - set_diagnostic_context (&dc, msgid, &ap, file, line, !flag_pedantic_errors); - report_diagnostic (&dc); - VA_CLOSE (ap); -} - -/* Just apologize with MSGID. */ + text_info text; + va_list ap; -void -sorry VPARAMS ((const char *msgid, ...)) -{ - output_state os; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); - - ++sorrycount; - os = output_buffer_state (diagnostic_buffer); - - output_set_prefix - (diagnostic_buffer, context_as_prefix (input_filename, lineno, 0)); - output_printf (diagnostic_buffer, "sorry, not implemented: "); - output_buffer_ptr_to_format_args (diagnostic_buffer) = ≈ - output_buffer_text_cursor (diagnostic_buffer) = _(msgid); - output_format (diagnostic_buffer); - diagnostic_finish ((output_buffer *) global_dc); - output_buffer_state (diagnostic_buffer) = os; - VA_CLOSE (ap); + va_start (ap, gmsgid); + text.err_no = errno; + 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); } -/* Called when the start of a function definition is parsed, - this function prints on stderr the name of the function. */ - -void -announce_function (decl) - tree decl; +bool +emit_diagnostic (diagnostic_t kind, location_t location, int opt, + const char *gmsgid, ...) { - if (! quiet_flag) - { - if (rtl_dump_and_exit) - verbatim ("%s ", IDENTIFIER_POINTER (DECL_NAME (decl))); - else - verbatim (" %s", (*decl_printable_name) (decl, 2)); - fflush (stderr); - output_needs_newline (diagnostic_buffer) = 1; - record_last_error_function (); - } -} - -/* The default function to print out name of current function that caused - an error. */ + diagnostic_info diagnostic; + va_list ap; -void -default_print_error_function (context, file) - diagnostic_context *context; - const char *file; -{ - if (error_function_changed ()) + va_start (ap, gmsgid); + if (kind == DK_PERMERROR) { - char *prefix = file ? build_message_string ("%s: ", file) : NULL; - output_state os; - - os = output_buffer_state (context); - output_set_prefix ((output_buffer *) context, prefix); - - if (current_function_decl == NULL) - output_add_string ((output_buffer *) context, _("At top level:")); - else - { - if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE) - output_printf - ((output_buffer *) context, "In member function `%s':", - (*decl_printable_name) (current_function_decl, 2)); - else - output_printf - ((output_buffer *) context, "In function `%s':", - (*decl_printable_name) (current_function_decl, 2)); - } - output_add_newline ((output_buffer *) context); - - record_last_error_function (); - output_buffer_to_stream ((output_buffer *) context); - output_buffer_state (context) = os; - free ((char*) prefix); + 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); -/* Prints out, if necessary, the name of the current function - that caused an error. Called from all error and warning functions. - We ignore the FILE parameter, as it cannot be relied upon. */ - -void -report_error_function (file) - const char *file ATTRIBUTE_UNUSED; -{ - report_problematic_module ((output_buffer *) global_dc); - (*print_error_function) (global_dc, input_filename); + return report_diagnostic (&diagnostic); } +/* An informative note at LOCATION. Use this for additional details on an error + message. */ void -error_with_file_and_line VPARAMS ((const char *file, int line, - const char *msgid, ...)) +inform (location_t location, const char *gmsgid, ...) { - diagnostic_context dc; + diagnostic_info diagnostic; + va_list ap; - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, file); - VA_FIXEDARG (ap, int, line); - VA_FIXEDARG (ap, const char *, msgid); - - set_diagnostic_context (&dc, msgid, &ap, file, line, /* warn = */ 0); - report_diagnostic (&dc); - VA_CLOSE (ap); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_NOTE); + report_diagnostic (&diagnostic); + va_end (ap); } -void -error_with_decl VPARAMS ((tree decl, const char *msgid, ...)) +/* 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, ...) { - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, tree, decl); - VA_FIXEDARG (ap, const char *, msgid); - - diagnostic_for_decl (decl, msgid, &ap, /* warn = */ 0); - VA_CLOSE (ap); -} - + diagnostic_info diagnostic; + va_list ap; -/* Report an error message. The arguments are like that of printf. */ + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING); + diagnostic.option_index = opt; -void -error VPARAMS ((const char *msgid, ...)) -{ - diagnostic_context dc; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); - - set_diagnostic_context - (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 0); - report_diagnostic (&dc); - VA_CLOSE (ap); + va_end (ap); + return report_diagnostic (&diagnostic); } -/* Likewise, except that the compilation is terminated after printing the - error message. */ +/* 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. */ -void -fatal_error VPARAMS ((const char *msgid, ...)) +bool +warning_at (location_t location, int opt, const char *gmsgid, ...) { - diagnostic_context dc; + diagnostic_info diagnostic; + va_list ap; - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); - - set_diagnostic_context - (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 0); - report_diagnostic (&dc); - VA_CLOSE (ap); - - fnotice (stderr, "compilation terminated.\n"); - exit (FATAL_EXIT_CODE); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_WARNING); + diagnostic.option_index = opt; + va_end (ap); + return report_diagnostic (&diagnostic); } -/* Report a compiler error at the current line number. Allow a front end to - intercept the message. */ +/* 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. -static void (*internal_error_function) PARAMS ((const char *, va_list *)); + 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, use either "if (pedantic) pedwarn + (OPT_pedantic,...)" or just "pedwarn (OPT_pedantic,..)". To get a + pedwarn independently of the -pedantic switch use "pedwarn (0,...)". -/* Set the function to call when a compiler error occurs. */ + Returns true if the warning was printed, false if it was inhibited. */ -void -set_internal_error_function (f) - void (*f) PARAMS ((const char *, va_list *)); +bool +pedwarn (location_t location, int opt, const char *gmsgid, ...) { - internal_error_function = f; -} - -void -internal_error VPARAMS ((const char *msgid, ...)) -{ - diagnostic_context dc; + diagnostic_info diagnostic; + va_list ap; - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN); + diagnostic.option_index = opt; + va_end (ap); + return report_diagnostic (&diagnostic); +} - if (diagnostic_lock) - error_recursion (); +/* 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. -#ifndef ENABLE_CHECKING - if (errorcount > 0 || sorrycount > 0) - { - fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n", - input_filename, lineno); - exit (FATAL_EXIT_CODE); - } -#endif + Returns true if the warning was printed, false if it was inhibited. */ - if (internal_error_function != 0) - (*internal_error_function) (_(msgid), &ap); - - set_diagnostic_context - (&dc, msgid, &ap, input_filename, lineno, /* warn = */0); - report_diagnostic (&dc); - VA_CLOSE (ap); +bool +permerror (location_t location, const char *gmsgid, ...) +{ + diagnostic_info diagnostic; + va_list ap; - fnotice (stderr, -"Please submit a full bug report,\n\ -with preprocessed source if appropriate.\n\ -See %s for instructions.\n", GCCBUGURL); - exit (FATAL_EXIT_CODE); + 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 + will not be produced. */ void -warning_with_file_and_line VPARAMS ((const char *file, int line, - const char *msgid, ...)) +error (const char *gmsgid, ...) { - diagnostic_context dc; + diagnostic_info diagnostic; + va_list ap; - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, file); - VA_FIXEDARG (ap, int, line); - VA_FIXEDARG (ap, const char *, msgid); - - set_diagnostic_context (&dc, msgid, &ap, file, line, /* warn = */ 1); - report_diagnostic (&dc); - VA_CLOSE (ap); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ERROR); + report_diagnostic (&diagnostic); + va_end (ap); } +/* Same as ebove, but use location LOC instead of input_location. */ void -warning_with_decl VPARAMS ((tree decl, const char *msgid, ...)) +error_at (location_t loc, const char *gmsgid, ...) { - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, tree, decl); - VA_FIXEDARG (ap, const char *, msgid); + diagnostic_info diagnostic; + va_list ap; - diagnostic_for_decl (decl, msgid, &ap, /* warn = */ 1); - VA_CLOSE (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. */ void -warning VPARAMS ((const char *msgid, ...)) +sorry (const char *gmsgid, ...) { - diagnostic_context dc; - - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); + diagnostic_info diagnostic; + va_list ap; - set_diagnostic_context - (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 1); - report_diagnostic (&dc); - VA_CLOSE (ap); + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_SORRY); + report_diagnostic (&diagnostic); + va_end (ap); } -/* Flush diagnostic_buffer content on stderr. */ - -static void -diagnostic_finish (buffer) - output_buffer *buffer; +/* An error which is severe enough that we make no attempt to + continue. Do not use this for internal consistency checks; that's + internal_error. Use of this function should be rare. */ +void +fatal_error (const char *gmsgid, ...) { - output_buffer_to_stream (buffer); - clear_diagnostic_info (buffer); - fputc ('\n', output_buffer_attached_stream (buffer)); - fflush (output_buffer_attached_stream (buffer)); -} + diagnostic_info diagnostic; + va_list ap; -/* Helper subroutine of output_verbatim and verbatim. Do the appropriate - settings needed by BUFFER for a verbatim formatting. */ + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_FATAL); + report_diagnostic (&diagnostic); + va_end (ap); -static void -output_do_verbatim (buffer, msgid, args_ptr) - output_buffer *buffer; - const char *msgid; - va_list *args_ptr; -{ - output_state os; - - os = output_buffer_state (buffer); - output_prefix (buffer) = NULL; - diagnostic_prefixing_rule (buffer) = DIAGNOSTICS_SHOW_PREFIX_NEVER; - output_buffer_text_cursor (buffer) = _(msgid); - output_buffer_ptr_to_format_args (buffer) = args_ptr; - output_set_maximum_length (buffer, 0); - output_format (buffer); - output_buffer_state (buffer) = os; + gcc_unreachable (); } -/* Output MESSAGE verbatim into BUFFER. */ - +/* An internal consistency check has failed. We make no attempt to + continue. Note that unless there is debugging value to be had from + a more specific message, or some other good reason, you should use + abort () instead of calling this function directly. */ void -output_verbatim VPARAMS ((output_buffer *buffer, const char *msgid, ...)) +internal_error (const char *gmsgid, ...) { - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, output_buffer *, buffer); - VA_FIXEDARG (ap, const char *, msgid); + diagnostic_info diagnostic; + va_list ap; - output_do_verbatim (buffer, msgid, &ap); - VA_CLOSE (ap); -} + va_start (ap, gmsgid); + diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ICE); + report_diagnostic (&diagnostic); + va_end (ap); -/* Same as above but use diagnostic_buffer. */ - -void -verbatim VPARAMS ((const char *msgid, ...)) -{ - VA_OPEN (ap, msgid); - VA_FIXEDARG (ap, const char *, msgid); - - output_do_verbatim (diagnostic_buffer, msgid, &ap); - output_buffer_to_stream (diagnostic_buffer); - VA_CLOSE (ap); + gcc_unreachable (); } + +/* Special case error functions. Most are implemented in terms of the + above, or should be. */ -/* 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. */ - +/* Print a diagnostic MSGID on FILE. This is just fprintf, except it + runs its second argument through gettext. */ void -report_diagnostic (dc) - diagnostic_context *dc; +fnotice (FILE *file, const char *cmsgid, ...) { - output_state os; - - if (diagnostic_lock++) - error_recursion (); - - if (count_error (diagnostic_is_warning (dc))) - { - os = output_buffer_state (diagnostic_buffer); - diagnostic_msg = diagnostic_message (dc); - diagnostic_args = diagnostic_argument_list (dc); - (*diagnostic_starter (dc)) (diagnostic_buffer, dc); - output_format (diagnostic_buffer); - (*diagnostic_finalizer (dc)) (diagnostic_buffer, dc); - diagnostic_finish ((output_buffer *) global_dc); - output_buffer_state (diagnostic_buffer) = os; - } + va_list ap; - diagnostic_lock--; + va_start (ap, cmsgid); + vfprintf (file, _(cmsgid), ap); + va_end (ap); } /* Inform the user that an error occurred while trying to report some @@ -1381,182 +682,42 @@ report_diagnostic (dc) This mustn't use internal_error, that will cause infinite recursion. */ static void -error_recursion () +error_recursion (diagnostic_context *context) { - if (diagnostic_lock < 3) - diagnostic_finish ((output_buffer *) global_dc); + diagnostic_info diagnostic; + + if (context->lock < 3) + pp_flush (context->printer); fnotice (stderr, "Internal compiler error: Error reporting routines re-entered.\n"); - fnotice (stderr, -"Please submit a full bug report,\n\ -with preprocessed source if appropriate.\n\ -See %s for instructions.\n", GCCBUGURL); - exit (FATAL_EXIT_CODE); -} - -/* Given a partial pathname as input, return another pathname that - shares no directory elements with the pathname of __FILE__. This - is used by fancy_abort() to print `Internal compiler error in expr.c' - instead of `Internal compiler error in ../../GCC/gcc/expr.c'. */ - -const char * -trim_filename (name) - const char *name; -{ - static const char this_file[] = __FILE__; - const char *p = name, *q = this_file; - - /* First skip any "../" in each filename. This allows us to give a proper - reference to a file in a subdirectory. */ - while (p[0] == '.' && p[1] == '.' - && (p[2] == DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - || p[2] == DIR_SEPARATOR_2 -#endif - )) - p += 3; - - while (q[0] == '.' && q[1] == '.' - && (q[2] == DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - || p[2] == DIR_SEPARATOR_2 -#endif - )) - q += 3; - - /* Now skip any parts the two filenames have in common. */ - while (*p == *q && *p != 0 && *q != 0) - p++, q++; - - /* Now go backwards until the previous directory separator. */ - while (p > name && p[-1] != DIR_SEPARATOR -#ifdef DIR_SEPARATOR_2 - && p[-1] != DIR_SEPARATOR_2 -#endif - ) - p--; - - return p; -} -/* Report an internal compiler error in a friendly manner and without - dumping core. */ + /* Call diagnostic_action_after_output to get the "please submit a bug + report" message. It only looks at the kind field of diagnostic_info. */ + diagnostic.kind = DK_ICE; + diagnostic_action_after_output (context, &diagnostic); -void -fancy_abort (file, line, function) - const char *file; - int line; - const char *function; -{ - internal_error ("Internal compiler error in %s, at %s:%d", - function, trim_filename (file), line); + /* Do not use gcc_unreachable here; that goes through internal_error + and therefore would cause infinite recursion. */ + real_abort (); } -/* Setup DC for reporting a diagnostic MESSAGE (an error or a WARNING), - using arguments pointed to by ARGS_PTR, issued at a location specified - by FILE and LINE. */ +/* Report an internal compiler error in a friendly manner. This is + the function that gets called upon use of abort() in the source + code generally, thanks to a special macro. */ void -set_diagnostic_context (dc, msgid, args_ptr, file, line, warn) - diagnostic_context *dc; - const char *msgid; - va_list *args_ptr; - const char *file; - int line; - int warn; -{ - memset (dc, 0, sizeof (diagnostic_context)); - diagnostic_message (dc) = _(msgid); - diagnostic_argument_list (dc) = args_ptr; - diagnostic_file_location (dc) = file; - diagnostic_line_location (dc) = line; - diagnostic_is_warning (dc) = warn; - diagnostic_starter (dc) = diagnostic_starter (global_dc); - diagnostic_finalizer (dc) = diagnostic_finalizer (global_dc); -} - -void -report_problematic_module (buffer) - output_buffer *buffer; -{ - struct file_stack *p; - - if (output_needs_newline (buffer)) - { - output_add_newline (buffer); - output_needs_newline (buffer) = 0; - } - - if (input_file_stack && input_file_stack->next != 0 - && error_module_changed ()) - { - for (p = input_file_stack->next; p; p = p->next) - if (p == input_file_stack->next) - output_verbatim - (buffer, "In file included from %s:%d", p->name, p->line); - else - output_verbatim - (buffer, ",\n from %s:%d", p->name, p->line); - output_verbatim (buffer, ":\n"); - record_last_error_module (); - } -} - -static void -default_diagnostic_starter (buffer, dc) - output_buffer *buffer; - diagnostic_context *dc; +fancy_abort (const char *file, int line, const char *function) { - report_error_function (diagnostic_file_location (dc)); - output_set_prefix (buffer, - context_as_prefix (diagnostic_file_location (dc), - diagnostic_line_location (dc), - diagnostic_is_warning (dc))); + internal_error ("in %s, at %s:%d", function, trim_filename (file), line); } +/* Really call the system 'abort'. This has to go right at the end of + this file, so that there are no functions after it that call abort + and get the system abort instead of our macro. */ +#undef abort static void -default_diagnostic_finalizer (buffer, dc) - output_buffer *buffer; - diagnostic_context *dc __attribute__((__unused__)); +real_abort (void) { - output_destroy_prefix (buffer); -} - -void -warn_deprecated_use (node) - tree node; -{ - if (node == 0 || !warn_deprecated_decl) - return; - - if (DECL_P (node)) - warning ("`%s' is deprecated (declared at %s:%d)", - IDENTIFIER_POINTER (DECL_NAME (node)), - DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node)); - else if (TYPE_P (node)) - { - const char *what = NULL; - tree decl = TYPE_STUB_DECL (node); - - if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) - what = IDENTIFIER_POINTER (TYPE_NAME (node)); - else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (node))) - what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))); - - if (what) - { - if (decl) - warning ("`%s' is deprecated (declared at %s:%d)", what, - DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); - else - warning ("`%s' is deprecated", what); - } - else if (decl) - warning ("type is deprecated (declared at %s:%d)", - DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); - else - warning ("type is deprecated"); - } + abort (); }