OSDN Git Service

update copyrights
[pf3gnuchains/gcc-fork.git] / gcc / diagnostic.c
index fbaaec6..11591ec 100644 (file)
@@ -67,17 +67,20 @@ static void output_do_verbatim PARAMS ((output_buffer *,
                                         const char *, va_list *));
 static void output_to_stream PARAMS ((output_buffer *, FILE *));
 static void output_format PARAMS ((output_buffer *));
+static void output_indent PARAMS ((output_buffer *));
 
-static char *vbuild_message_string PARAMS ((const char *, va_list));
+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 char *context_as_prefix PARAMS ((const char *, int, int));
-static void output_do_printf PARAMS ((output_buffer *, const char *));
+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 file_and_line_for_asm PARAMS ((rtx, const char **, int *));
 static void diagnostic_for_asm PARAMS ((rtx, const char *, va_list *, int));
 static void diagnostic_for_decl PARAMS ((tree, const char *, va_list *, int));
-static void vnotice PARAMS ((FILE *, const char *, va_list));
+static void vnotice PARAMS ((FILE *, const char *, va_list))
+     ATTRIBUTE_PRINTF (2, 0);
 static void set_real_maximum_length PARAMS ((output_buffer *));
                                           
 static void output_unsigned_decimal PARAMS ((output_buffer *, unsigned int));
@@ -93,9 +96,13 @@ 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_text_info PARAMS ((output_buffer *));
 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;
 static const char *trim_filename PARAMS ((const char *));
 
@@ -116,8 +123,6 @@ static char digit_buffer[128];
 static output_buffer global_output_buffer;
 output_buffer *diagnostic_buffer = &global_output_buffer;
 
-static int need_error_newline;
-
 /* 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.  */
@@ -132,19 +137,57 @@ static int last_error_tick;
 void (*print_error_function) PARAMS ((const char *)) =
   default_print_error_function;
 
+/* Hooks for language specific diagnostic messages pager and finalizer.  */
+diagnostic_starter_fn lang_diagnostic_starter;
+diagnostic_finalizer_fn lang_diagnostic_finalizer;
+
 /* Maximum characters per line in automatic line wrapping mode.
    Zero means don't wrap lines. */
 
 int diagnostic_message_length_per_line;
 
 /* Used to control every diagnostic message formatting.  Front-ends should
-   call set_message_prefixing_rule to set up their politics.  */
+   call set_message_prefixing_rule to set up their policies.  */
 static int current_prefixing_rule;
 
 /* Prevent recursion into the error handler.  */
 static int diagnostic_lock;
 
 \f
+/* Return truthvalue if current input file is different from the most recent
+   file involved in a diagnostic message.  */
+
+int
+error_module_changed ()
+{
+  return last_error_tick != input_file_stack_tick;
+}
+
+/* Remember current file as being the most recent file involved in a
+   diagnostic message.  */
+
+void
+record_last_error_module ()
+{
+  last_error_tick = input_file_stack_tick;
+}
+
+/* Same as error_module_changed, but for function.  */
+
+int
+error_function_changed ()
+{
+  return last_error_function != current_function_decl;
+}
+
+/* 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
@@ -156,6 +199,9 @@ initialize_diagnostics ()
 
   /* Proceed to actual initialization.  */
   default_initialize_buffer (diagnostic_buffer);
+
+  lang_diagnostic_starter = default_diagnostic_starter;
+  lang_diagnostic_finalizer = default_diagnostic_finalizer;
 }
 
 void
