xref: /dflybsd-src/contrib/gcc-8.0/gcc/diagnostic.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Language-independent diagnostic subroutines for the GNU Compiler Collection
238fd1498Szrj    Copyright (C) 1999-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj 
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3.  If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>.  */
2038fd1498Szrj 
2138fd1498Szrj 
2238fd1498Szrj /* This file implements the language independent aspect of diagnostic
2338fd1498Szrj    message module.  */
2438fd1498Szrj 
2538fd1498Szrj #include "config.h"
2638fd1498Szrj #include "system.h"
2738fd1498Szrj #include "coretypes.h"
2838fd1498Szrj #include "version.h"
2938fd1498Szrj #include "demangle.h"
3038fd1498Szrj #include "intl.h"
3138fd1498Szrj #include "backtrace.h"
3238fd1498Szrj #include "diagnostic.h"
3338fd1498Szrj #include "diagnostic-color.h"
3438fd1498Szrj #include "edit-context.h"
3538fd1498Szrj #include "selftest.h"
3638fd1498Szrj #include "selftest-diagnostic.h"
3738fd1498Szrj 
3838fd1498Szrj #ifdef HAVE_TERMIOS_H
3938fd1498Szrj # include <termios.h>
4038fd1498Szrj #endif
4138fd1498Szrj 
4238fd1498Szrj #ifdef GWINSZ_IN_SYS_IOCTL
4338fd1498Szrj # include <sys/ioctl.h>
4438fd1498Szrj #endif
4538fd1498Szrj 
4638fd1498Szrj #define pedantic_warning_kind(DC)			\
4738fd1498Szrj   ((DC)->pedantic_errors ? DK_ERROR : DK_WARNING)
4838fd1498Szrj #define permissive_error_kind(DC) ((DC)->permissive ? DK_WARNING : DK_ERROR)
4938fd1498Szrj #define permissive_error_option(DC) ((DC)->opt_permissive)
5038fd1498Szrj 
5138fd1498Szrj /* Prototypes.  */
5238fd1498Szrj static bool diagnostic_impl (rich_location *, int, const char *,
5338fd1498Szrj 			     va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(3,0);
5438fd1498Szrj static bool diagnostic_n_impl (rich_location *, int, unsigned HOST_WIDE_INT,
5538fd1498Szrj 			       const char *, const char *, va_list *,
5638fd1498Szrj 			       diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
5738fd1498Szrj 
5838fd1498Szrj static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
5938fd1498Szrj static void real_abort (void) ATTRIBUTE_NORETURN;
6038fd1498Szrj 
6138fd1498Szrj /* Name of program invoked, sans directories.  */
6238fd1498Szrj 
6338fd1498Szrj const char *progname;
6438fd1498Szrj 
6538fd1498Szrj /* A diagnostic_context surrogate for stderr.  */
6638fd1498Szrj static diagnostic_context global_diagnostic_context;
6738fd1498Szrj diagnostic_context *global_dc = &global_diagnostic_context;
6838fd1498Szrj 
6938fd1498Szrj /* Return a malloc'd string containing MSG formatted a la printf.  The
7038fd1498Szrj    caller is responsible for freeing the memory.  */
7138fd1498Szrj char *
build_message_string(const char * msg,...)7238fd1498Szrj build_message_string (const char *msg, ...)
7338fd1498Szrj {
7438fd1498Szrj   char *str;
7538fd1498Szrj   va_list ap;
7638fd1498Szrj 
7738fd1498Szrj   va_start (ap, msg);
7838fd1498Szrj   str = xvasprintf (msg, ap);
7938fd1498Szrj   va_end (ap);
8038fd1498Szrj 
8138fd1498Szrj   return str;
8238fd1498Szrj }
8338fd1498Szrj 
8438fd1498Szrj /* Same as diagnostic_build_prefix, but only the source FILE is given.  */
8538fd1498Szrj char *
file_name_as_prefix(diagnostic_context * context,const char * f)8638fd1498Szrj file_name_as_prefix (diagnostic_context *context, const char *f)
8738fd1498Szrj {
8838fd1498Szrj   const char *locus_cs
8938fd1498Szrj     = colorize_start (pp_show_color (context->printer), "locus");
9038fd1498Szrj   const char *locus_ce = colorize_stop (pp_show_color (context->printer));
9138fd1498Szrj   return build_message_string ("%s%s:%s ", locus_cs, f, locus_ce);
9238fd1498Szrj }
9338fd1498Szrj 
9438fd1498Szrj 
9538fd1498Szrj 
9638fd1498Szrj /* Return the value of the getenv("COLUMNS") as an integer. If the
9738fd1498Szrj    value is not set to a positive integer, use ioctl to get the
9838fd1498Szrj    terminal width. If it fails, return INT_MAX.  */
9938fd1498Szrj int
get_terminal_width(void)10038fd1498Szrj get_terminal_width (void)
10138fd1498Szrj {
10238fd1498Szrj   const char * s = getenv ("COLUMNS");
10338fd1498Szrj   if (s != NULL) {
10438fd1498Szrj     int n = atoi (s);
10538fd1498Szrj     if (n > 0)
10638fd1498Szrj       return n;
10738fd1498Szrj   }
10838fd1498Szrj 
10938fd1498Szrj #ifdef TIOCGWINSZ
11038fd1498Szrj   struct winsize w;
11138fd1498Szrj   w.ws_col = 0;
11238fd1498Szrj   if (ioctl (0, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
11338fd1498Szrj     return w.ws_col;
11438fd1498Szrj #endif
11538fd1498Szrj 
11638fd1498Szrj   return INT_MAX;
11738fd1498Szrj }
11838fd1498Szrj 
11938fd1498Szrj /* Set caret_max_width to value.  */
12038fd1498Szrj void
diagnostic_set_caret_max_width(diagnostic_context * context,int value)12138fd1498Szrj diagnostic_set_caret_max_width (diagnostic_context *context, int value)
12238fd1498Szrj {
12338fd1498Szrj   /* One minus to account for the leading empty space.  */
12438fd1498Szrj   value = value ? value - 1
12538fd1498Szrj     : (isatty (fileno (pp_buffer (context->printer)->stream))
12638fd1498Szrj        ? get_terminal_width () - 1: INT_MAX);
12738fd1498Szrj 
12838fd1498Szrj   if (value <= 0)
12938fd1498Szrj     value = INT_MAX;
13038fd1498Szrj 
13138fd1498Szrj   context->caret_max_width = value;
13238fd1498Szrj }
13338fd1498Szrj 
13438fd1498Szrj /* Initialize the diagnostic message outputting machinery.  */
13538fd1498Szrj void
diagnostic_initialize(diagnostic_context * context,int n_opts)13638fd1498Szrj diagnostic_initialize (diagnostic_context *context, int n_opts)
13738fd1498Szrj {
13838fd1498Szrj   int i;
13938fd1498Szrj 
14038fd1498Szrj   /* Allocate a basic pretty-printer.  Clients will replace this a
14138fd1498Szrj      much more elaborated pretty-printer if they wish.  */
14238fd1498Szrj   context->printer = XNEW (pretty_printer);
14338fd1498Szrj   new (context->printer) pretty_printer ();
14438fd1498Szrj 
14538fd1498Szrj   memset (context->diagnostic_count, 0, sizeof context->diagnostic_count);
14638fd1498Szrj   context->warning_as_error_requested = false;
14738fd1498Szrj   context->n_opts = n_opts;
14838fd1498Szrj   context->classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
14938fd1498Szrj   for (i = 0; i < n_opts; i++)
15038fd1498Szrj     context->classify_diagnostic[i] = DK_UNSPECIFIED;
15138fd1498Szrj   context->show_caret = false;
15238fd1498Szrj   diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
15338fd1498Szrj   for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
15438fd1498Szrj     context->caret_chars[i] = '^';
15538fd1498Szrj   context->show_option_requested = false;
15638fd1498Szrj   context->abort_on_error = false;
15738fd1498Szrj   context->show_column = false;
15838fd1498Szrj   context->pedantic_errors = false;
15938fd1498Szrj   context->permissive = false;
16038fd1498Szrj   context->opt_permissive = 0;
16138fd1498Szrj   context->fatal_errors = false;
16238fd1498Szrj   context->dc_inhibit_warnings = false;
16338fd1498Szrj   context->dc_warn_system_headers = false;
16438fd1498Szrj   context->max_errors = 0;
16538fd1498Szrj   context->internal_error = NULL;
16638fd1498Szrj   diagnostic_starter (context) = default_diagnostic_starter;
16738fd1498Szrj   context->start_span = default_diagnostic_start_span_fn;
16838fd1498Szrj   diagnostic_finalizer (context) = default_diagnostic_finalizer;
16938fd1498Szrj   context->option_enabled = NULL;
17038fd1498Szrj   context->option_state = NULL;
17138fd1498Szrj   context->option_name = NULL;
17238fd1498Szrj   context->last_location = UNKNOWN_LOCATION;
17338fd1498Szrj   context->last_module = 0;
17438fd1498Szrj   context->x_data = NULL;
17538fd1498Szrj   context->lock = 0;
17638fd1498Szrj   context->inhibit_notes_p = false;
17738fd1498Szrj   context->colorize_source_p = false;
17838fd1498Szrj   context->show_ruler_p = false;
17938fd1498Szrj   context->parseable_fixits_p = false;
18038fd1498Szrj   context->edit_context_ptr = NULL;
18138fd1498Szrj }
18238fd1498Szrj 
18338fd1498Szrj /* Maybe initialize the color support. We require clients to do this
18438fd1498Szrj    explicitly, since most clients don't want color.  When called
18538fd1498Szrj    without a VALUE, it initializes with DIAGNOSTICS_COLOR_DEFAULT.  */
18638fd1498Szrj 
18738fd1498Szrj void
diagnostic_color_init(diagnostic_context * context,int value)18838fd1498Szrj diagnostic_color_init (diagnostic_context *context, int value /*= -1 */)
18938fd1498Szrj {
19038fd1498Szrj   /* value == -1 is the default value.  */
19138fd1498Szrj   if (value < 0)
19238fd1498Szrj     {
19338fd1498Szrj       /* If DIAGNOSTICS_COLOR_DEFAULT is -1, default to
19438fd1498Szrj 	 -fdiagnostics-color=auto if GCC_COLORS is in the environment,
19538fd1498Szrj 	 otherwise default to -fdiagnostics-color=never, for other
19638fd1498Szrj 	 values default to that
19738fd1498Szrj 	 -fdiagnostics-color={never,auto,always}.  */
19838fd1498Szrj       if (DIAGNOSTICS_COLOR_DEFAULT == -1)
19938fd1498Szrj 	{
20038fd1498Szrj 	  if (!getenv ("GCC_COLORS"))
20138fd1498Szrj 	    return;
20238fd1498Szrj 	  value = DIAGNOSTICS_COLOR_AUTO;
20338fd1498Szrj 	}
20438fd1498Szrj       else
20538fd1498Szrj 	value = DIAGNOSTICS_COLOR_DEFAULT;
20638fd1498Szrj     }
20738fd1498Szrj   pp_show_color (context->printer)
20838fd1498Szrj     = colorize_init ((diagnostic_color_rule_t) value);
20938fd1498Szrj }
21038fd1498Szrj 
21138fd1498Szrj /* Do any cleaning up required after the last diagnostic is emitted.  */
21238fd1498Szrj 
21338fd1498Szrj void
diagnostic_finish(diagnostic_context * context)21438fd1498Szrj diagnostic_finish (diagnostic_context *context)
21538fd1498Szrj {
21638fd1498Szrj   /* Some of the errors may actually have been warnings.  */
21738fd1498Szrj   if (diagnostic_kind_count (context, DK_WERROR))
21838fd1498Szrj     {
21938fd1498Szrj       /* -Werror was given.  */
22038fd1498Szrj       if (context->warning_as_error_requested)
22138fd1498Szrj 	pp_verbatim (context->printer,
22238fd1498Szrj 		     _("%s: all warnings being treated as errors"),
22338fd1498Szrj 		     progname);
22438fd1498Szrj       /* At least one -Werror= was given.  */
22538fd1498Szrj       else
22638fd1498Szrj 	pp_verbatim (context->printer,
22738fd1498Szrj 		     _("%s: some warnings being treated as errors"),
22838fd1498Szrj 		     progname);
22938fd1498Szrj       pp_newline_and_flush (context->printer);
23038fd1498Szrj     }
23138fd1498Szrj 
23238fd1498Szrj   diagnostic_file_cache_fini ();
23338fd1498Szrj 
23438fd1498Szrj   XDELETEVEC (context->classify_diagnostic);
23538fd1498Szrj   context->classify_diagnostic = NULL;
23638fd1498Szrj 
23738fd1498Szrj   /* diagnostic_initialize allocates context->printer using XNEW
23838fd1498Szrj      and placement-new.  */
23938fd1498Szrj   context->printer->~pretty_printer ();
24038fd1498Szrj   XDELETE (context->printer);
24138fd1498Szrj   context->printer = NULL;
24238fd1498Szrj 
24338fd1498Szrj   if (context->edit_context_ptr)
24438fd1498Szrj     {
24538fd1498Szrj       delete context->edit_context_ptr;
24638fd1498Szrj       context->edit_context_ptr = NULL;
24738fd1498Szrj     }
24838fd1498Szrj }
24938fd1498Szrj 
25038fd1498Szrj /* Initialize DIAGNOSTIC, where the message MSG has already been
25138fd1498Szrj    translated.  */
25238fd1498Szrj void
diagnostic_set_info_translated(diagnostic_info * diagnostic,const char * msg,va_list * args,rich_location * richloc,diagnostic_t kind)25338fd1498Szrj diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
25438fd1498Szrj 				va_list *args, rich_location *richloc,
25538fd1498Szrj 				diagnostic_t kind)
25638fd1498Szrj {
25738fd1498Szrj   gcc_assert (richloc);
25838fd1498Szrj   diagnostic->message.err_no = errno;
25938fd1498Szrj   diagnostic->message.args_ptr = args;
26038fd1498Szrj   diagnostic->message.format_spec = msg;
26138fd1498Szrj   diagnostic->message.m_richloc = richloc;
26238fd1498Szrj   diagnostic->richloc = richloc;
26338fd1498Szrj   diagnostic->kind = kind;
26438fd1498Szrj   diagnostic->option_index = 0;
26538fd1498Szrj }
26638fd1498Szrj 
26738fd1498Szrj /* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
26838fd1498Szrj    translated.  */
26938fd1498Szrj void
diagnostic_set_info(diagnostic_info * diagnostic,const char * gmsgid,va_list * args,rich_location * richloc,diagnostic_t kind)27038fd1498Szrj diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
27138fd1498Szrj 		     va_list *args, rich_location *richloc,
27238fd1498Szrj 		     diagnostic_t kind)
27338fd1498Szrj {
27438fd1498Szrj   gcc_assert (richloc);
27538fd1498Szrj   diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
27638fd1498Szrj }
27738fd1498Szrj 
27838fd1498Szrj static const char *const diagnostic_kind_color[] = {
27938fd1498Szrj #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
28038fd1498Szrj #include "diagnostic.def"
28138fd1498Szrj #undef DEFINE_DIAGNOSTIC_KIND
28238fd1498Szrj   NULL
28338fd1498Szrj };
28438fd1498Szrj 
28538fd1498Szrj /* Get a color name for diagnostics of type KIND
28638fd1498Szrj    Result could be NULL.  */
28738fd1498Szrj 
28838fd1498Szrj const char *
diagnostic_get_color_for_kind(diagnostic_t kind)28938fd1498Szrj diagnostic_get_color_for_kind (diagnostic_t kind)
29038fd1498Szrj {
29138fd1498Szrj   return diagnostic_kind_color[kind];
29238fd1498Szrj }
29338fd1498Szrj 
29438fd1498Szrj /* Return a formatted line and column ':%line:%column'.  Elided if
29538fd1498Szrj    zero.  The result is a statically allocated buffer.  */
29638fd1498Szrj 
29738fd1498Szrj static const char *
maybe_line_and_column(int line,int col)29838fd1498Szrj maybe_line_and_column (int line, int col)
29938fd1498Szrj {
30038fd1498Szrj   static char result[32];
30138fd1498Szrj 
30238fd1498Szrj   if (line)
30338fd1498Szrj     {
30438fd1498Szrj       size_t l = snprintf (result, sizeof (result),
30538fd1498Szrj 			   col ? ":%d:%d" : ":%d", line, col);
30638fd1498Szrj       gcc_checking_assert (l < sizeof (result));
30738fd1498Szrj     }
30838fd1498Szrj   else
30938fd1498Szrj     result[0] = 0;
31038fd1498Szrj   return result;
31138fd1498Szrj }
31238fd1498Szrj 
31338fd1498Szrj /* Return a malloc'd string describing a location e.g. "foo.c:42:10".
31438fd1498Szrj    The caller is responsible for freeing the memory.  */
31538fd1498Szrj 
31638fd1498Szrj static char *
diagnostic_get_location_text(diagnostic_context * context,expanded_location s)31738fd1498Szrj diagnostic_get_location_text (diagnostic_context *context,
31838fd1498Szrj 			      expanded_location s)
31938fd1498Szrj {
32038fd1498Szrj   pretty_printer *pp = context->printer;
32138fd1498Szrj   const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
32238fd1498Szrj   const char *locus_ce = colorize_stop (pp_show_color (pp));
32338fd1498Szrj   const char *file = s.file ? s.file : progname;
32438fd1498Szrj   int line = strcmp (file, N_("<built-in>")) ? s.line : 0;
32538fd1498Szrj   int col = context->show_column ? s.column : 0;
32638fd1498Szrj 
32738fd1498Szrj   const char *line_col = maybe_line_and_column (line, col);
32838fd1498Szrj   return build_message_string ("%s%s%s:%s", locus_cs, file,
32938fd1498Szrj 			       line_col, locus_ce);
33038fd1498Szrj }
33138fd1498Szrj 
33238fd1498Szrj /* Return a malloc'd string describing a location and the severity of the
33338fd1498Szrj    diagnostic, e.g. "foo.c:42:10: error: ".  The caller is responsible for
33438fd1498Szrj    freeing the memory.  */
33538fd1498Szrj char *
diagnostic_build_prefix(diagnostic_context * context,const diagnostic_info * diagnostic)33638fd1498Szrj diagnostic_build_prefix (diagnostic_context *context,
33738fd1498Szrj 			 const diagnostic_info *diagnostic)
33838fd1498Szrj {
33938fd1498Szrj   static const char *const diagnostic_kind_text[] = {
34038fd1498Szrj #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
34138fd1498Szrj #include "diagnostic.def"
34238fd1498Szrj #undef DEFINE_DIAGNOSTIC_KIND
34338fd1498Szrj     "must-not-happen"
34438fd1498Szrj   };
34538fd1498Szrj   gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
34638fd1498Szrj 
34738fd1498Szrj   const char *text = _(diagnostic_kind_text[diagnostic->kind]);
34838fd1498Szrj   const char *text_cs = "", *text_ce = "";
34938fd1498Szrj   pretty_printer *pp = context->printer;
35038fd1498Szrj 
35138fd1498Szrj   if (diagnostic_kind_color[diagnostic->kind])
35238fd1498Szrj     {
35338fd1498Szrj       text_cs = colorize_start (pp_show_color (pp),
35438fd1498Szrj 				diagnostic_kind_color[diagnostic->kind]);
35538fd1498Szrj       text_ce = colorize_stop (pp_show_color (pp));
35638fd1498Szrj     }
35738fd1498Szrj 
35838fd1498Szrj   expanded_location s = diagnostic_expand_location (diagnostic);
35938fd1498Szrj   char *location_text = diagnostic_get_location_text (context, s);
36038fd1498Szrj 
36138fd1498Szrj   char *result = build_message_string ("%s %s%s%s", location_text,
36238fd1498Szrj 				       text_cs, text, text_ce);
36338fd1498Szrj   free (location_text);
36438fd1498Szrj   return result;
36538fd1498Szrj }
36638fd1498Szrj 
36738fd1498Szrj /* Functions at which to stop the backtrace print.  It's not
36838fd1498Szrj    particularly helpful to print the callers of these functions.  */
36938fd1498Szrj 
37038fd1498Szrj static const char * const bt_stop[] =
37138fd1498Szrj {
37238fd1498Szrj   "main",
37338fd1498Szrj   "toplev::main",
37438fd1498Szrj   "execute_one_pass",
37538fd1498Szrj   "compile_file",
37638fd1498Szrj };
37738fd1498Szrj 
37838fd1498Szrj /* A callback function passed to the backtrace_full function.  */
37938fd1498Szrj 
38038fd1498Szrj static int
bt_callback(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)38138fd1498Szrj bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
38238fd1498Szrj 	     const char *function)
38338fd1498Szrj {
38438fd1498Szrj   int *pcount = (int *) data;
38538fd1498Szrj 
38638fd1498Szrj   /* If we don't have any useful information, don't print
38738fd1498Szrj      anything.  */
38838fd1498Szrj   if (filename == NULL && function == NULL)
38938fd1498Szrj     return 0;
39038fd1498Szrj 
39138fd1498Szrj   /* Skip functions in diagnostic.c.  */
39238fd1498Szrj   if (*pcount == 0
39338fd1498Szrj       && filename != NULL
39438fd1498Szrj       && strcmp (lbasename (filename), "diagnostic.c") == 0)
39538fd1498Szrj     return 0;
39638fd1498Szrj 
39738fd1498Szrj   /* Print up to 20 functions.  We could make this a --param, but
39838fd1498Szrj      since this is only for debugging just use a constant for now.  */
39938fd1498Szrj   if (*pcount >= 20)
40038fd1498Szrj     {
40138fd1498Szrj       /* Returning a non-zero value stops the backtrace.  */
40238fd1498Szrj       return 1;
40338fd1498Szrj     }
40438fd1498Szrj   ++*pcount;
40538fd1498Szrj 
40638fd1498Szrj   char *alc = NULL;
40738fd1498Szrj   if (function != NULL)
40838fd1498Szrj     {
40938fd1498Szrj       char *str = cplus_demangle_v3 (function,
41038fd1498Szrj 				     (DMGL_VERBOSE | DMGL_ANSI
41138fd1498Szrj 				      | DMGL_GNU_V3 | DMGL_PARAMS));
41238fd1498Szrj       if (str != NULL)
41338fd1498Szrj 	{
41438fd1498Szrj 	  alc = str;
41538fd1498Szrj 	  function = str;
41638fd1498Szrj 	}
41738fd1498Szrj 
41838fd1498Szrj       for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
41938fd1498Szrj 	{
42038fd1498Szrj 	  size_t len = strlen (bt_stop[i]);
42138fd1498Szrj 	  if (strncmp (function, bt_stop[i], len) == 0
42238fd1498Szrj 	      && (function[len] == '\0' || function[len] == '('))
42338fd1498Szrj 	    {
42438fd1498Szrj 	      if (alc != NULL)
42538fd1498Szrj 		free (alc);
42638fd1498Szrj 	      /* Returning a non-zero value stops the backtrace.  */
42738fd1498Szrj 	      return 1;
42838fd1498Szrj 	    }
42938fd1498Szrj 	}
43038fd1498Szrj     }
43138fd1498Szrj 
43238fd1498Szrj   fprintf (stderr, "0x%lx %s\n\t%s:%d\n",
43338fd1498Szrj 	   (unsigned long) pc,
43438fd1498Szrj 	   function == NULL ? "???" : function,
43538fd1498Szrj 	   filename == NULL ? "???" : filename,
43638fd1498Szrj 	   lineno);
43738fd1498Szrj 
43838fd1498Szrj   if (alc != NULL)
43938fd1498Szrj     free (alc);
44038fd1498Szrj 
44138fd1498Szrj   return 0;
44238fd1498Szrj }
44338fd1498Szrj 
44438fd1498Szrj /* A callback function passed to the backtrace_full function.  This is
44538fd1498Szrj    called if backtrace_full has an error.  */
44638fd1498Szrj 
44738fd1498Szrj static void
bt_err_callback(void * data ATTRIBUTE_UNUSED,const char * msg,int errnum)44838fd1498Szrj bt_err_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
44938fd1498Szrj {
45038fd1498Szrj   if (errnum < 0)
45138fd1498Szrj     {
45238fd1498Szrj       /* This means that no debug info was available.  Just quietly
45338fd1498Szrj 	 skip printing backtrace info.  */
45438fd1498Szrj       return;
45538fd1498Szrj     }
45638fd1498Szrj   fprintf (stderr, "%s%s%s\n", msg, errnum == 0 ? "" : ": ",
45738fd1498Szrj 	   errnum == 0 ? "" : xstrerror (errnum));
45838fd1498Szrj }
45938fd1498Szrj 
46038fd1498Szrj /* Check if we've met the maximum error limit, and if so fatally exit
46138fd1498Szrj    with a message.  CONTEXT is the context to check, and FLUSH
46238fd1498Szrj    indicates whether a diagnostic_finish call is needed.  */
46338fd1498Szrj 
46438fd1498Szrj void
diagnostic_check_max_errors(diagnostic_context * context,bool flush)46538fd1498Szrj diagnostic_check_max_errors (diagnostic_context *context, bool flush)
46638fd1498Szrj {
46738fd1498Szrj   if (!context->max_errors)
46838fd1498Szrj     return;
46938fd1498Szrj 
47038fd1498Szrj   int count = (diagnostic_kind_count (context, DK_ERROR)
47138fd1498Szrj 	       + diagnostic_kind_count (context, DK_SORRY)
47238fd1498Szrj 	       + diagnostic_kind_count (context, DK_WERROR));
47338fd1498Szrj 
47438fd1498Szrj   if (count >= context->max_errors)
47538fd1498Szrj     {
47638fd1498Szrj       fnotice (stderr,
47738fd1498Szrj 	       "compilation terminated due to -fmax-errors=%u.\n",
47838fd1498Szrj 	       context->max_errors);
47938fd1498Szrj       if (flush)
48038fd1498Szrj 	diagnostic_finish (context);
48138fd1498Szrj       exit (FATAL_EXIT_CODE);
48238fd1498Szrj     }
48338fd1498Szrj }
48438fd1498Szrj 
48538fd1498Szrj /* Take any action which is expected to happen after the diagnostic
48638fd1498Szrj    is written out.  This function does not always return.  */
48738fd1498Szrj void
diagnostic_action_after_output(diagnostic_context * context,diagnostic_t diag_kind)48838fd1498Szrj diagnostic_action_after_output (diagnostic_context *context,
48938fd1498Szrj 				diagnostic_t diag_kind)
49038fd1498Szrj {
49138fd1498Szrj   switch (diag_kind)
49238fd1498Szrj     {
49338fd1498Szrj     case DK_DEBUG:
49438fd1498Szrj     case DK_NOTE:
49538fd1498Szrj     case DK_ANACHRONISM:
49638fd1498Szrj     case DK_WARNING:
49738fd1498Szrj       break;
49838fd1498Szrj 
49938fd1498Szrj     case DK_ERROR:
50038fd1498Szrj     case DK_SORRY:
50138fd1498Szrj       if (context->abort_on_error)
50238fd1498Szrj 	real_abort ();
50338fd1498Szrj       if (context->fatal_errors)
50438fd1498Szrj 	{
50538fd1498Szrj 	  fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n");
50638fd1498Szrj 	  diagnostic_finish (context);
50738fd1498Szrj 	  exit (FATAL_EXIT_CODE);
50838fd1498Szrj 	}
50938fd1498Szrj       break;
51038fd1498Szrj 
51138fd1498Szrj     case DK_ICE:
51238fd1498Szrj     case DK_ICE_NOBT:
51338fd1498Szrj       {
51438fd1498Szrj 	struct backtrace_state *state = NULL;
51538fd1498Szrj 	if (diag_kind == DK_ICE)
51638fd1498Szrj 	  state = backtrace_create_state (NULL, 0, bt_err_callback, NULL);
51738fd1498Szrj 	int count = 0;
51838fd1498Szrj 	if (state != NULL)
51938fd1498Szrj 	  backtrace_full (state, 2, bt_callback, bt_err_callback,
52038fd1498Szrj 			  (void *) &count);
52138fd1498Szrj 
52238fd1498Szrj 	if (context->abort_on_error)
52338fd1498Szrj 	  real_abort ();
52438fd1498Szrj 
52538fd1498Szrj 	fnotice (stderr, "Please submit a full bug report,\n"
52638fd1498Szrj 		 "with preprocessed source if appropriate.\n");
52738fd1498Szrj 	if (count > 0)
52838fd1498Szrj 	  fnotice (stderr,
52938fd1498Szrj 		   ("Please include the complete backtrace "
53038fd1498Szrj 		    "with any bug report.\n"));
53138fd1498Szrj 	fnotice (stderr, "See %s for instructions.\n", bug_report_url);
53238fd1498Szrj 
53338fd1498Szrj 	exit (ICE_EXIT_CODE);
53438fd1498Szrj       }
53538fd1498Szrj 
53638fd1498Szrj     case DK_FATAL:
53738fd1498Szrj       if (context->abort_on_error)
53838fd1498Szrj 	real_abort ();
53938fd1498Szrj       diagnostic_finish (context);
54038fd1498Szrj       fnotice (stderr, "compilation terminated.\n");
54138fd1498Szrj       exit (FATAL_EXIT_CODE);
54238fd1498Szrj 
54338fd1498Szrj     default:
54438fd1498Szrj       gcc_unreachable ();
54538fd1498Szrj     }
54638fd1498Szrj }
54738fd1498Szrj 
54838fd1498Szrj /* True if the last module or file in which a diagnostic was reported is
54938fd1498Szrj    different from the current one.  */
55038fd1498Szrj 
55138fd1498Szrj static bool
last_module_changed_p(diagnostic_context * context,const line_map_ordinary * map)55238fd1498Szrj last_module_changed_p (diagnostic_context *context,
55338fd1498Szrj 		       const line_map_ordinary *map)
55438fd1498Szrj {
55538fd1498Szrj   return context->last_module != map;
55638fd1498Szrj }
55738fd1498Szrj 
55838fd1498Szrj /* Remember the current module or file as being the last one in which we
55938fd1498Szrj    report a diagnostic.  */
56038fd1498Szrj 
56138fd1498Szrj static void
set_last_module(diagnostic_context * context,const line_map_ordinary * map)56238fd1498Szrj set_last_module (diagnostic_context *context, const line_map_ordinary *map)
56338fd1498Szrj {
56438fd1498Szrj   context->last_module = map;
56538fd1498Szrj }
56638fd1498Szrj 
56738fd1498Szrj void
diagnostic_report_current_module(diagnostic_context * context,location_t where)56838fd1498Szrj diagnostic_report_current_module (diagnostic_context *context, location_t where)
56938fd1498Szrj {
57038fd1498Szrj   const line_map_ordinary *map = NULL;
57138fd1498Szrj 
57238fd1498Szrj   if (pp_needs_newline (context->printer))
57338fd1498Szrj     {
57438fd1498Szrj       pp_newline (context->printer);
57538fd1498Szrj       pp_needs_newline (context->printer) = false;
57638fd1498Szrj     }
57738fd1498Szrj 
57838fd1498Szrj   if (where <= BUILTINS_LOCATION)
57938fd1498Szrj     return;
58038fd1498Szrj 
58138fd1498Szrj   linemap_resolve_location (line_table, where,
58238fd1498Szrj 			    LRK_MACRO_DEFINITION_LOCATION,
58338fd1498Szrj 			    &map);
58438fd1498Szrj 
58538fd1498Szrj   if (map && last_module_changed_p (context, map))
58638fd1498Szrj     {
58738fd1498Szrj       set_last_module (context, map);
58838fd1498Szrj       if (! MAIN_FILE_P (map))
58938fd1498Szrj 	{
59038fd1498Szrj 	  map = INCLUDED_FROM (line_table, map);
59138fd1498Szrj 	  const char *line_col
59238fd1498Szrj 	    = maybe_line_and_column (LAST_SOURCE_LINE (map),
59338fd1498Szrj 				     context->show_column
59438fd1498Szrj 				     ? LAST_SOURCE_COLUMN (map) : 0);
59538fd1498Szrj 	  pp_verbatim (context->printer,
59638fd1498Szrj 		       "In file included from %r%s%s%R", "locus",
59738fd1498Szrj 		       LINEMAP_FILE (map), line_col);
59838fd1498Szrj 	  while (! MAIN_FILE_P (map))
59938fd1498Szrj 	    {
60038fd1498Szrj 	      map = INCLUDED_FROM (line_table, map);
60138fd1498Szrj 	      line_col = maybe_line_and_column (LAST_SOURCE_LINE (map), 0);
60238fd1498Szrj 	      pp_verbatim (context->printer,
60338fd1498Szrj 			   ",\n                 from %r%s%s%R", "locus",
60438fd1498Szrj 			   LINEMAP_FILE (map), line_col);
60538fd1498Szrj 	    }
60638fd1498Szrj 	  pp_verbatim (context->printer, ":");
60738fd1498Szrj 	  pp_newline (context->printer);
60838fd1498Szrj 	}
60938fd1498Szrj     }
61038fd1498Szrj }
61138fd1498Szrj 
61238fd1498Szrj void
default_diagnostic_starter(diagnostic_context * context,diagnostic_info * diagnostic)61338fd1498Szrj default_diagnostic_starter (diagnostic_context *context,
61438fd1498Szrj 			    diagnostic_info *diagnostic)
61538fd1498Szrj {
61638fd1498Szrj   diagnostic_report_current_module (context, diagnostic_location (diagnostic));
61738fd1498Szrj   pp_set_prefix (context->printer, diagnostic_build_prefix (context,
61838fd1498Szrj 							    diagnostic));
61938fd1498Szrj }
62038fd1498Szrj 
62138fd1498Szrj void
default_diagnostic_start_span_fn(diagnostic_context * context,expanded_location exploc)62238fd1498Szrj default_diagnostic_start_span_fn (diagnostic_context *context,
62338fd1498Szrj 				  expanded_location exploc)
62438fd1498Szrj {
62538fd1498Szrj   pp_set_prefix (context->printer,
62638fd1498Szrj 		 diagnostic_get_location_text (context, exploc));
62738fd1498Szrj   pp_string (context->printer, "");
62838fd1498Szrj   pp_newline (context->printer);
62938fd1498Szrj }
63038fd1498Szrj 
63138fd1498Szrj void
default_diagnostic_finalizer(diagnostic_context * context,diagnostic_info * diagnostic)63238fd1498Szrj default_diagnostic_finalizer (diagnostic_context *context,
63338fd1498Szrj 			      diagnostic_info *diagnostic)
63438fd1498Szrj {
63538fd1498Szrj   diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind);
63638fd1498Szrj   pp_destroy_prefix (context->printer);
63738fd1498Szrj   pp_flush (context->printer);
63838fd1498Szrj }
63938fd1498Szrj 
64038fd1498Szrj /* Interface to specify diagnostic kind overrides.  Returns the
64138fd1498Szrj    previous setting, or DK_UNSPECIFIED if the parameters are out of
64238fd1498Szrj    range.  If OPTION_INDEX is zero, the new setting is for all the
64338fd1498Szrj    diagnostics.  */
64438fd1498Szrj diagnostic_t
diagnostic_classify_diagnostic(diagnostic_context * context,int option_index,diagnostic_t new_kind,location_t where)64538fd1498Szrj diagnostic_classify_diagnostic (diagnostic_context *context,
64638fd1498Szrj 				int option_index,
64738fd1498Szrj 				diagnostic_t new_kind,
64838fd1498Szrj 				location_t where)
64938fd1498Szrj {
65038fd1498Szrj   diagnostic_t old_kind;
65138fd1498Szrj 
65238fd1498Szrj   if (option_index < 0
65338fd1498Szrj       || option_index >= context->n_opts
65438fd1498Szrj       || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
65538fd1498Szrj     return DK_UNSPECIFIED;
65638fd1498Szrj 
65738fd1498Szrj   old_kind = context->classify_diagnostic[option_index];
65838fd1498Szrj 
65938fd1498Szrj   /* Handle pragmas separately, since we need to keep track of *where*
66038fd1498Szrj      the pragmas were.  */
66138fd1498Szrj   if (where != UNKNOWN_LOCATION)
66238fd1498Szrj     {
66338fd1498Szrj       int i;
66438fd1498Szrj 
66538fd1498Szrj       /* Record the command-line status, so we can reset it back on DK_POP. */
66638fd1498Szrj       if (old_kind == DK_UNSPECIFIED)
66738fd1498Szrj 	{
66838fd1498Szrj 	  old_kind = !context->option_enabled (option_index,
66938fd1498Szrj 					       context->option_state)
67038fd1498Szrj 	    ? DK_IGNORED : (context->warning_as_error_requested
67138fd1498Szrj 			    ? DK_ERROR : DK_WARNING);
67238fd1498Szrj 	  context->classify_diagnostic[option_index] = old_kind;
67338fd1498Szrj 	}
67438fd1498Szrj 
67538fd1498Szrj       for (i = context->n_classification_history - 1; i >= 0; i --)
67638fd1498Szrj 	if (context->classification_history[i].option == option_index)
67738fd1498Szrj 	  {
67838fd1498Szrj 	    old_kind = context->classification_history[i].kind;
67938fd1498Szrj 	    break;
68038fd1498Szrj 	  }
68138fd1498Szrj 
68238fd1498Szrj       i = context->n_classification_history;
68338fd1498Szrj       context->classification_history =
68438fd1498Szrj 	(diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1)
68538fd1498Szrj 							 * sizeof (diagnostic_classification_change_t));
68638fd1498Szrj       context->classification_history[i].location = where;
68738fd1498Szrj       context->classification_history[i].option = option_index;
68838fd1498Szrj       context->classification_history[i].kind = new_kind;
68938fd1498Szrj       context->n_classification_history ++;
69038fd1498Szrj     }
69138fd1498Szrj   else
69238fd1498Szrj     context->classify_diagnostic[option_index] = new_kind;
69338fd1498Szrj 
69438fd1498Szrj   return old_kind;
69538fd1498Szrj }
69638fd1498Szrj 
69738fd1498Szrj /* Save all diagnostic classifications in a stack.  */
69838fd1498Szrj void
diagnostic_push_diagnostics(diagnostic_context * context,location_t where ATTRIBUTE_UNUSED)69938fd1498Szrj diagnostic_push_diagnostics (diagnostic_context *context, location_t where ATTRIBUTE_UNUSED)
70038fd1498Szrj {
70138fd1498Szrj   context->push_list = (int *) xrealloc (context->push_list, (context->n_push + 1) * sizeof (int));
70238fd1498Szrj   context->push_list[context->n_push ++] = context->n_classification_history;
70338fd1498Szrj }
70438fd1498Szrj 
70538fd1498Szrj /* Restore the topmost classification set off the stack.  If the stack
70638fd1498Szrj    is empty, revert to the state based on command line parameters.  */
70738fd1498Szrj void
diagnostic_pop_diagnostics(diagnostic_context * context,location_t where)70838fd1498Szrj diagnostic_pop_diagnostics (diagnostic_context *context, location_t where)
70938fd1498Szrj {
71038fd1498Szrj   int jump_to;
71138fd1498Szrj   int i;
71238fd1498Szrj 
71338fd1498Szrj   if (context->n_push)
71438fd1498Szrj     jump_to = context->push_list [-- context->n_push];
71538fd1498Szrj   else
71638fd1498Szrj     jump_to = 0;
71738fd1498Szrj 
71838fd1498Szrj   i = context->n_classification_history;
71938fd1498Szrj   context->classification_history =
72038fd1498Szrj     (diagnostic_classification_change_t *) xrealloc (context->classification_history, (i + 1)
72138fd1498Szrj 						     * sizeof (diagnostic_classification_change_t));
72238fd1498Szrj   context->classification_history[i].location = where;
72338fd1498Szrj   context->classification_history[i].option = jump_to;
72438fd1498Szrj   context->classification_history[i].kind = DK_POP;
72538fd1498Szrj   context->n_classification_history ++;
72638fd1498Szrj }
72738fd1498Szrj 
72838fd1498Szrj /* Helper function for print_parseable_fixits.  Print TEXT to PP, obeying the
72938fd1498Szrj    escaping rules for -fdiagnostics-parseable-fixits.  */
73038fd1498Szrj 
73138fd1498Szrj static void
print_escaped_string(pretty_printer * pp,const char * text)73238fd1498Szrj print_escaped_string (pretty_printer *pp, const char *text)
73338fd1498Szrj {
73438fd1498Szrj   gcc_assert (pp);
73538fd1498Szrj   gcc_assert (text);
73638fd1498Szrj 
73738fd1498Szrj   pp_character (pp, '"');
73838fd1498Szrj   for (const char *ch = text; *ch; ch++)
73938fd1498Szrj     {
74038fd1498Szrj       switch (*ch)
74138fd1498Szrj 	{
74238fd1498Szrj 	case '\\':
74338fd1498Szrj 	  /* Escape backslash as two backslashes.  */
74438fd1498Szrj 	  pp_string (pp, "\\\\");
74538fd1498Szrj 	  break;
74638fd1498Szrj 	case '\t':
74738fd1498Szrj 	  /* Escape tab as "\t".  */
74838fd1498Szrj 	  pp_string (pp, "\\t");
74938fd1498Szrj 	  break;
75038fd1498Szrj 	case '\n':
75138fd1498Szrj 	  /* Escape newline as "\n".  */
75238fd1498Szrj 	  pp_string (pp, "\\n");
75338fd1498Szrj 	  break;
75438fd1498Szrj 	case '"':
75538fd1498Szrj 	  /* Escape doublequotes as \".  */
75638fd1498Szrj 	  pp_string (pp, "\\\"");
75738fd1498Szrj 	  break;
75838fd1498Szrj 	default:
75938fd1498Szrj 	  if (ISPRINT (*ch))
76038fd1498Szrj 	    pp_character (pp, *ch);
76138fd1498Szrj 	  else
76238fd1498Szrj 	    /* Use octal for non-printable chars.  */
76338fd1498Szrj 	    {
76438fd1498Szrj 	      unsigned char c = (*ch & 0xff);
76538fd1498Szrj 	      pp_printf (pp, "\\%o%o%o", (c / 64), (c / 8) & 007, c & 007);
76638fd1498Szrj 	    }
76738fd1498Szrj 	  break;
76838fd1498Szrj 	}
76938fd1498Szrj     }
77038fd1498Szrj   pp_character (pp, '"');
77138fd1498Szrj }
77238fd1498Szrj 
77338fd1498Szrj /* Implementation of -fdiagnostics-parseable-fixits.  Print a
77438fd1498Szrj    machine-parseable version of all fixits in RICHLOC to PP.  */
77538fd1498Szrj 
77638fd1498Szrj static void
print_parseable_fixits(pretty_printer * pp,rich_location * richloc)77738fd1498Szrj print_parseable_fixits (pretty_printer *pp, rich_location *richloc)
77838fd1498Szrj {
77938fd1498Szrj   gcc_assert (pp);
78038fd1498Szrj   gcc_assert (richloc);
78138fd1498Szrj 
78238fd1498Szrj   for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++)
78338fd1498Szrj     {
78438fd1498Szrj       const fixit_hint *hint = richloc->get_fixit_hint (i);
78538fd1498Szrj       source_location start_loc = hint->get_start_loc ();
78638fd1498Szrj       expanded_location start_exploc = expand_location (start_loc);
78738fd1498Szrj       pp_string (pp, "fix-it:");
78838fd1498Szrj       print_escaped_string (pp, start_exploc.file);
78938fd1498Szrj       /* For compatibility with clang, print as a half-open range.  */
79038fd1498Szrj       source_location next_loc = hint->get_next_loc ();
79138fd1498Szrj       expanded_location next_exploc = expand_location (next_loc);
79238fd1498Szrj       pp_printf (pp, ":{%i:%i-%i:%i}:",
79338fd1498Szrj 		 start_exploc.line, start_exploc.column,
79438fd1498Szrj 		 next_exploc.line, next_exploc.column);
79538fd1498Szrj       print_escaped_string (pp, hint->get_string ());
79638fd1498Szrj       pp_newline (pp);
79738fd1498Szrj     }
79838fd1498Szrj }
79938fd1498Szrj 
80038fd1498Szrj /* Update the diag_class of DIAGNOSTIC based on its location
80138fd1498Szrj    relative to any
80238fd1498Szrj      #pragma GCC diagnostic
80338fd1498Szrj    directives recorded within CONTEXT.
80438fd1498Szrj 
80538fd1498Szrj    Return the new diag_class of DIAGNOSTIC if it was updated, or
80638fd1498Szrj    DK_UNSPECIFIED otherwise.  */
80738fd1498Szrj 
80838fd1498Szrj static diagnostic_t
update_effective_level_from_pragmas(diagnostic_context * context,diagnostic_info * diagnostic)80938fd1498Szrj update_effective_level_from_pragmas (diagnostic_context *context,
81038fd1498Szrj 				     diagnostic_info *diagnostic)
81138fd1498Szrj {
81238fd1498Szrj   diagnostic_t diag_class = DK_UNSPECIFIED;
81338fd1498Szrj 
81438fd1498Szrj   if (context->n_classification_history > 0)
81538fd1498Szrj     {
81638fd1498Szrj       location_t location = diagnostic_location (diagnostic);
81738fd1498Szrj 
81838fd1498Szrj       /* FIXME: Stupid search.  Optimize later. */
81938fd1498Szrj       for (int i = context->n_classification_history - 1; i >= 0; i --)
82038fd1498Szrj 	{
82138fd1498Szrj 	  if (linemap_location_before_p
82238fd1498Szrj 	      (line_table,
82338fd1498Szrj 	       context->classification_history[i].location,
82438fd1498Szrj 	       location))
82538fd1498Szrj 	    {
82638fd1498Szrj 	      if (context->classification_history[i].kind == (int) DK_POP)
82738fd1498Szrj 		{
82838fd1498Szrj 		  i = context->classification_history[i].option;
82938fd1498Szrj 		  continue;
83038fd1498Szrj 		}
83138fd1498Szrj 	      int option = context->classification_history[i].option;
83238fd1498Szrj 	      /* The option 0 is for all the diagnostics.  */
83338fd1498Szrj 	      if (option == 0 || option == diagnostic->option_index)
83438fd1498Szrj 		{
83538fd1498Szrj 		  diag_class = context->classification_history[i].kind;
83638fd1498Szrj 		  if (diag_class != DK_UNSPECIFIED)
83738fd1498Szrj 		    diagnostic->kind = diag_class;
83838fd1498Szrj 		  break;
83938fd1498Szrj 		}
84038fd1498Szrj 	    }
84138fd1498Szrj 	}
84238fd1498Szrj     }
84338fd1498Szrj 
84438fd1498Szrj   return diag_class;
84538fd1498Szrj }
84638fd1498Szrj 
84738fd1498Szrj /* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
84838fd1498Szrj    printer, e.g. " [-Werror=uninitialized]".
84938fd1498Szrj    Subroutine of diagnostic_report_diagnostic.  */
85038fd1498Szrj 
85138fd1498Szrj static void
print_option_information(diagnostic_context * context,const diagnostic_info * diagnostic,diagnostic_t orig_diag_kind)85238fd1498Szrj print_option_information (diagnostic_context *context,
85338fd1498Szrj 			  const diagnostic_info *diagnostic,
85438fd1498Szrj 			  diagnostic_t orig_diag_kind)
85538fd1498Szrj {
85638fd1498Szrj   char *option_text;
85738fd1498Szrj 
85838fd1498Szrj   option_text = context->option_name (context, diagnostic->option_index,
85938fd1498Szrj 				      orig_diag_kind, diagnostic->kind);
86038fd1498Szrj 
86138fd1498Szrj   if (option_text)
86238fd1498Szrj     {
86338fd1498Szrj       pretty_printer *pp = context->printer;
86438fd1498Szrj       pp_string (pp, " [");
86538fd1498Szrj       pp_string (pp, colorize_start (pp_show_color (pp),
86638fd1498Szrj 				     diagnostic_kind_color[diagnostic->kind]));
86738fd1498Szrj       pp_string (pp, option_text);
86838fd1498Szrj       pp_string (pp, colorize_stop (pp_show_color (pp)));
86938fd1498Szrj       pp_character (pp, ']');
87038fd1498Szrj       free (option_text);
87138fd1498Szrj     }
87238fd1498Szrj }
87338fd1498Szrj 
87438fd1498Szrj /* Report a diagnostic message (an error or a warning) as specified by
87538fd1498Szrj    DC.  This function is *the* subroutine in terms of which front-ends
87638fd1498Szrj    should implement their specific diagnostic handling modules.  The
87738fd1498Szrj    front-end independent format specifiers are exactly those described
87838fd1498Szrj    in the documentation of output_format.
87938fd1498Szrj    Return true if a diagnostic was printed, false otherwise.  */
88038fd1498Szrj 
88138fd1498Szrj bool
diagnostic_report_diagnostic(diagnostic_context * context,diagnostic_info * diagnostic)88238fd1498Szrj diagnostic_report_diagnostic (diagnostic_context *context,
88338fd1498Szrj 			      diagnostic_info *diagnostic)
88438fd1498Szrj {
88538fd1498Szrj   location_t location = diagnostic_location (diagnostic);
88638fd1498Szrj   diagnostic_t orig_diag_kind = diagnostic->kind;
88738fd1498Szrj 
88838fd1498Szrj   /* Give preference to being able to inhibit warnings, before they
88938fd1498Szrj      get reclassified to something else.  */
89038fd1498Szrj   if ((diagnostic->kind == DK_WARNING || diagnostic->kind == DK_PEDWARN)
89138fd1498Szrj       && !diagnostic_report_warnings_p (context, location))
89238fd1498Szrj     return false;
89338fd1498Szrj 
89438fd1498Szrj   if (diagnostic->kind == DK_PEDWARN)
89538fd1498Szrj     {
89638fd1498Szrj       diagnostic->kind = pedantic_warning_kind (context);
89738fd1498Szrj       /* We do this to avoid giving the message for -pedantic-errors.  */
89838fd1498Szrj       orig_diag_kind = diagnostic->kind;
89938fd1498Szrj     }
90038fd1498Szrj 
90138fd1498Szrj   if (diagnostic->kind == DK_NOTE && context->inhibit_notes_p)
90238fd1498Szrj     return false;
90338fd1498Szrj 
90438fd1498Szrj   if (context->lock > 0)
90538fd1498Szrj     {
90638fd1498Szrj       /* If we're reporting an ICE in the middle of some other error,
90738fd1498Szrj 	 try to flush out the previous error, then let this one
90838fd1498Szrj 	 through.  Don't do this more than once.  */
90938fd1498Szrj       if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
91038fd1498Szrj 	  && context->lock == 1)
91138fd1498Szrj 	pp_newline_and_flush (context->printer);
91238fd1498Szrj       else
91338fd1498Szrj 	error_recursion (context);
91438fd1498Szrj     }
91538fd1498Szrj 
91638fd1498Szrj   /* If the user requested that warnings be treated as errors, so be
91738fd1498Szrj      it.  Note that we do this before the next block so that
91838fd1498Szrj      individual warnings can be overridden back to warnings with
91938fd1498Szrj      -Wno-error=*.  */
92038fd1498Szrj   if (context->warning_as_error_requested
92138fd1498Szrj       && diagnostic->kind == DK_WARNING)
92238fd1498Szrj     diagnostic->kind = DK_ERROR;
92338fd1498Szrj 
92438fd1498Szrj   if (diagnostic->option_index
92538fd1498Szrj       && diagnostic->option_index != permissive_error_option (context))
92638fd1498Szrj     {
92738fd1498Szrj       /* This tests if the user provided the appropriate -Wfoo or
92838fd1498Szrj 	 -Wno-foo option.  */
92938fd1498Szrj       if (! context->option_enabled (diagnostic->option_index,
93038fd1498Szrj 				     context->option_state))
93138fd1498Szrj 	return false;
93238fd1498Szrj 
93338fd1498Szrj       /* This tests for #pragma diagnostic changes.  */
93438fd1498Szrj       diagnostic_t diag_class
93538fd1498Szrj 	= update_effective_level_from_pragmas (context, diagnostic);
93638fd1498Szrj 
93738fd1498Szrj       /* This tests if the user provided the appropriate -Werror=foo
93838fd1498Szrj 	 option.  */
93938fd1498Szrj       if (diag_class == DK_UNSPECIFIED
94038fd1498Szrj 	  && (context->classify_diagnostic[diagnostic->option_index]
94138fd1498Szrj 	      != DK_UNSPECIFIED))
94238fd1498Szrj 	diagnostic->kind
94338fd1498Szrj 	  = context->classify_diagnostic[diagnostic->option_index];
94438fd1498Szrj 
94538fd1498Szrj       /* This allows for future extensions, like temporarily disabling
94638fd1498Szrj 	 warnings for ranges of source code.  */
94738fd1498Szrj       if (diagnostic->kind == DK_IGNORED)
94838fd1498Szrj 	return false;
94938fd1498Szrj     }
95038fd1498Szrj 
95138fd1498Szrj   if (diagnostic->kind != DK_NOTE)
95238fd1498Szrj     diagnostic_check_max_errors (context);
95338fd1498Szrj 
95438fd1498Szrj   context->lock++;
95538fd1498Szrj 
95638fd1498Szrj   if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
95738fd1498Szrj     {
95838fd1498Szrj       /* When not checking, ICEs are converted to fatal errors when an
95938fd1498Szrj 	 error has already occurred.  This is counteracted by
96038fd1498Szrj 	 abort_on_error.  */
96138fd1498Szrj       if (!CHECKING_P
96238fd1498Szrj 	  && (diagnostic_kind_count (context, DK_ERROR) > 0
96338fd1498Szrj 	      || diagnostic_kind_count (context, DK_SORRY) > 0)
96438fd1498Szrj 	  && !context->abort_on_error)
96538fd1498Szrj 	{
96638fd1498Szrj 	  expanded_location s
96738fd1498Szrj 	    = expand_location (diagnostic_location (diagnostic));
96838fd1498Szrj 	  fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
96938fd1498Szrj 		   s.file, s.line);
97038fd1498Szrj 	  exit (ICE_EXIT_CODE);
97138fd1498Szrj 	}
97238fd1498Szrj       if (context->internal_error)
97338fd1498Szrj 	(*context->internal_error) (context,
97438fd1498Szrj 				    diagnostic->message.format_spec,
97538fd1498Szrj 				    diagnostic->message.args_ptr);
97638fd1498Szrj     }
97738fd1498Szrj   if (diagnostic->kind == DK_ERROR && orig_diag_kind == DK_WARNING)
97838fd1498Szrj     ++diagnostic_kind_count (context, DK_WERROR);
97938fd1498Szrj   else
98038fd1498Szrj     ++diagnostic_kind_count (context, diagnostic->kind);
98138fd1498Szrj 
98238fd1498Szrj   diagnostic->message.x_data = &diagnostic->x_data;
98338fd1498Szrj   diagnostic->x_data = NULL;
98438fd1498Szrj   pp_format (context->printer, &diagnostic->message);
98538fd1498Szrj   (*diagnostic_starter (context)) (context, diagnostic);
98638fd1498Szrj   pp_output_formatted_text (context->printer);
98738fd1498Szrj   if (context->show_option_requested)
98838fd1498Szrj     print_option_information (context, diagnostic, orig_diag_kind);
98938fd1498Szrj   (*diagnostic_finalizer (context)) (context, diagnostic);
99038fd1498Szrj   if (context->parseable_fixits_p)
99138fd1498Szrj     {
99238fd1498Szrj       print_parseable_fixits (context->printer, diagnostic->richloc);
99338fd1498Szrj       pp_flush (context->printer);
99438fd1498Szrj     }
99538fd1498Szrj   diagnostic_action_after_output (context, diagnostic->kind);
99638fd1498Szrj   diagnostic->x_data = NULL;
99738fd1498Szrj 
99838fd1498Szrj   if (context->edit_context_ptr)
99938fd1498Szrj     if (diagnostic->richloc->fixits_can_be_auto_applied_p ())
100038fd1498Szrj       context->edit_context_ptr->add_fixits (diagnostic->richloc);
100138fd1498Szrj 
100238fd1498Szrj   context->lock--;
100338fd1498Szrj 
100438fd1498Szrj   return true;
100538fd1498Szrj }
100638fd1498Szrj 
100738fd1498Szrj /* Given a partial pathname as input, return another pathname that
100838fd1498Szrj    shares no directory elements with the pathname of __FILE__.  This
100938fd1498Szrj    is used by fancy_abort() to print `Internal compiler error in expr.c'
101038fd1498Szrj    instead of `Internal compiler error in ../../GCC/gcc/expr.c'.  */
101138fd1498Szrj 
101238fd1498Szrj const char *
trim_filename(const char * name)101338fd1498Szrj trim_filename (const char *name)
101438fd1498Szrj {
101538fd1498Szrj   static const char this_file[] = __FILE__;
101638fd1498Szrj   const char *p = name, *q = this_file;
101738fd1498Szrj 
101838fd1498Szrj   /* First skip any "../" in each filename.  This allows us to give a proper
101938fd1498Szrj      reference to a file in a subdirectory.  */
102038fd1498Szrj   while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2]))
102138fd1498Szrj     p += 3;
102238fd1498Szrj 
102338fd1498Szrj   while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2]))
102438fd1498Szrj     q += 3;
102538fd1498Szrj 
102638fd1498Szrj   /* Now skip any parts the two filenames have in common.  */
102738fd1498Szrj   while (*p == *q && *p != 0 && *q != 0)
102838fd1498Szrj     p++, q++;
102938fd1498Szrj 
103038fd1498Szrj   /* Now go backwards until the previous directory separator.  */
103138fd1498Szrj   while (p > name && !IS_DIR_SEPARATOR (p[-1]))
103238fd1498Szrj     p--;
103338fd1498Szrj 
103438fd1498Szrj   return p;
103538fd1498Szrj }
103638fd1498Szrj 
103738fd1498Szrj /* Standard error reporting routines in increasing order of severity.
103838fd1498Szrj    All of these take arguments like printf.  */
103938fd1498Szrj 
104038fd1498Szrj /* Text to be emitted verbatim to the error message stream; this
104138fd1498Szrj    produces no prefix and disables line-wrapping.  Use rarely.  */
104238fd1498Szrj void
verbatim(const char * gmsgid,...)104338fd1498Szrj verbatim (const char *gmsgid, ...)
104438fd1498Szrj {
104538fd1498Szrj   text_info text;
104638fd1498Szrj   va_list ap;
104738fd1498Szrj 
104838fd1498Szrj   va_start (ap, gmsgid);
104938fd1498Szrj   text.err_no = errno;
105038fd1498Szrj   text.args_ptr = &ap;
105138fd1498Szrj   text.format_spec = _(gmsgid);
105238fd1498Szrj   text.x_data = NULL;
105338fd1498Szrj   pp_format_verbatim (global_dc->printer, &text);
105438fd1498Szrj   pp_newline_and_flush (global_dc->printer);
105538fd1498Szrj   va_end (ap);
105638fd1498Szrj }
105738fd1498Szrj 
105838fd1498Szrj /* Add a note with text GMSGID and with LOCATION to the diagnostic CONTEXT.  */
105938fd1498Szrj void
diagnostic_append_note(diagnostic_context * context,location_t location,const char * gmsgid,...)106038fd1498Szrj diagnostic_append_note (diagnostic_context *context,
106138fd1498Szrj                         location_t location,
106238fd1498Szrj                         const char * gmsgid, ...)
106338fd1498Szrj {
106438fd1498Szrj   diagnostic_info diagnostic;
106538fd1498Szrj   va_list ap;
106638fd1498Szrj   rich_location richloc (line_table, location);
106738fd1498Szrj 
106838fd1498Szrj   va_start (ap, gmsgid);
106938fd1498Szrj   diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
107038fd1498Szrj   if (context->inhibit_notes_p)
107138fd1498Szrj     {
107238fd1498Szrj       va_end (ap);
107338fd1498Szrj       return;
107438fd1498Szrj     }
1075*58e805e6Szrj   char *saved_prefix = pp_take_prefix (context->printer);
107638fd1498Szrj   pp_set_prefix (context->printer,
107738fd1498Szrj                  diagnostic_build_prefix (context, &diagnostic));
107838fd1498Szrj   pp_format (context->printer, &diagnostic.message);
107938fd1498Szrj   pp_output_formatted_text (context->printer);
108038fd1498Szrj   pp_destroy_prefix (context->printer);
108138fd1498Szrj   pp_set_prefix (context->printer, saved_prefix);
108238fd1498Szrj   diagnostic_show_locus (context, &richloc, DK_NOTE);
108338fd1498Szrj   va_end (ap);
108438fd1498Szrj }
108538fd1498Szrj 
108638fd1498Szrj /* Implement emit_diagnostic, inform, warning, warning_at, pedwarn,
108738fd1498Szrj    permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
108838fd1498Szrj    and internal_error_no_backtrace, as documented and defined below.  */
108938fd1498Szrj static bool
diagnostic_impl(rich_location * richloc,int opt,const char * gmsgid,va_list * ap,diagnostic_t kind)109038fd1498Szrj diagnostic_impl (rich_location *richloc, int opt,
109138fd1498Szrj 		 const char *gmsgid,
109238fd1498Szrj 		 va_list *ap, diagnostic_t kind)
109338fd1498Szrj {
109438fd1498Szrj   diagnostic_info diagnostic;
109538fd1498Szrj   if (kind == DK_PERMERROR)
109638fd1498Szrj     {
109738fd1498Szrj       diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
109838fd1498Szrj 			   permissive_error_kind (global_dc));
109938fd1498Szrj       diagnostic.option_index = permissive_error_option (global_dc);
110038fd1498Szrj     }
110138fd1498Szrj   else
110238fd1498Szrj     {
110338fd1498Szrj       diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
110438fd1498Szrj       if (kind == DK_WARNING || kind == DK_PEDWARN)
110538fd1498Szrj 	diagnostic.option_index = opt;
110638fd1498Szrj     }
110738fd1498Szrj   return diagnostic_report_diagnostic (global_dc, &diagnostic);
110838fd1498Szrj }
110938fd1498Szrj 
111038fd1498Szrj /* Implement inform_n, warning_n, and error_n, as documented and
111138fd1498Szrj    defined below.  */
111238fd1498Szrj static bool
diagnostic_n_impl(rich_location * richloc,int opt,unsigned HOST_WIDE_INT n,const char * singular_gmsgid,const char * plural_gmsgid,va_list * ap,diagnostic_t kind)111338fd1498Szrj diagnostic_n_impl (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
111438fd1498Szrj 		   const char *singular_gmsgid,
111538fd1498Szrj 		   const char *plural_gmsgid,
111638fd1498Szrj 		   va_list *ap, diagnostic_t kind)
111738fd1498Szrj {
111838fd1498Szrj   diagnostic_info diagnostic;
111938fd1498Szrj   unsigned long gtn;
112038fd1498Szrj 
112138fd1498Szrj   if (sizeof n <= sizeof gtn)
112238fd1498Szrj     gtn = n;
112338fd1498Szrj   else
112438fd1498Szrj     /* Use the largest number ngettext can handle, otherwise
112538fd1498Szrj        preserve the six least significant decimal digits for
112638fd1498Szrj        languages where the plural form depends on them.  */
112738fd1498Szrj     gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU;
112838fd1498Szrj 
112938fd1498Szrj   const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
113038fd1498Szrj   diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
113138fd1498Szrj   if (kind == DK_WARNING)
113238fd1498Szrj     diagnostic.option_index = opt;
113338fd1498Szrj   return diagnostic_report_diagnostic (global_dc, &diagnostic);
113438fd1498Szrj }
113538fd1498Szrj 
113638fd1498Szrj /* Wrapper around diagnostic_impl taking a variable argument list.  */
113738fd1498Szrj 
113838fd1498Szrj bool
emit_diagnostic(diagnostic_t kind,location_t location,int opt,const char * gmsgid,...)113938fd1498Szrj emit_diagnostic (diagnostic_t kind, location_t location, int opt,
114038fd1498Szrj 		 const char *gmsgid, ...)
114138fd1498Szrj {
114238fd1498Szrj   va_list ap;
114338fd1498Szrj   va_start (ap, gmsgid);
114438fd1498Szrj   rich_location richloc (line_table, location);
114538fd1498Szrj   bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, kind);
114638fd1498Szrj   va_end (ap);
114738fd1498Szrj   return ret;
114838fd1498Szrj }
114938fd1498Szrj 
115038fd1498Szrj /* Wrapper around diagnostic_impl taking a va_list parameter.  */
115138fd1498Szrj 
115238fd1498Szrj bool
emit_diagnostic_valist(diagnostic_t kind,location_t location,int opt,const char * gmsgid,va_list * ap)115338fd1498Szrj emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
115438fd1498Szrj 			const char *gmsgid, va_list *ap)
115538fd1498Szrj {
115638fd1498Szrj   rich_location richloc (line_table, location);
115738fd1498Szrj   return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
115838fd1498Szrj }
115938fd1498Szrj 
116038fd1498Szrj /* An informative note at LOCATION.  Use this for additional details on an error
116138fd1498Szrj    message.  */
116238fd1498Szrj void
inform(location_t location,const char * gmsgid,...)116338fd1498Szrj inform (location_t location, const char *gmsgid, ...)
116438fd1498Szrj {
116538fd1498Szrj   va_list ap;
116638fd1498Szrj   va_start (ap, gmsgid);
116738fd1498Szrj   rich_location richloc (line_table, location);
116838fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_NOTE);
116938fd1498Szrj   va_end (ap);
117038fd1498Szrj }
117138fd1498Szrj 
117238fd1498Szrj /* Same as "inform" above, but at RICHLOC.  */
117338fd1498Szrj void
inform(rich_location * richloc,const char * gmsgid,...)117438fd1498Szrj inform (rich_location *richloc, const char *gmsgid, ...)
117538fd1498Szrj {
117638fd1498Szrj   gcc_assert (richloc);
117738fd1498Szrj 
117838fd1498Szrj   va_list ap;
117938fd1498Szrj   va_start (ap, gmsgid);
118038fd1498Szrj   diagnostic_impl (richloc, -1, gmsgid, &ap, DK_NOTE);
118138fd1498Szrj   va_end (ap);
118238fd1498Szrj }
118338fd1498Szrj 
118438fd1498Szrj /* An informative note at LOCATION.  Use this for additional details on an
118538fd1498Szrj    error message.  */
118638fd1498Szrj void
inform_n(location_t location,unsigned HOST_WIDE_INT n,const char * singular_gmsgid,const char * plural_gmsgid,...)118738fd1498Szrj inform_n (location_t location, unsigned HOST_WIDE_INT n,
118838fd1498Szrj 	  const char *singular_gmsgid, const char *plural_gmsgid, ...)
118938fd1498Szrj {
119038fd1498Szrj   va_list ap;
119138fd1498Szrj   va_start (ap, plural_gmsgid);
119238fd1498Szrj   rich_location richloc (line_table, location);
119338fd1498Szrj   diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
119438fd1498Szrj 		     &ap, DK_NOTE);
119538fd1498Szrj   va_end (ap);
119638fd1498Szrj }
119738fd1498Szrj 
119838fd1498Szrj /* A warning at INPUT_LOCATION.  Use this for code which is correct according
119938fd1498Szrj    to the relevant language specification but is likely to be buggy anyway.
120038fd1498Szrj    Returns true if the warning was printed, false if it was inhibited.  */
120138fd1498Szrj bool
warning(int opt,const char * gmsgid,...)120238fd1498Szrj warning (int opt, const char *gmsgid, ...)
120338fd1498Szrj {
120438fd1498Szrj   va_list ap;
120538fd1498Szrj   va_start (ap, gmsgid);
120638fd1498Szrj   rich_location richloc (line_table, input_location);
120738fd1498Szrj   bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
120838fd1498Szrj   va_end (ap);
120938fd1498Szrj   return ret;
121038fd1498Szrj }
121138fd1498Szrj 
121238fd1498Szrj /* A warning at LOCATION.  Use this for code which is correct according to the
121338fd1498Szrj    relevant language specification but is likely to be buggy anyway.
121438fd1498Szrj    Returns true if the warning was printed, false if it was inhibited.  */
121538fd1498Szrj 
121638fd1498Szrj bool
warning_at(location_t location,int opt,const char * gmsgid,...)121738fd1498Szrj warning_at (location_t location, int opt, const char *gmsgid, ...)
121838fd1498Szrj {
121938fd1498Szrj   va_list ap;
122038fd1498Szrj   va_start (ap, gmsgid);
122138fd1498Szrj   rich_location richloc (line_table, location);
122238fd1498Szrj   bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
122338fd1498Szrj   va_end (ap);
122438fd1498Szrj   return ret;
122538fd1498Szrj }
122638fd1498Szrj 
122738fd1498Szrj /* Same as "warning at" above, but using RICHLOC.  */
122838fd1498Szrj 
122938fd1498Szrj bool
warning_at(rich_location * richloc,int opt,const char * gmsgid,...)123038fd1498Szrj warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
123138fd1498Szrj {
123238fd1498Szrj   gcc_assert (richloc);
123338fd1498Szrj 
123438fd1498Szrj   va_list ap;
123538fd1498Szrj   va_start (ap, gmsgid);
123638fd1498Szrj   bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
123738fd1498Szrj   va_end (ap);
123838fd1498Szrj   return ret;
123938fd1498Szrj }
124038fd1498Szrj 
124138fd1498Szrj /* Same as warning_n plural variant below, but using RICHLOC.  */
124238fd1498Szrj 
124338fd1498Szrj bool
warning_n(rich_location * richloc,int opt,unsigned HOST_WIDE_INT n,const char * singular_gmsgid,const char * plural_gmsgid,...)124438fd1498Szrj warning_n (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
124538fd1498Szrj 	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
124638fd1498Szrj {
124738fd1498Szrj   gcc_assert (richloc);
124838fd1498Szrj 
124938fd1498Szrj   va_list ap;
125038fd1498Szrj   va_start (ap, plural_gmsgid);
125138fd1498Szrj   bool ret = diagnostic_n_impl (richloc, opt, n,
125238fd1498Szrj 				singular_gmsgid, plural_gmsgid,
125338fd1498Szrj 				&ap, DK_WARNING);
125438fd1498Szrj   va_end (ap);
125538fd1498Szrj   return ret;
125638fd1498Szrj }
125738fd1498Szrj 
125838fd1498Szrj /* A warning at LOCATION.  Use this for code which is correct according to the
125938fd1498Szrj    relevant language specification but is likely to be buggy anyway.
126038fd1498Szrj    Returns true if the warning was printed, false if it was inhibited.  */
126138fd1498Szrj 
126238fd1498Szrj bool
warning_n(location_t location,int opt,unsigned HOST_WIDE_INT n,const char * singular_gmsgid,const char * plural_gmsgid,...)126338fd1498Szrj warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
126438fd1498Szrj 	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
126538fd1498Szrj {
126638fd1498Szrj   va_list ap;
126738fd1498Szrj   va_start (ap, plural_gmsgid);
126838fd1498Szrj   rich_location richloc (line_table, location);
126938fd1498Szrj   bool ret = diagnostic_n_impl (&richloc, opt, n,
127038fd1498Szrj 				singular_gmsgid, plural_gmsgid,
127138fd1498Szrj 				&ap, DK_WARNING);
127238fd1498Szrj   va_end (ap);
127338fd1498Szrj   return ret;
127438fd1498Szrj }
127538fd1498Szrj 
127638fd1498Szrj /* A "pedantic" warning at LOCATION: issues a warning unless
127738fd1498Szrj    -pedantic-errors was given on the command line, in which case it
127838fd1498Szrj    issues an error.  Use this for diagnostics required by the relevant
127938fd1498Szrj    language standard, if you have chosen not to make them errors.
128038fd1498Szrj 
128138fd1498Szrj    Note that these diagnostics are issued independent of the setting
128238fd1498Szrj    of the -Wpedantic command-line switch.  To get a warning enabled
128338fd1498Szrj    only with that switch, use either "if (pedantic) pedwarn
128438fd1498Szrj    (OPT_Wpedantic,...)" or just "pedwarn (OPT_Wpedantic,..)".  To get a
128538fd1498Szrj    pedwarn independently of the -Wpedantic switch use "pedwarn (0,...)".
128638fd1498Szrj 
128738fd1498Szrj    Returns true if the warning was printed, false if it was inhibited.  */
128838fd1498Szrj 
128938fd1498Szrj bool
pedwarn(location_t location,int opt,const char * gmsgid,...)129038fd1498Szrj pedwarn (location_t location, int opt, const char *gmsgid, ...)
129138fd1498Szrj {
129238fd1498Szrj   va_list ap;
129338fd1498Szrj   va_start (ap, gmsgid);
129438fd1498Szrj   rich_location richloc (line_table, location);
129538fd1498Szrj   bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_PEDWARN);
129638fd1498Szrj   va_end (ap);
129738fd1498Szrj   return ret;
129838fd1498Szrj }
129938fd1498Szrj 
130038fd1498Szrj /* Same as pedwarn above, but using RICHLOC.  */
130138fd1498Szrj 
130238fd1498Szrj bool
pedwarn(rich_location * richloc,int opt,const char * gmsgid,...)130338fd1498Szrj pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
130438fd1498Szrj {
130538fd1498Szrj   gcc_assert (richloc);
130638fd1498Szrj 
130738fd1498Szrj   va_list ap;
130838fd1498Szrj   va_start (ap, gmsgid);
130938fd1498Szrj   bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
131038fd1498Szrj   va_end (ap);
131138fd1498Szrj   return ret;
131238fd1498Szrj }
131338fd1498Szrj 
131438fd1498Szrj /* A "permissive" error at LOCATION: issues an error unless
131538fd1498Szrj    -fpermissive was given on the command line, in which case it issues
131638fd1498Szrj    a warning.  Use this for things that really should be errors but we
131738fd1498Szrj    want to support legacy code.
131838fd1498Szrj 
131938fd1498Szrj    Returns true if the warning was printed, false if it was inhibited.  */
132038fd1498Szrj 
132138fd1498Szrj bool
permerror(location_t location,const char * gmsgid,...)132238fd1498Szrj permerror (location_t location, const char *gmsgid, ...)
132338fd1498Szrj {
132438fd1498Szrj   va_list ap;
132538fd1498Szrj   va_start (ap, gmsgid);
132638fd1498Szrj   rich_location richloc (line_table, location);
132738fd1498Szrj   bool ret = diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_PERMERROR);
132838fd1498Szrj   va_end (ap);
132938fd1498Szrj   return ret;
133038fd1498Szrj }
133138fd1498Szrj 
133238fd1498Szrj /* Same as "permerror" above, but at RICHLOC.  */
133338fd1498Szrj 
133438fd1498Szrj bool
permerror(rich_location * richloc,const char * gmsgid,...)133538fd1498Szrj permerror (rich_location *richloc, const char *gmsgid, ...)
133638fd1498Szrj {
133738fd1498Szrj   gcc_assert (richloc);
133838fd1498Szrj 
133938fd1498Szrj   va_list ap;
134038fd1498Szrj   va_start (ap, gmsgid);
134138fd1498Szrj   bool ret = diagnostic_impl (richloc, -1, gmsgid, &ap, DK_PERMERROR);
134238fd1498Szrj   va_end (ap);
134338fd1498Szrj   return ret;
134438fd1498Szrj }
134538fd1498Szrj 
134638fd1498Szrj /* A hard error: the code is definitely ill-formed, and an object file
134738fd1498Szrj    will not be produced.  */
134838fd1498Szrj void
error(const char * gmsgid,...)134938fd1498Szrj error (const char *gmsgid, ...)
135038fd1498Szrj {
135138fd1498Szrj   va_list ap;
135238fd1498Szrj   va_start (ap, gmsgid);
135338fd1498Szrj   rich_location richloc (line_table, input_location);
135438fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
135538fd1498Szrj   va_end (ap);
135638fd1498Szrj }
135738fd1498Szrj 
135838fd1498Szrj /* A hard error: the code is definitely ill-formed, and an object file
135938fd1498Szrj    will not be produced.  */
136038fd1498Szrj void
error_n(location_t location,unsigned HOST_WIDE_INT n,const char * singular_gmsgid,const char * plural_gmsgid,...)136138fd1498Szrj error_n (location_t location, unsigned HOST_WIDE_INT n,
136238fd1498Szrj 	 const char *singular_gmsgid, const char *plural_gmsgid, ...)
136338fd1498Szrj {
136438fd1498Szrj   va_list ap;
136538fd1498Szrj   va_start (ap, plural_gmsgid);
136638fd1498Szrj   rich_location richloc (line_table, location);
136738fd1498Szrj   diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
136838fd1498Szrj 		     &ap, DK_ERROR);
136938fd1498Szrj   va_end (ap);
137038fd1498Szrj }
137138fd1498Szrj 
137238fd1498Szrj /* Same as above, but use location LOC instead of input_location.  */
137338fd1498Szrj void
error_at(location_t loc,const char * gmsgid,...)137438fd1498Szrj error_at (location_t loc, const char *gmsgid, ...)
137538fd1498Szrj {
137638fd1498Szrj   va_list ap;
137738fd1498Szrj   va_start (ap, gmsgid);
137838fd1498Szrj   rich_location richloc (line_table, loc);
137938fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
138038fd1498Szrj   va_end (ap);
138138fd1498Szrj }
138238fd1498Szrj 
138338fd1498Szrj /* Same as above, but use RICH_LOC.  */
138438fd1498Szrj 
138538fd1498Szrj void
error_at(rich_location * richloc,const char * gmsgid,...)138638fd1498Szrj error_at (rich_location *richloc, const char *gmsgid, ...)
138738fd1498Szrj {
138838fd1498Szrj   gcc_assert (richloc);
138938fd1498Szrj 
139038fd1498Szrj   va_list ap;
139138fd1498Szrj   va_start (ap, gmsgid);
139238fd1498Szrj   diagnostic_impl (richloc, -1, gmsgid, &ap, DK_ERROR);
139338fd1498Szrj   va_end (ap);
139438fd1498Szrj }
139538fd1498Szrj 
139638fd1498Szrj /* "Sorry, not implemented."  Use for a language feature which is
139738fd1498Szrj    required by the relevant specification but not implemented by GCC.
139838fd1498Szrj    An object file will not be produced.  */
139938fd1498Szrj void
sorry(const char * gmsgid,...)140038fd1498Szrj sorry (const char *gmsgid, ...)
140138fd1498Szrj {
140238fd1498Szrj   va_list ap;
140338fd1498Szrj   va_start (ap, gmsgid);
140438fd1498Szrj   rich_location richloc (line_table, input_location);
140538fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
140638fd1498Szrj   va_end (ap);
140738fd1498Szrj }
140838fd1498Szrj 
140938fd1498Szrj /* Return true if an error or a "sorry" has been seen.  Various
141038fd1498Szrj    processing is disabled after errors.  */
141138fd1498Szrj bool
seen_error(void)141238fd1498Szrj seen_error (void)
141338fd1498Szrj {
141438fd1498Szrj   return errorcount || sorrycount;
141538fd1498Szrj }
141638fd1498Szrj 
141738fd1498Szrj /* An error which is severe enough that we make no attempt to
141838fd1498Szrj    continue.  Do not use this for internal consistency checks; that's
141938fd1498Szrj    internal_error.  Use of this function should be rare.  */
142038fd1498Szrj void
fatal_error(location_t loc,const char * gmsgid,...)142138fd1498Szrj fatal_error (location_t loc, const char *gmsgid, ...)
142238fd1498Szrj {
142338fd1498Szrj   va_list ap;
142438fd1498Szrj   va_start (ap, gmsgid);
142538fd1498Szrj   rich_location richloc (line_table, loc);
142638fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_FATAL);
142738fd1498Szrj   va_end (ap);
142838fd1498Szrj 
142938fd1498Szrj   gcc_unreachable ();
143038fd1498Szrj }
143138fd1498Szrj 
143238fd1498Szrj /* An internal consistency check has failed.  We make no attempt to
143338fd1498Szrj    continue.  Note that unless there is debugging value to be had from
143438fd1498Szrj    a more specific message, or some other good reason, you should use
143538fd1498Szrj    abort () instead of calling this function directly.  */
143638fd1498Szrj void
internal_error(const char * gmsgid,...)143738fd1498Szrj internal_error (const char *gmsgid, ...)
143838fd1498Szrj {
143938fd1498Szrj   va_list ap;
144038fd1498Szrj   va_start (ap, gmsgid);
144138fd1498Szrj   rich_location richloc (line_table, input_location);
144238fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE);
144338fd1498Szrj   va_end (ap);
144438fd1498Szrj 
144538fd1498Szrj   gcc_unreachable ();
144638fd1498Szrj }
144738fd1498Szrj 
144838fd1498Szrj /* Like internal_error, but no backtrace will be printed.  Used when
144938fd1498Szrj    the internal error does not happen at the current location, but happened
145038fd1498Szrj    somewhere else.  */
145138fd1498Szrj void
internal_error_no_backtrace(const char * gmsgid,...)145238fd1498Szrj internal_error_no_backtrace (const char *gmsgid, ...)
145338fd1498Szrj {
145438fd1498Szrj   va_list ap;
145538fd1498Szrj   va_start (ap, gmsgid);
145638fd1498Szrj   rich_location richloc (line_table, input_location);
145738fd1498Szrj   diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE_NOBT);
145838fd1498Szrj   va_end (ap);
145938fd1498Szrj 
146038fd1498Szrj   gcc_unreachable ();
146138fd1498Szrj }
146238fd1498Szrj 
146338fd1498Szrj /* Special case error functions.  Most are implemented in terms of the
146438fd1498Szrj    above, or should be.  */
146538fd1498Szrj 
146638fd1498Szrj /* Print a diagnostic MSGID on FILE.  This is just fprintf, except it
146738fd1498Szrj    runs its second argument through gettext.  */
146838fd1498Szrj void
fnotice(FILE * file,const char * cmsgid,...)146938fd1498Szrj fnotice (FILE *file, const char *cmsgid, ...)
147038fd1498Szrj {
147138fd1498Szrj   va_list ap;
147238fd1498Szrj 
147338fd1498Szrj   va_start (ap, cmsgid);
147438fd1498Szrj   vfprintf (file, _(cmsgid), ap);
147538fd1498Szrj   va_end (ap);
147638fd1498Szrj }
147738fd1498Szrj 
147838fd1498Szrj /* Inform the user that an error occurred while trying to report some
147938fd1498Szrj    other error.  This indicates catastrophic internal inconsistencies,
148038fd1498Szrj    so give up now.  But do try to flush out the previous error.
148138fd1498Szrj    This mustn't use internal_error, that will cause infinite recursion.  */
148238fd1498Szrj 
148338fd1498Szrj static void
error_recursion(diagnostic_context * context)148438fd1498Szrj error_recursion (diagnostic_context *context)
148538fd1498Szrj {
148638fd1498Szrj   if (context->lock < 3)
148738fd1498Szrj     pp_newline_and_flush (context->printer);
148838fd1498Szrj 
148938fd1498Szrj   fnotice (stderr,
149038fd1498Szrj 	   "Internal compiler error: Error reporting routines re-entered.\n");
149138fd1498Szrj 
149238fd1498Szrj   /* Call diagnostic_action_after_output to get the "please submit a bug
149338fd1498Szrj      report" message.  */
149438fd1498Szrj   diagnostic_action_after_output (context, DK_ICE);
149538fd1498Szrj 
149638fd1498Szrj   /* Do not use gcc_unreachable here; that goes through internal_error
149738fd1498Szrj      and therefore would cause infinite recursion.  */
149838fd1498Szrj   real_abort ();
149938fd1498Szrj }
150038fd1498Szrj 
150138fd1498Szrj /* Report an internal compiler error in a friendly manner.  This is
150238fd1498Szrj    the function that gets called upon use of abort() in the source
150338fd1498Szrj    code generally, thanks to a special macro.  */
150438fd1498Szrj 
150538fd1498Szrj void
fancy_abort(const char * file,int line,const char * function)150638fd1498Szrj fancy_abort (const char *file, int line, const char *function)
150738fd1498Szrj {
150838fd1498Szrj   internal_error ("in %s, at %s:%d", function, trim_filename (file), line);
150938fd1498Szrj }
151038fd1498Szrj 
151138fd1498Szrj /* Really call the system 'abort'.  This has to go right at the end of
151238fd1498Szrj    this file, so that there are no functions after it that call abort
151338fd1498Szrj    and get the system abort instead of our macro.  */
151438fd1498Szrj #undef abort
151538fd1498Szrj static void
real_abort(void)151638fd1498Szrj real_abort (void)
151738fd1498Szrj {
151838fd1498Szrj   abort ();
151938fd1498Szrj }
152038fd1498Szrj 
152138fd1498Szrj #if CHECKING_P
152238fd1498Szrj 
152338fd1498Szrj namespace selftest {
152438fd1498Szrj 
152538fd1498Szrj /* Helper function for test_print_escaped_string.  */
152638fd1498Szrj 
152738fd1498Szrj static void
assert_print_escaped_string(const location & loc,const char * expected_output,const char * input)152838fd1498Szrj assert_print_escaped_string (const location &loc, const char *expected_output,
152938fd1498Szrj 			     const char *input)
153038fd1498Szrj {
153138fd1498Szrj   pretty_printer pp;
153238fd1498Szrj   print_escaped_string (&pp, input);
153338fd1498Szrj   ASSERT_STREQ_AT (loc, expected_output, pp_formatted_text (&pp));
153438fd1498Szrj }
153538fd1498Szrj 
153638fd1498Szrj #define ASSERT_PRINT_ESCAPED_STRING_STREQ(EXPECTED_OUTPUT, INPUT) \
153738fd1498Szrj     assert_print_escaped_string (SELFTEST_LOCATION, EXPECTED_OUTPUT, INPUT)
153838fd1498Szrj 
153938fd1498Szrj /* Tests of print_escaped_string.  */
154038fd1498Szrj 
154138fd1498Szrj static void
test_print_escaped_string()154238fd1498Szrj test_print_escaped_string ()
154338fd1498Szrj {
154438fd1498Szrj   /* Empty string.  */
154538fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"\"", "");
154638fd1498Szrj 
154738fd1498Szrj   /* Non-empty string.  */
154838fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"hello world\"", "hello world");
154938fd1498Szrj 
155038fd1498Szrj   /* Various things that need to be escaped:  */
155138fd1498Szrj   /* Backslash.  */
155238fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\\after\"",
155338fd1498Szrj 				     "before\\after");
155438fd1498Szrj   /* Tab.  */
155538fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\tafter\"",
155638fd1498Szrj 				     "before\tafter");
155738fd1498Szrj   /* Newline.  */
155838fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\nafter\"",
155938fd1498Szrj 				     "before\nafter");
156038fd1498Szrj   /* Double quote.  */
156138fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\"after\"",
156238fd1498Szrj 				     "before\"after");
156338fd1498Szrj 
156438fd1498Szrj   /* Non-printable characters: BEL: '\a': 0x07 */
156538fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\007after\"",
156638fd1498Szrj 				     "before\aafter");
156738fd1498Szrj   /* Non-printable characters: vertical tab: '\v': 0x0b */
156838fd1498Szrj   ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\013after\"",
156938fd1498Szrj 				     "before\vafter");
157038fd1498Szrj }
157138fd1498Szrj 
157238fd1498Szrj /* Tests of print_parseable_fixits.  */
157338fd1498Szrj 
157438fd1498Szrj /* Verify that print_parseable_fixits emits the empty string if there
157538fd1498Szrj    are no fixits.  */
157638fd1498Szrj 
157738fd1498Szrj static void
test_print_parseable_fixits_none()157838fd1498Szrj test_print_parseable_fixits_none ()
157938fd1498Szrj {
158038fd1498Szrj   pretty_printer pp;
158138fd1498Szrj   rich_location richloc (line_table, UNKNOWN_LOCATION);
158238fd1498Szrj 
158338fd1498Szrj   print_parseable_fixits (&pp, &richloc);
158438fd1498Szrj   ASSERT_STREQ ("", pp_formatted_text (&pp));
158538fd1498Szrj }
158638fd1498Szrj 
158738fd1498Szrj /* Verify that print_parseable_fixits does the right thing if there
158838fd1498Szrj    is an insertion fixit hint.  */
158938fd1498Szrj 
159038fd1498Szrj static void
test_print_parseable_fixits_insert()159138fd1498Szrj test_print_parseable_fixits_insert ()
159238fd1498Szrj {
159338fd1498Szrj   pretty_printer pp;
159438fd1498Szrj   rich_location richloc (line_table, UNKNOWN_LOCATION);
159538fd1498Szrj 
159638fd1498Szrj   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
159738fd1498Szrj   linemap_line_start (line_table, 5, 100);
159838fd1498Szrj   linemap_add (line_table, LC_LEAVE, false, NULL, 0);
159938fd1498Szrj   location_t where = linemap_position_for_column (line_table, 10);
160038fd1498Szrj   richloc.add_fixit_insert_before (where, "added content");
160138fd1498Szrj 
160238fd1498Szrj   print_parseable_fixits (&pp, &richloc);
160338fd1498Szrj   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n",
160438fd1498Szrj 		pp_formatted_text (&pp));
160538fd1498Szrj }
160638fd1498Szrj 
160738fd1498Szrj /* Verify that print_parseable_fixits does the right thing if there
160838fd1498Szrj    is an removal fixit hint.  */
160938fd1498Szrj 
161038fd1498Szrj static void
test_print_parseable_fixits_remove()161138fd1498Szrj test_print_parseable_fixits_remove ()
161238fd1498Szrj {
161338fd1498Szrj   pretty_printer pp;
161438fd1498Szrj   rich_location richloc (line_table, UNKNOWN_LOCATION);
161538fd1498Szrj 
161638fd1498Szrj   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
161738fd1498Szrj   linemap_line_start (line_table, 5, 100);
161838fd1498Szrj   linemap_add (line_table, LC_LEAVE, false, NULL, 0);
161938fd1498Szrj   source_range where;
162038fd1498Szrj   where.m_start = linemap_position_for_column (line_table, 10);
162138fd1498Szrj   where.m_finish = linemap_position_for_column (line_table, 20);
162238fd1498Szrj   richloc.add_fixit_remove (where);
162338fd1498Szrj 
162438fd1498Szrj   print_parseable_fixits (&pp, &richloc);
162538fd1498Szrj   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"\"\n",
162638fd1498Szrj 		pp_formatted_text (&pp));
162738fd1498Szrj }
162838fd1498Szrj 
162938fd1498Szrj /* Verify that print_parseable_fixits does the right thing if there
163038fd1498Szrj    is an replacement fixit hint.  */
163138fd1498Szrj 
163238fd1498Szrj static void
test_print_parseable_fixits_replace()163338fd1498Szrj test_print_parseable_fixits_replace ()
163438fd1498Szrj {
163538fd1498Szrj   pretty_printer pp;
163638fd1498Szrj   rich_location richloc (line_table, UNKNOWN_LOCATION);
163738fd1498Szrj 
163838fd1498Szrj   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
163938fd1498Szrj   linemap_line_start (line_table, 5, 100);
164038fd1498Szrj   linemap_add (line_table, LC_LEAVE, false, NULL, 0);
164138fd1498Szrj   source_range where;
164238fd1498Szrj   where.m_start = linemap_position_for_column (line_table, 10);
164338fd1498Szrj   where.m_finish = linemap_position_for_column (line_table, 20);
164438fd1498Szrj   richloc.add_fixit_replace (where, "replacement");
164538fd1498Szrj 
164638fd1498Szrj   print_parseable_fixits (&pp, &richloc);
164738fd1498Szrj   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"replacement\"\n",
164838fd1498Szrj 		pp_formatted_text (&pp));
164938fd1498Szrj }
165038fd1498Szrj 
165138fd1498Szrj /* Verify that
165238fd1498Szrj      diagnostic_get_location_text (..., SHOW_COLUMN)
165338fd1498Szrj    generates EXPECTED_LOC_TEXT, given FILENAME, LINE, COLUMN, with
165438fd1498Szrj    colorization disabled.  */
165538fd1498Szrj 
165638fd1498Szrj static void
assert_location_text(const char * expected_loc_text,const char * filename,int line,int column,bool show_column)165738fd1498Szrj assert_location_text (const char *expected_loc_text,
165838fd1498Szrj 		      const char *filename, int line, int column,
165938fd1498Szrj 		      bool show_column)
166038fd1498Szrj {
166138fd1498Szrj   test_diagnostic_context dc;
166238fd1498Szrj   dc.show_column = show_column;
166338fd1498Szrj 
166438fd1498Szrj   expanded_location xloc;
166538fd1498Szrj   xloc.file = filename;
166638fd1498Szrj   xloc.line = line;
166738fd1498Szrj   xloc.column = column;
166838fd1498Szrj   xloc.data = NULL;
166938fd1498Szrj   xloc.sysp = false;
167038fd1498Szrj 
167138fd1498Szrj   char *actual_loc_text = diagnostic_get_location_text (&dc, xloc);
167238fd1498Szrj   ASSERT_STREQ (expected_loc_text, actual_loc_text);
167338fd1498Szrj   free (actual_loc_text);
167438fd1498Szrj }
167538fd1498Szrj 
167638fd1498Szrj /* Verify that diagnostic_get_location_text works as expected.  */
167738fd1498Szrj 
167838fd1498Szrj static void
test_diagnostic_get_location_text()167938fd1498Szrj test_diagnostic_get_location_text ()
168038fd1498Szrj {
168138fd1498Szrj   const char *old_progname = progname;
168238fd1498Szrj   progname = "PROGNAME";
168338fd1498Szrj   assert_location_text ("PROGNAME:", NULL, 0, 0, true);
168438fd1498Szrj   assert_location_text ("<built-in>:", "<built-in>", 42, 10, true);
168538fd1498Szrj   assert_location_text ("foo.c:42:10:", "foo.c", 42, 10, true);
168638fd1498Szrj   assert_location_text ("foo.c:42:", "foo.c", 42, 0, true);
168738fd1498Szrj   assert_location_text ("foo.c:", "foo.c", 0, 10, true);
168838fd1498Szrj   assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
168938fd1498Szrj   assert_location_text ("foo.c:", "foo.c", 0, 10, false);
169038fd1498Szrj 
169138fd1498Szrj   maybe_line_and_column (INT_MAX, INT_MAX);
169238fd1498Szrj   maybe_line_and_column (INT_MIN, INT_MIN);
169338fd1498Szrj 
169438fd1498Szrj   progname = old_progname;
169538fd1498Szrj }
169638fd1498Szrj 
169738fd1498Szrj /* Run all of the selftests within this file.  */
169838fd1498Szrj 
169938fd1498Szrj void
diagnostic_c_tests()170038fd1498Szrj diagnostic_c_tests ()
170138fd1498Szrj {
170238fd1498Szrj   test_print_escaped_string ();
170338fd1498Szrj   test_print_parseable_fixits_none ();
170438fd1498Szrj   test_print_parseable_fixits_insert ();
170538fd1498Szrj   test_print_parseable_fixits_remove ();
170638fd1498Szrj   test_print_parseable_fixits_replace ();
170738fd1498Szrj   test_diagnostic_get_location_text ();
170838fd1498Szrj }
170938fd1498Szrj 
171038fd1498Szrj } // namespace selftest
171138fd1498Szrj 
171238fd1498Szrj #endif /* #if CHECKING_P */
1713