@@ -190,8 +236,12 @@ static void
 set_real_maximum_length (buffer)
      output_buffer *buffer;
 {
-  /* If we're told not to wrap lines then do the obvious thing.  */
-  if (! output_is_line_wrapping (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 unncessarily the line-length cut-off.  */
+  if (! output_is_line_wrapping (buffer)
+      || prefixing_policy (buffer) == DIAGNOSTICS_SHOW_PREFIX_ONCE
+      || prefixing_policy (buffer) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
     line_wrap_cutoff (buffer) = ideal_line_wrap_cutoff (buffer);
   else
     {
@@ -228,6 +278,20 @@ output_set_prefix (buffer, prefix)
   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;
 }
 
 /* Free BUFFER's prefix, a previously malloc'd string.  */
@@ -245,8 +309,8 @@ output_destroy_prefix (buffer)
 
 /* Zero out any text output so far in BUFFER.  */
 
-static void
-clear_text_info (buffer)
+void
+output_clear_message_text (buffer)
      output_buffer *buffer;
 {
   obstack_free (&buffer->obstack, obstack_base (&buffer->obstack));
@@ -262,6 +326,7 @@ clear_diagnostic_info (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
@@ -273,6 +338,7 @@ init_output_buffer (buffer, prefix, maximum_length)
      const char *prefix;
      int maximum_length;
 {
+  memset (buffer, 0, sizeof (output_buffer));
   obstack_init (&buffer->obstack);
   ideal_line_wrap_cutoff (buffer) = maximum_length;
   prefixing_policy (buffer) = current_prefixing_rule;
@@ -283,6 +349,7 @@ init_output_buffer (buffer, prefix, maximum_length)
 
 /* Initialize BUFFER with a NULL prefix and current diagnostic message
    length cutoff.  */
+
 void
 default_initialize_buffer (buffer)
      output_buffer *buffer;
@@ -303,23 +370,31 @@ reshape_diagnostic_buffer ()
 }
 
 /* Reinitialize BUFFER.  */
+
 void
 output_clear (buffer)
      output_buffer *buffer;
 {
-  clear_text_info (buffer);
+  output_clear_message_text (buffer);
   clear_diagnostic_info (buffer);
 }
 
-/* Finishes to construct a NULL-terminated character string representing
+/* Finishes constructing a NULL-terminated character string representing
    the BUFFERed message.  */
 
 const char *
-output_finish (buffer)
+output_finalize_message (buffer)
      output_buffer *buffer;
 {
   obstack_1grow (&buffer->obstack, '\0');
-  return (const char *) obstack_finish (&buffer->obstack);
+  return output_message_text (buffer);
+}
+
+void
+flush_diagnostic_buffer ()
+{
+  output_to_stream (diagnostic_buffer, stderr);
+  fflush (stderr);
 }
 
 /* Return the amount of characters BUFFER can accept to
@@ -348,8 +423,12 @@ output_emit_prefix (buffer)
 
         case DIAGNOSTICS_SHOW_PREFIX_ONCE:
           if (prefix_was_emitted_for (buffer))
-            break;
-          /* Else fall through.  */
+            {
+              output_indent (buffer);
+              break;
+            }
+          output_indentation (buffer) += 3;          
+          /* Fall through.  */
 
         case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
           {
@@ -502,6 +581,17 @@ output_append (buffer, start, end)
   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.  */
 
 static void
@@ -510,6 +600,8 @@ wrap_text (buffer, start, end)
      const char *start;
      const char *end;
 {
+  int is_wrapping = output_is_line_wrapping (buffer);
+  
   while (start != end)
     {
       /* Dump anything bodered by whitespaces.  */ 
@@ -517,7 +609,7 @@ wrap_text (buffer, start, end)
         const char *p = start;
         while (p != end && *p != ' ' && *p != '\n')
           ++p;
-        if (p - start >= output_space_left (buffer))
+        if (is_wrapping && p - start >= output_space_left (buffer))
           output_add_newline (buffer);
         output_append (buffer, start, p);
         start = p;
@@ -537,6 +629,7 @@ wrap_text (buffer, start, end)
 }
 
 /* Same as wrap_text but wrap text only when in line-wrapping mode.  */
+
 static void
 maybe_wrap_text (buffer, start, end)
      output_buffer *buffer;
@@ -550,7 +643,7 @@ maybe_wrap_text (buffer, start, end)
 }
 
 
-/* Append a STRING to BUFFER; the STRING maybe be line-wrapped if in
+/* Append a STRING to BUFFER; the STRING might be line-wrapped if in
    appropriate mode.  */
 
 void
@@ -568,14 +661,14 @@ output_to_stream (buffer, file)
      output_buffer *buffer;
      FILE *file;
 {
-  const char *text = output_finish (buffer);
+  const char *text = output_finalize_message (buffer);
   fputs (text, file);
-  clear_text_info (buffer);
+  output_clear_message_text (buffer);
 }
 
 /* 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:
+   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.
@@ -600,7 +693,7 @@ output_format (buffer)
         const char *p = output_buffer_text_cursor (buffer);
         while (*p && *p != '%')
           ++p;
-        maybe_wrap_text (buffer, output_buffer_text_cursor (buffer), p);
+        wrap_text (buffer, output_buffer_text_cursor (buffer), p);
         output_buffer_text_cursor (buffer) = p;
       }
 
@@ -661,6 +754,7 @@ output_format (buffer)
             output_unsigned_decimal
               (buffer, va_arg (output_buffer_format_args (buffer),
                                unsigned int));
+          break;
           
         case 'x':
           if (long_integer)
@@ -739,11 +833,10 @@ build_message_string VPARAMS ((const char *msgid, ...))
   return str;
 }
 
-
 /* Return a malloc'd string describing a location.  The caller is
    responsible for freeing the memory.  */
 
-static char *
+char *
 context_as_prefix (file, line, warn)
      const char *file;
      int line;
@@ -765,6 +858,15 @@ context_as_prefix (file, line, warn)
     }
 }
 
+/* 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
@@ -775,7 +877,7 @@ output_do_printf (buffer, msgid)
   char *message = vbuild_message_string (msgid,
                                          output_buffer_format_args (buffer));
 
-  output_add_string (buffer, message);
+  wrap_text (buffer, message, message + strlen (message));
   free (message);
 }
 
@@ -912,11 +1014,12 @@ diagnostic_for_asm (insn, msg, args_ptr, warn)
      va_list *args_ptr;
      int warn;
 {
-  const char *file;
-  int line;
+  diagnostic_context dc;
 
-  file_and_line_for_asm (insn, &file, &line);
-  report_diagnostic (msg, args_ptr, file, line, warn);
+  set_diagnostic_context (&dc, msg, args_ptr, NULL, 0, warn);
+  file_and_line_for_asm (insn, &diagnostic_file_location (&dc),
+                         &diagnostic_line_location (&dc));
+  report_diagnostic (&dc);
 }
 
 /* Report a diagnostic MESSAGE at the declaration DECL.
@@ -937,7 +1040,7 @@ diagnostic_for_decl (decl, msg, args_ptr, warn)
 
   if (count_error (warn))
     {
-      os = diagnostic_buffer->state;
+      os = output_buffer_state (diagnostic_buffer);
       report_error_function (DECL_SOURCE_FILE (decl));
       output_set_prefix
        (diagnostic_buffer, context_as_prefix
@@ -948,7 +1051,7 @@ diagnostic_for_decl (decl, msg, args_ptr, warn)
       finish_diagnostic ();
       output_destroy_prefix (diagnostic_buffer);
   
-      diagnostic_buffer->state = os;
+      output_buffer_state (diagnostic_buffer) = os;
     }
   diagnostic_lock--;
 }
@@ -960,7 +1063,9 @@ int
 count_error (warningp)
      int warningp;
 {
-  if (warningp && inhibit_warnings)
+  if (warningp
+      && (inhibit_warnings
+          || (in_system_header && !warn_system_headers)))
     return 0;
 
   if (warningp && !warnings_are_errors)
@@ -1032,6 +1137,7 @@ pedwarn VPARAMS ((const char *msgid, ...))
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1039,8 +1145,9 @@ pedwarn VPARAMS ((const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, input_filename, lineno,
-                     !flag_pedantic_errors);
+  set_diagnostic_context
+    (&dc, msgid, &ap, input_filename, lineno, !flag_pedantic_errors);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
@@ -1084,6 +1191,7 @@ pedwarn_with_file_and_line VPARAMS ((const char *file, int line,
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1093,7 +1201,8 @@ pedwarn_with_file_and_line VPARAMS ((const char *file, int line,
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, file, line, !flag_pedantic_errors);
+  set_diagnostic_context (&dc, msgid, &ap, file, line, !flag_pedantic_errors);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
@@ -1108,7 +1217,7 @@ sorry VPARAMS ((const char *msgid, ...))
   va_list ap;
   output_state os;
 
-  os = diagnostic_buffer->state;
+  os = output_buffer_state (diagnostic_buffer);
   VA_START (ap, msgid);
 
 #ifndef ANSI_PROTOTYPES
@@ -1122,7 +1231,7 @@ sorry VPARAMS ((const char *msgid, ...))
   output_buffer_text_cursor (diagnostic_buffer) = msgid;
   output_format (diagnostic_buffer);
   finish_diagnostic ();
-  diagnostic_buffer->state = os;
+  output_buffer_state (diagnostic_buffer) = os;
   va_end (ap);
 }
 
@@ -1140,8 +1249,8 @@ announce_function (decl)
       else
         verbatim (" %s", (*decl_printable_name) (decl, 2));
       fflush (stderr);
-      need_error_newline = 1;
-      last_error_function = current_function_decl;
+      output_needs_newline (diagnostic_buffer) = 1;
+      record_last_error_function ();
     }
 }
 
@@ -1152,34 +1261,32 @@ void
 default_print_error_function (file)
   const char *file;
 {
-  if (last_error_function != current_function_decl)
+  if (error_function_changed ())
     {
       char *prefix = file ? build_message_string ("%s: ", file) : NULL;
       output_state os;
 
-      os = diagnostic_buffer->state;
+      os = output_buffer_state (diagnostic_buffer);
       output_set_prefix (diagnostic_buffer, prefix);
       
       if (current_function_decl == NULL)
-        {
           output_add_string (diagnostic_buffer, "At top level:");
-          output_add_newline (diagnostic_buffer);
-        }
       else
        {
          if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
             output_printf
-              (diagnostic_buffer, "In method `%s':\n",
+              (diagnostic_buffer, "In method `%s':",
                (*decl_printable_name) (current_function_decl, 2));
          else
             output_printf
-              (diagnostic_buffer, "In function `%s':\n",
+              (diagnostic_buffer, "In function `%s':",
                (*decl_printable_name) (current_function_decl, 2));
        }
+      output_add_newline (diagnostic_buffer);
 
-      last_error_function = current_function_decl;
+      record_last_error_function ();
       output_to_stream (diagnostic_buffer, stderr);
-      diagnostic_buffer->state = os;
+      output_buffer_state (diagnostic_buffer) = os;
       free ((char*) prefix);
     }
 }
@@ -1192,26 +1299,7 @@ void
 report_error_function (file)
   const char *file ATTRIBUTE_UNUSED;
 {
-  struct file_stack *p;
-
-  if (need_error_newline)
-    {
-      verbatim ("\n");
-      need_error_newline = 0;
-    }
-
-  if (input_file_stack && input_file_stack->next != 0
-      && input_file_stack_tick != last_error_tick)
-    {
-      for (p = input_file_stack->next; p; p = p->next)
-       if (p == input_file_stack->next)
-         verbatim ("In file included from %s:%d", p->name, p->line);
-       else
-         verbatim (",\n                 from %s:%d", p->name, p->line);
-      verbatim (":\n");
-      last_error_tick = input_file_stack_tick;
-    }
-
+  report_problematic_module (diagnostic_buffer);
   (*print_error_function) (input_filename);
 }
 
@@ -1225,6 +1313,7 @@ error_with_file_and_line VPARAMS ((const char *file, int line,
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1234,7 +1323,8 @@ error_with_file_and_line VPARAMS ((const char *file, int line,
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, file, line, /* warn = */ 0);
+  set_diagnostic_context (&dc, msgid, &ap, file, line, /* warn = */ 0);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
@@ -1285,6 +1375,7 @@ error VPARAMS ((const char *msgid, ...))
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1292,7 +1383,9 @@ error VPARAMS ((const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, input_filename, lineno, /* warn = */ 0);
+  set_diagnostic_context
+    (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 0);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
@@ -1317,6 +1410,7 @@ fatal VPARAMS ((const char *msgid, ...))
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1324,11 +1418,23 @@ fatal VPARAMS ((const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-   if (fatal_function != 0)
-     (*fatal_function) (_(msgid), &ap);
+  if (errorcount > 1 || sorrycount > 0)
+    {
+      fprintf (stderr, "confused by earlier errors, bailing out\n");
+      exit (FATAL_EXIT_CODE);
+    }
 
-  report_diagnostic (msgid, &ap, input_filename, lineno, 0);
+  if (fatal_function != 0)
+    (*fatal_function) (_(msgid), &ap);
+  
+  set_diagnostic_context
+    (&dc, msgid, &ap, input_filename, lineno, /* warn = */0);
+  report_diagnostic (&dc);
   va_end (ap);
+
+  fprintf
+    (stderr, "Please submit a full bug report.\n See %s for instructions.\n",
+     GCCBUGURL);
   exit (FATAL_EXIT_CODE);
 }
 
@@ -1369,6 +1475,7 @@ warning_with_file_and_line VPARAMS ((const char *file, int line,
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1378,7 +1485,8 @@ warning_with_file_and_line VPARAMS ((const char *file, int line,
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, file, line, /* warn = */ 1);
+  set_diagnostic_context (&dc, msgid, &ap, file, line, /* warn = */ 1);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
@@ -1429,6 +1537,7 @@ warning VPARAMS ((const char *msgid, ...))
   const char *msgid;
 #endif
   va_list ap;
+  diagnostic_context dc;
 
   VA_START (ap, msgid);
 
@@ -1436,11 +1545,14 @@ warning VPARAMS ((const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  report_diagnostic (msgid, &ap, input_filename, lineno, /* warn = */ 1);
+  set_diagnostic_context
+    (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 1);
+  report_diagnostic (&dc);
   va_end (ap);
 }
 
 /* Flush diagnostic_buffer content on stderr.  */
+
 static void
 finish_diagnostic ()
 {
@@ -1452,6 +1564,7 @@ finish_diagnostic ()
 
 /* Helper subroutine of output_verbatim and verbatim. Do the approriate
    settings needed by BUFFER for a verbatim formatting.  */
+
 static void
 output_do_verbatim (buffer, msg, args_ptr)
      output_buffer *buffer;
@@ -1460,17 +1573,18 @@ output_do_verbatim (buffer, msg, args_ptr)
 {
   output_state os;
 
-  os = buffer->state;
+  os = output_buffer_state (buffer);
   output_prefix (buffer) = NULL;
   prefixing_policy (buffer) = DIAGNOSTICS_SHOW_PREFIX_NEVER;
   output_buffer_text_cursor (buffer) = msg;
   output_buffer_ptr_to_format_args (buffer) = args_ptr;
   output_set_maximum_length (buffer, 0);
   output_format (buffer);
-  buffer->state = os;
+  output_buffer_state (buffer) = os;
 }
 
 /* Output MESSAGE verbatim into BUFFER.  */
+
 void
 output_verbatim VPARAMS ((output_buffer *buffer, const char *msg, ...))
 {
@@ -1490,6 +1604,7 @@ output_verbatim VPARAMS ((output_buffer *buffer, const char *msg, ...))
 }
 
 /* Same as above but use diagnostic_buffer.  */
+
 void
 verbatim VPARAMS ((const char *msg, ...))
 {
@@ -1507,37 +1622,31 @@ verbatim VPARAMS ((const char *msg, ...))
   va_end (ap);
 }
 
-/* Report a diagnostic MESSAGE (an error or a WARNING) involving
-   entities in ARGUMENTS.  FILE and LINE indicate where the diagnostic
-   occurs.  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
+/* 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.  */
+
 void
-report_diagnostic (msg, args_ptr, file, line, warn)
-     const char *msg;
-     va_list *args_ptr;
-     const char *file;
-     int line;
-     int warn;
+report_diagnostic (dc)
+     diagnostic_context *dc;
 {
   output_state os;
 
   if (diagnostic_lock++)
     error_recursion ();
 
-  if (count_error (warn))
+  if (count_error (diagnostic_is_warning (dc)))
     {
-      os = diagnostic_buffer->state;
-      diagnostic_msg = msg;
-      diagnostic_args = args_ptr;
-      report_error_function (file);
-      output_set_prefix
-       (diagnostic_buffer, context_as_prefix (file, line, warn));
+      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);
       finish_diagnostic ();
-      output_destroy_prefix (diagnostic_buffer);
-      diagnostic_buffer->state = os;
+      output_buffer_state (diagnostic_buffer) = os;
     }
 
   diagnostic_lock--;
@@ -1546,24 +1655,21 @@ report_diagnostic (msg, args_ptr, file, line, warn)
 /* Inform the user that an error occurred while trying to report some
    other error.  This indicates catastrophic internal inconsistencies,
    so give up now.  But do try to flush out the previous error.  */
+
 static void
 error_recursion ()
 {
   if (diagnostic_lock < 3)
     finish_diagnostic ();
 
-  fprintf (stderr,
-"Internal compiler error: Error reporting routines re-entered.\n\
-Please submit a full bug report.\n\
-See %s for instructions.\n", GCCBUGURL);
-
-  exit (FATAL_EXIT_CODE);
+  fatal ("Internal compiler error: Error reporting routines re-entered.");
 }
 
 /* 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 ../../egcs/gcc/expr.c'.  */
+   instead of `Internal compiler error in ../../GCC/gcc/expr.c'.  */
+
 static const char *
 trim_filename (name)
      const char *name;
@@ -1571,7 +1677,29 @@ trim_filename (name)
   static const char this_file[] = __FILE__;
   const char *p = name, *q = this_file;
 
-  while (*p == *q && *p != 0 && *q != 0) p++, q++;
+  /* 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
@@ -1591,9 +1719,76 @@ fancy_abort (file, line, function)
      int line;
      const char *function;
 {
-  fatal (
-"Internal compiler error in %s, at %s:%d\n\
-Please submit a full bug report.\n\
-See %s for instructions.",
-        function, trim_filename (file), line, GCCBUGURL);
+  fatal ("Internal compiler error in %s, at %s:%d",
+        function, trim_filename (file), line);
+}
+
+/* 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.  */
+
+void
+set_diagnostic_context (dc, message, args_ptr, file, line, warn)
+     diagnostic_context *dc;
+     const char *message;
+     va_list *args_ptr;
+     const char *file;
+     int line;
+     int warn;
+{
+  memset (dc, 0, sizeof (diagnostic_context));
+  diagnostic_message (dc) = message;
+  diagnostic_argument_list (dc) = args_ptr;
+  diagnostic_file_location (dc) = file;
+  diagnostic_line_location (dc) = line;
+  diagnostic_is_warning (dc) = warn;
+  diagnostic_starter (dc) = lang_diagnostic_starter;
+  diagnostic_finalizer (dc) = lang_diagnostic_finalizer;
+}
+
+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;
+{
+  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)));
+}
+
+static void
+default_diagnostic_finalizer (buffer, dc)
+     output_buffer *buffer;
+     diagnostic_context *dc __attribute__((__unused__));
+{
+  output_destroy_prefix (buffer);
 }