1/* Language-independent diagnostic subroutines for the GNU Compiler Collection
2 Copyright (C) 1999-2024 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21
22/* This file implements the language independent aspect of diagnostic
23 message module. */
24
25#include "config.h"
26#define INCLUDE_VECTOR
27#include "system.h"
28#include "coretypes.h"
29#include "version.h"
30#include "demangle.h"
31#include "intl.h"
32#include "backtrace.h"
33#include "diagnostic.h"
34#include "diagnostic-color.h"
35#include "diagnostic-url.h"
36#include "diagnostic-metadata.h"
37#include "diagnostic-path.h"
38#include "diagnostic-client-data-hooks.h"
39#include "diagnostic-diagram.h"
40#include "edit-context.h"
41#include "selftest.h"
42#include "selftest-diagnostic.h"
43#include "opts.h"
44#include "cpplib.h"
45#include "text-art/theme.h"
46#include "pretty-print-urlifier.h"
47
48#ifdef HAVE_TERMIOS_H
49# include <termios.h>
50#endif
51
52#ifdef GWINSZ_IN_SYS_IOCTL
53# include <sys/ioctl.h>
54#endif
55
56/* Disable warnings about quoting issues in the pp_xxx calls below
57 that (intentionally) don't follow GCC diagnostic conventions. */
58#if __GNUC__ >= 10
59# pragma GCC diagnostic push
60# pragma GCC diagnostic ignored "-Wformat-diag"
61#endif
62
63#define pedantic_warning_kind(DC) \
64 ((DC)->m_pedantic_errors ? DK_ERROR : DK_WARNING)
65#define permissive_error_kind(DC) ((DC)->m_permissive ? DK_WARNING : DK_ERROR)
66#define permissive_error_option(DC) ((DC)->m_opt_permissive)
67
68/* Prototypes. */
69static bool diagnostic_impl (rich_location *, const diagnostic_metadata *,
70 int, const char *,
71 va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(4,0);
72static bool diagnostic_n_impl (rich_location *, const diagnostic_metadata *,
73 int, unsigned HOST_WIDE_INT,
74 const char *, const char *, va_list *,
75 diagnostic_t) ATTRIBUTE_GCC_DIAG(6,0);
76
77static void real_abort (void) ATTRIBUTE_NORETURN;
78
79/* Name of program invoked, sans directories. */
80
81const char *progname;
82
83/* A diagnostic_context surrogate for stderr. */
84static diagnostic_context global_diagnostic_context;
85diagnostic_context *global_dc = &global_diagnostic_context;
86
87/* Return a malloc'd string containing MSG formatted a la printf. The
88 caller is responsible for freeing the memory. */
89char *
90build_message_string (const char *msg, ...)
91{
92 char *str;
93 va_list ap;
94
95 va_start (ap, msg);
96 str = xvasprintf (msg, ap);
97 va_end (ap);
98
99 return str;
100}
101
102/* Same as diagnostic_build_prefix, but only the source FILE is given. */
103char *
104file_name_as_prefix (diagnostic_context *context, const char *f)
105{
106 const char *locus_cs
107 = colorize_start (pp_show_color (context->printer), name: "locus");
108 const char *locus_ce = colorize_stop (pp_show_color (context->printer));
109 return build_message_string (msg: "%s%s:%s ", locus_cs, f, locus_ce);
110}
111
112
113
114/* Return the value of the getenv("COLUMNS") as an integer. If the
115 value is not set to a positive integer, use ioctl to get the
116 terminal width. If it fails, return INT_MAX. */
117int
118get_terminal_width (void)
119{
120 const char * s = getenv (name: "COLUMNS");
121 if (s != NULL) {
122 int n = atoi (nptr: s);
123 if (n > 0)
124 return n;
125 }
126
127#ifdef TIOCGWINSZ
128 struct winsize w;
129 w.ws_col = 0;
130 if (ioctl (fd: 0, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
131 return w.ws_col;
132#endif
133
134 return INT_MAX;
135}
136
137/* Set caret_max_width to value. */
138void
139diagnostic_set_caret_max_width (diagnostic_context *context, int value)
140{
141 /* One minus to account for the leading empty space. */
142 value = value ? value - 1
143 : (isatty (fileno (pp_buffer (context->printer)->stream))
144 ? get_terminal_width () - 1: INT_MAX);
145
146 if (value <= 0)
147 value = INT_MAX;
148
149 context->m_source_printing.max_width = value;
150}
151
152void
153diagnostic_option_classifier::init (int n_opts)
154{
155 m_n_opts = n_opts;
156 m_classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
157 for (int i = 0; i < n_opts; i++)
158 m_classify_diagnostic[i] = DK_UNSPECIFIED;
159 m_push_list = nullptr;
160 m_n_push = 0;
161}
162
163void
164diagnostic_option_classifier::fini ()
165{
166 XDELETEVEC (m_classify_diagnostic);
167 m_classify_diagnostic = nullptr;
168 free (ptr: m_push_list);
169 m_n_push = 0;
170}
171
172/* Save all diagnostic classifications in a stack. */
173
174void
175diagnostic_option_classifier::push ()
176{
177 m_push_list = (int *) xrealloc (m_push_list, (m_n_push + 1) * sizeof (int));
178 m_push_list[m_n_push ++] = m_n_classification_history;
179}
180
181/* Restore the topmost classification set off the stack. If the stack
182 is empty, revert to the state based on command line parameters. */
183
184void
185diagnostic_option_classifier::pop (location_t where)
186{
187 int jump_to;
188
189 if (m_n_push)
190 jump_to = m_push_list [-- m_n_push];
191 else
192 jump_to = 0;
193
194 const int i = m_n_classification_history;
195 m_classification_history =
196 (diagnostic_classification_change_t *) xrealloc (m_classification_history, (i + 1)
197 * sizeof (diagnostic_classification_change_t));
198 m_classification_history[i].location = where;
199 m_classification_history[i].option = jump_to;
200 m_classification_history[i].kind = DK_POP;
201 m_n_classification_history ++;
202}
203
204/* Initialize the diagnostic message outputting machinery. */
205
206void
207diagnostic_context::initialize (int n_opts)
208{
209 /* Allocate a basic pretty-printer. Clients will replace this a
210 much more elaborated pretty-printer if they wish. */
211 this->printer = XNEW (pretty_printer);
212 new (this->printer) pretty_printer ();
213
214 m_file_cache = new file_cache ();
215 memset (s: m_diagnostic_count, c: 0, n: sizeof m_diagnostic_count);
216 m_warning_as_error_requested = false;
217 m_n_opts = n_opts;
218 m_option_classifier.init (n_opts);
219 m_source_printing.enabled = false;
220 diagnostic_set_caret_max_width (context: this, pp_line_cutoff (this->printer));
221 for (int i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
222 m_source_printing.caret_chars[i] = '^';
223 m_show_cwe = false;
224 m_show_rules = false;
225 m_path_format = DPF_NONE;
226 m_show_path_depths = false;
227 m_show_option_requested = false;
228 m_abort_on_error = false;
229 m_show_column = false;
230 m_pedantic_errors = false;
231 m_permissive = false;
232 m_opt_permissive = 0;
233 m_fatal_errors = false;
234 m_inhibit_warnings = false;
235 m_warn_system_headers = false;
236 m_max_errors = 0;
237 m_internal_error = nullptr;
238 m_text_callbacks.m_begin_diagnostic = default_diagnostic_starter;
239 m_text_callbacks.m_start_span = default_diagnostic_start_span_fn;
240 m_text_callbacks.m_end_diagnostic = default_diagnostic_finalizer;
241 m_option_callbacks.m_option_enabled_cb = nullptr;
242 m_option_callbacks.m_option_state = nullptr;
243 m_option_callbacks.m_make_option_name_cb = nullptr;
244 m_option_callbacks.m_make_option_url_cb = nullptr;
245 m_urlifier = nullptr;
246 m_last_location = UNKNOWN_LOCATION;
247 m_last_module = nullptr;
248 m_client_aux_data = nullptr;
249 m_lock = 0;
250 m_inhibit_notes_p = false;
251 m_source_printing.colorize_source_p = false;
252 m_source_printing.show_labels_p = false;
253 m_source_printing.show_line_numbers_p = false;
254 m_source_printing.min_margin_width = 0;
255 m_source_printing.show_ruler_p = false;
256 m_report_bug = false;
257 m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_none;
258 if (const char *var = getenv (name: "GCC_EXTRA_DIAGNOSTIC_OUTPUT"))
259 {
260 if (!strcmp (s1: var, s2: "fixits-v1"))
261 m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1;
262 else if (!strcmp (s1: var, s2: "fixits-v2"))
263 m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2;
264 /* Silently ignore unrecognized values. */
265 }
266 m_column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
267 m_column_origin = 1;
268 m_tabstop = 8;
269 m_escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
270 m_edit_context_ptr = nullptr;
271 m_diagnostic_groups.m_nesting_depth = 0;
272 m_diagnostic_groups.m_emission_count = 0;
273 m_output_format = new diagnostic_text_output_format (*this);
274 m_set_locations_cb = nullptr;
275 m_ice_handler_cb = nullptr;
276 m_includes_seen = nullptr;
277 m_client_data_hooks = nullptr;
278 m_diagrams.m_theme = nullptr;
279
280 enum diagnostic_text_art_charset text_art_charset
281 = DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI;
282 if (const char *lang = getenv (name: "LANG"))
283 {
284 /* For LANG=C, don't assume the terminal supports anything
285 other than ASCII. */
286 if (!strcmp (s1: lang, s2: "C"))
287 text_art_charset = DIAGNOSTICS_TEXT_ART_CHARSET_ASCII;
288 }
289 set_text_art_charset (text_art_charset);
290}
291
292/* Maybe initialize the color support. We require clients to do this
293 explicitly, since most clients don't want color. When called
294 without a VALUE, it initializes with DIAGNOSTICS_COLOR_DEFAULT. */
295
296void
297diagnostic_context::color_init (int value)
298{
299 /* value == -1 is the default value. */
300 if (value < 0)
301 {
302 /* If DIAGNOSTICS_COLOR_DEFAULT is -1, default to
303 -fdiagnostics-color=auto if GCC_COLORS is in the environment,
304 otherwise default to -fdiagnostics-color=never, for other
305 values default to that
306 -fdiagnostics-color={never,auto,always}. */
307 if (DIAGNOSTICS_COLOR_DEFAULT == -1)
308 {
309 if (!getenv (name: "GCC_COLORS"))
310 return;
311 value = DIAGNOSTICS_COLOR_AUTO;
312 }
313 else
314 value = DIAGNOSTICS_COLOR_DEFAULT;
315 }
316 pp_show_color (this->printer)
317 = colorize_init ((diagnostic_color_rule_t) value);
318}
319
320/* Initialize URL support within this context based on VALUE,
321 handling "auto". */
322
323void
324diagnostic_context::urls_init (int value)
325{
326 /* value == -1 is the default value. */
327 if (value < 0)
328 {
329 /* If DIAGNOSTICS_URLS_DEFAULT is -1, default to
330 -fdiagnostics-urls=auto if GCC_URLS or TERM_URLS is in the
331 environment, otherwise default to -fdiagnostics-urls=never,
332 for other values default to that
333 -fdiagnostics-urls={never,auto,always}. */
334 if (DIAGNOSTICS_URLS_DEFAULT == -1)
335 {
336 if (!getenv (name: "GCC_URLS") && !getenv (name: "TERM_URLS"))
337 return;
338 value = DIAGNOSTICS_URL_AUTO;
339 }
340 else
341 value = DIAGNOSTICS_URLS_DEFAULT;
342 }
343
344 this->printer->url_format
345 = determine_url_format ((diagnostic_url_rule_t) value);
346}
347
348/* Create the file_cache, if not already created, and tell it how to
349 translate files on input. */
350void
351diagnostic_context::
352initialize_input_context (diagnostic_input_charset_callback ccb,
353 bool should_skip_bom)
354{
355 m_file_cache->initialize_input_context (ccb, should_skip_bom);
356}
357
358/* Do any cleaning up required after the last diagnostic is emitted. */
359
360void
361diagnostic_context::finish ()
362{
363 delete m_output_format;
364 m_output_format= nullptr;
365
366 if (m_diagrams.m_theme)
367 {
368 delete m_diagrams.m_theme;
369 m_diagrams.m_theme = nullptr;
370 }
371
372 delete m_file_cache;
373 m_file_cache = nullptr;
374
375 m_option_classifier.fini ();
376
377 /* diagnostic_context::initialize allocates this->printer using XNEW
378 and placement-new. */
379 this->printer->~pretty_printer ();
380 XDELETE (this->printer);
381 this->printer = nullptr;
382
383 if (m_edit_context_ptr)
384 {
385 delete m_edit_context_ptr;
386 m_edit_context_ptr = nullptr;
387 }
388
389 if (m_includes_seen)
390 {
391 delete m_includes_seen;
392 m_includes_seen = nullptr;
393 }
394
395 if (m_client_data_hooks)
396 {
397 delete m_client_data_hooks;
398 m_client_data_hooks = nullptr;
399 }
400
401 delete m_urlifier;
402 m_urlifier = nullptr;
403}
404
405void
406diagnostic_context::set_output_format (diagnostic_output_format *output_format)
407{
408 /* Ideally we'd use a std::unique_ptr here. */
409 delete m_output_format;
410 m_output_format = output_format;
411}
412
413void
414diagnostic_context::set_client_data_hooks (diagnostic_client_data_hooks *hooks)
415{
416 /* Ideally we'd use a std::unique_ptr here. */
417 delete m_client_data_hooks;
418 m_client_data_hooks = hooks;
419}
420
421void
422diagnostic_context::
423set_option_hooks (diagnostic_option_enabled_cb option_enabled_cb,
424 void *option_state,
425 diagnostic_make_option_name_cb make_option_name_cb,
426 diagnostic_make_option_url_cb make_option_url_cb,
427 unsigned lang_mask)
428{
429 m_option_callbacks.m_option_enabled_cb = option_enabled_cb;
430 m_option_callbacks.m_option_state = option_state;
431 m_option_callbacks.m_make_option_name_cb = make_option_name_cb;
432 m_option_callbacks.m_make_option_url_cb = make_option_url_cb;
433 m_option_callbacks.m_lang_mask = lang_mask;
434}
435
436void
437diagnostic_context::set_urlifier (urlifier *urlifier)
438{
439 /* Ideally we'd use a std::unique_ptr here. */
440 delete m_urlifier;
441 m_urlifier = urlifier;
442}
443
444void
445diagnostic_context::create_edit_context ()
446{
447 delete m_edit_context_ptr;
448 gcc_assert (m_file_cache);
449 m_edit_context_ptr = new edit_context (*m_file_cache);
450}
451
452/* Initialize DIAGNOSTIC, where the message MSG has already been
453 translated. */
454void
455diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
456 va_list *args, rich_location *richloc,
457 diagnostic_t kind)
458{
459 gcc_assert (richloc);
460 diagnostic->message.m_err_no = errno;
461 diagnostic->message.m_args_ptr = args;
462 diagnostic->message.m_format_spec = msg;
463 diagnostic->message.m_richloc = richloc;
464 diagnostic->richloc = richloc;
465 diagnostic->metadata = NULL;
466 diagnostic->kind = kind;
467 diagnostic->option_index = 0;
468}
469
470/* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
471 translated. */
472void
473diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
474 va_list *args, rich_location *richloc,
475 diagnostic_t kind)
476{
477 gcc_assert (richloc);
478 diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
479}
480
481static const char *const diagnostic_kind_color[] = {
482#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
483#include "diagnostic.def"
484#undef DEFINE_DIAGNOSTIC_KIND
485 NULL
486};
487
488/* Get a color name for diagnostics of type KIND
489 Result could be NULL. */
490
491const char *
492diagnostic_get_color_for_kind (diagnostic_t kind)
493{
494 return diagnostic_kind_color[kind];
495}
496
497/* Given an expanded_location, convert the column (which is in 1-based bytes)
498 to the requested units, without converting the origin.
499 Return -1 if the column is invalid (<= 0). */
500
501static int
502convert_column_unit (file_cache &fc,
503 enum diagnostics_column_unit column_unit,
504 int tabstop,
505 expanded_location s)
506{
507 if (s.column <= 0)
508 return -1;
509
510 switch (column_unit)
511 {
512 default:
513 gcc_unreachable ();
514
515 case DIAGNOSTICS_COLUMN_UNIT_DISPLAY:
516 {
517 cpp_char_column_policy policy (tabstop, cpp_wcwidth);
518 return location_compute_display_column (fc, exploc: s, policy);
519 }
520
521 case DIAGNOSTICS_COLUMN_UNIT_BYTE:
522 return s.column;
523 }
524}
525
526/* Given an expanded_location, convert the column (which is in 1-based bytes)
527 to the requested units and origin. Return -1 if the column is
528 invalid (<= 0). */
529int
530diagnostic_context::converted_column (expanded_location s) const
531{
532 int one_based_col = convert_column_unit (fc&: get_file_cache (),
533 column_unit: m_column_unit, tabstop: m_tabstop, s);
534 if (one_based_col <= 0)
535 return -1;
536 return one_based_col + (m_column_origin - 1);
537}
538
539/* Return a formatted line and column ':%line:%column'. Elided if
540 line == 0 or col < 0. (A column of 0 may be valid due to the
541 -fdiagnostics-column-origin option.)
542 The result is a statically allocated buffer. */
543
544static const char *
545maybe_line_and_column (int line, int col)
546{
547 static char result[32];
548
549 if (line)
550 {
551 size_t l
552 = snprintf (s: result, maxlen: sizeof (result),
553 format: col >= 0 ? ":%d:%d" : ":%d", line, col);
554 gcc_checking_assert (l < sizeof (result));
555 }
556 else
557 result[0] = 0;
558 return result;
559}
560
561/* Return a string describing a location e.g. "foo.c:42:10". */
562
563label_text
564diagnostic_context::get_location_text (const expanded_location &s) const
565{
566 pretty_printer *pp = this->printer;
567 const char *locus_cs = colorize_start (pp_show_color (pp), name: "locus");
568 const char *locus_ce = colorize_stop (pp_show_color (pp));
569 const char *file = s.file ? s.file : progname;
570 int line = 0;
571 int col = -1;
572 if (strcmp (s1: file, s2: special_fname_builtin ()))
573 {
574 line = s.line;
575 if (m_show_column)
576 col = this->converted_column (s);
577 }
578
579 const char *line_col = maybe_line_and_column (line, col);
580 return label_text::take (buffer: build_message_string (msg: "%s%s%s:%s", locus_cs, file,
581 line_col, locus_ce));
582}
583
584static const char *const diagnostic_kind_text[] = {
585#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
586#include "diagnostic.def"
587#undef DEFINE_DIAGNOSTIC_KIND
588 "must-not-happen"
589};
590
591/* Return a malloc'd string describing a location and the severity of the
592 diagnostic, e.g. "foo.c:42:10: error: ". The caller is responsible for
593 freeing the memory. */
594char *
595diagnostic_build_prefix (diagnostic_context *context,
596 const diagnostic_info *diagnostic)
597{
598 gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
599
600 const char *text = _(diagnostic_kind_text[diagnostic->kind]);
601 const char *text_cs = "", *text_ce = "";
602 pretty_printer *pp = context->printer;
603
604 if (diagnostic_kind_color[diagnostic->kind])
605 {
606 text_cs = colorize_start (pp_show_color (pp),
607 name: diagnostic_kind_color[diagnostic->kind]);
608 text_ce = colorize_stop (pp_show_color (pp));
609 }
610
611 const expanded_location s = diagnostic_expand_location (diagnostic);
612 label_text location_text = context->get_location_text (s);
613
614 char *result = build_message_string (msg: "%s %s%s%s", location_text.get (),
615 text_cs, text, text_ce);
616 return result;
617}
618
619/* Functions at which to stop the backtrace print. It's not
620 particularly helpful to print the callers of these functions. */
621
622static const char * const bt_stop[] =
623{
624 "main",
625 "toplev::main",
626 "execute_one_pass",
627 "compile_file",
628};
629
630/* A callback function passed to the backtrace_full function. */
631
632static int
633bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
634 const char *function)
635{
636 int *pcount = (int *) data;
637
638 /* If we don't have any useful information, don't print
639 anything. */
640 if (filename == NULL && function == NULL)
641 return 0;
642
643 /* Skip functions in diagnostic.cc. */
644 if (*pcount == 0
645 && filename != NULL
646 && strcmp (s1: lbasename (filename), s2: "diagnostic.cc") == 0)
647 return 0;
648
649 /* Print up to 20 functions. We could make this a --param, but
650 since this is only for debugging just use a constant for now. */
651 if (*pcount >= 20)
652 {
653 /* Returning a non-zero value stops the backtrace. */
654 return 1;
655 }
656 ++*pcount;
657
658 char *alc = NULL;
659 if (function != NULL)
660 {
661 char *str = cplus_demangle_v3 (mangled: function,
662 options: (DMGL_VERBOSE | DMGL_ANSI
663 | DMGL_GNU_V3 | DMGL_PARAMS));
664 if (str != NULL)
665 {
666 alc = str;
667 function = str;
668 }
669
670 for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
671 {
672 size_t len = strlen (s: bt_stop[i]);
673 if (strncmp (s1: function, s2: bt_stop[i], n: len) == 0
674 && (function[len] == '\0' || function[len] == '('))
675 {
676 if (alc != NULL)
677 free (ptr: alc);
678 /* Returning a non-zero value stops the backtrace. */
679 return 1;
680 }
681 }
682 }
683
684 fprintf (stderr, format: "0x%lx %s\n\t%s:%d\n",
685 (unsigned long) pc,
686 function == NULL ? "???" : function,
687 filename == NULL ? "???" : filename,
688 lineno);
689
690 if (alc != NULL)
691 free (ptr: alc);
692
693 return 0;
694}
695
696/* A callback function passed to the backtrace_full function. This is
697 called if backtrace_full has an error. */
698
699static void
700bt_err_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
701{
702 if (errnum < 0)
703 {
704 /* This means that no debug info was available. Just quietly
705 skip printing backtrace info. */
706 return;
707 }
708 fprintf (stderr, format: "%s%s%s\n", msg, errnum == 0 ? "" : ": ",
709 errnum == 0 ? "" : xstrerror (errnum));
710}
711
712/* Check if we've met the maximum error limit, and if so fatally exit
713 with a message.
714 FLUSH indicates whether a diagnostic_context::finish call is needed. */
715
716void
717diagnostic_context::check_max_errors (bool flush)
718{
719 if (!m_max_errors)
720 return;
721
722 int count = (m_diagnostic_count[DK_ERROR]
723 + m_diagnostic_count[DK_SORRY]
724 + m_diagnostic_count[DK_WERROR]);
725
726 if (count >= m_max_errors)
727 {
728 fnotice (stderr,
729 "compilation terminated due to -fmax-errors=%u.\n",
730 m_max_errors);
731 if (flush)
732 finish ();
733 exit (FATAL_EXIT_CODE);
734 }
735}
736
737/* Take any action which is expected to happen after the diagnostic
738 is written out. This function does not always return. */
739void
740diagnostic_context::action_after_output (diagnostic_t diag_kind)
741{
742 switch (diag_kind)
743 {
744 case DK_DEBUG:
745 case DK_NOTE:
746 case DK_ANACHRONISM:
747 case DK_WARNING:
748 break;
749
750 case DK_ERROR:
751 case DK_SORRY:
752 if (m_abort_on_error)
753 real_abort ();
754 if (m_fatal_errors)
755 {
756 fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n");
757 finish ();
758 exit (FATAL_EXIT_CODE);
759 }
760 break;
761
762 case DK_ICE:
763 case DK_ICE_NOBT:
764 {
765 /* Optional callback for attempting to handle ICEs gracefully. */
766 if (void (*ice_handler_cb) (diagnostic_context *) = m_ice_handler_cb)
767 {
768 /* Clear the callback, to avoid potentially re-entering
769 the routine if there's a crash within the handler. */
770 m_ice_handler_cb = NULL;
771 ice_handler_cb (this);
772 }
773 /* The context might have had diagnostic_finish called on
774 it at this point. */
775
776 struct backtrace_state *state = NULL;
777 if (diag_kind == DK_ICE)
778 state = backtrace_create_state (NULL, threaded: 0, error_callback: bt_err_callback, NULL);
779 int count = 0;
780 if (state != NULL)
781 backtrace_full (state, skip: 2, callback: bt_callback, error_callback: bt_err_callback,
782 data: (void *) &count);
783
784 if (m_abort_on_error)
785 real_abort ();
786
787 if (m_report_bug)
788 fnotice (stderr, "Please submit a full bug report, "
789 "with preprocessed source.\n");
790 else
791 fnotice (stderr, "Please submit a full bug report, "
792 "with preprocessed source (by using -freport-bug).\n");
793
794 if (count > 0)
795 fnotice (stderr, "Please include the complete backtrace "
796 "with any bug report.\n");
797 fnotice (stderr, "See %s for instructions.\n", bug_report_url);
798
799 exit (ICE_EXIT_CODE);
800 }
801
802 case DK_FATAL:
803 if (m_abort_on_error)
804 real_abort ();
805 fnotice (stderr, "compilation terminated.\n");
806 finish ();
807 exit (FATAL_EXIT_CODE);
808
809 default:
810 gcc_unreachable ();
811 }
812}
813
814/* Only dump the "In file included from..." stack once for each file. */
815
816bool
817diagnostic_context::includes_seen_p (const line_map_ordinary *map)
818{
819 /* No include path for main. */
820 if (MAIN_FILE_P (ord_map: map))
821 return true;
822
823 /* Always identify C++ modules, at least for now. */
824 auto probe = map;
825 if (linemap_check_ordinary (map)->reason == LC_RENAME)
826 /* The module source file shows up as LC_RENAME inside LC_MODULE. */
827 probe = linemap_included_from_linemap (set: line_table, map);
828 if (MAP_MODULE_P (map: probe))
829 return false;
830
831 if (!m_includes_seen)
832 m_includes_seen = new hash_set<location_t, false, location_hash>;
833
834 /* Hash the location of the #include directive to better handle files
835 that are included multiple times with different macros defined. */
836 return m_includes_seen->add (k: linemap_included_from (ord_map: map));
837}
838
839void
840diagnostic_context::report_current_module (location_t where)
841{
842 const line_map_ordinary *map = NULL;
843
844 if (pp_needs_newline (this->printer))
845 {
846 pp_newline (this->printer);
847 pp_needs_newline (this->printer) = false;
848 }
849
850 if (where <= BUILTINS_LOCATION)
851 return;
852
853 linemap_resolve_location (line_table, loc: where,
854 lrk: LRK_MACRO_DEFINITION_LOCATION,
855 loc_map: &map);
856
857 if (map && m_last_module != map)
858 {
859 m_last_module = map;
860 if (!includes_seen_p (map))
861 {
862 bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
863 expanded_location s = {};
864 do
865 {
866 where = linemap_included_from (ord_map: map);
867 map = linemap_included_from_linemap (set: line_table, map);
868 bool is_module = MAP_MODULE_P (map);
869 s.file = LINEMAP_FILE (ord_map: map);
870 s.line = SOURCE_LINE (ord_map: map, loc: where);
871 int col = -1;
872 if (first && m_show_column)
873 {
874 s.column = SOURCE_COLUMN (ord_map: map, loc: where);
875 col = converted_column (s);
876 }
877 const char *line_col = maybe_line_and_column (line: s.line, col);
878 static const char *const msgs[] =
879 {
880 NULL,
881 N_(" from"),
882 N_("In file included from"), /* 2 */
883 N_(" included from"),
884 N_("In module"), /* 4 */
885 N_("of module"),
886 N_("In module imported at"), /* 6 */
887 N_("imported at"),
888 };
889
890 unsigned index = (was_module ? 6 : is_module ? 4
891 : need_inc ? 2 : 0) + !first;
892
893 pp_verbatim (this->printer, "%s%s %r%s%s%R",
894 first ? "" : was_module ? ", " : ",\n",
895 _(msgs[index]),
896 "locus", s.file, line_col);
897 first = false, need_inc = was_module, was_module = is_module;
898 }
899 while (!includes_seen_p (map));
900 pp_verbatim (this->printer, ":");
901 pp_newline (this->printer);
902 }
903 }
904}
905
906/* If DIAGNOSTIC has a diagnostic_path and this context supports
907 printing paths, print the path. */
908
909void
910diagnostic_context::show_any_path (const diagnostic_info &diagnostic)
911{
912 const diagnostic_path *path = diagnostic.richloc->get_path ();
913 if (!path)
914 return;
915
916 if (m_print_path)
917 m_print_path (this, path);
918}
919
920/* class diagnostic_event. */
921
922/* struct diagnostic_event::meaning. */
923
924void
925diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const
926{
927 bool need_comma = false;
928 pp_character (pp, '{');
929 if (const char *verb_str = maybe_get_verb_str (m_verb))
930 {
931 pp_printf (pp, "verb: %qs", verb_str);
932 need_comma = true;
933 }
934 if (const char *noun_str = maybe_get_noun_str (m_noun))
935 {
936 if (need_comma)
937 pp_string (pp, ", ");
938 pp_printf (pp, "noun: %qs", noun_str);
939 need_comma = true;
940 }
941 if (const char *property_str = maybe_get_property_str (m_property))
942 {
943 if (need_comma)
944 pp_string (pp, ", ");
945 pp_printf (pp, "property: %qs", property_str);
946 need_comma = true;
947 }
948 pp_character (pp, '}');
949}
950
951/* Get a string (or NULL) for V suitable for use within a SARIF
952 threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
953
954const char *
955diagnostic_event::meaning::maybe_get_verb_str (enum verb v)
956{
957 switch (v)
958 {
959 default:
960 gcc_unreachable ();
961 case VERB_unknown:
962 return NULL;
963 case VERB_acquire:
964 return "acquire";
965 case VERB_release:
966 return "release";
967 case VERB_enter:
968 return "enter";
969 case VERB_exit:
970 return "exit";
971 case VERB_call:
972 return "call";
973 case VERB_return:
974 return "return";
975 case VERB_branch:
976 return "branch";
977 case VERB_danger:
978 return "danger";
979 }
980}
981
982/* Get a string (or NULL) for N suitable for use within a SARIF
983 threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
984
985const char *
986diagnostic_event::meaning::maybe_get_noun_str (enum noun n)
987{
988 switch (n)
989 {
990 default:
991 gcc_unreachable ();
992 case NOUN_unknown:
993 return NULL;
994 case NOUN_taint:
995 return "taint";
996 case NOUN_sensitive:
997 return "sensitive";
998 case NOUN_function:
999 return "function";
1000 case NOUN_lock:
1001 return "lock";
1002 case NOUN_memory:
1003 return "memory";
1004 case NOUN_resource:
1005 return "resource";
1006 }
1007}
1008
1009/* Get a string (or NULL) for P suitable for use within a SARIF
1010 threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
1011
1012const char *
1013diagnostic_event::meaning::maybe_get_property_str (enum property p)
1014{
1015 switch (p)
1016 {
1017 default:
1018 gcc_unreachable ();
1019 case PROPERTY_unknown:
1020 return NULL;
1021 case PROPERTY_true:
1022 return "true";
1023 case PROPERTY_false:
1024 return "false";
1025 }
1026}
1027
1028/* class diagnostic_path. */
1029
1030/* Subroutint of diagnostic_path::interprocedural_p.
1031 Look for the first event in this path that is within a function
1032 i.e. has a non-NULL fndecl, and a non-zero stack depth.
1033 If found, write its index to *OUT_IDX and return true.
1034 Otherwise return false. */
1035
1036bool
1037diagnostic_path::get_first_event_in_a_function (unsigned *out_idx) const
1038{
1039 const unsigned num = num_events ();
1040 for (unsigned i = 0; i < num; i++)
1041 {
1042 if (!(get_event (idx: i).get_fndecl () == NULL
1043 && get_event (idx: i).get_stack_depth () == 0))
1044 {
1045 *out_idx = i;
1046 return true;
1047 }
1048 }
1049 return false;
1050}
1051
1052/* Return true if the events in this path involve more than one
1053 function, or false if it is purely intraprocedural. */
1054
1055bool
1056diagnostic_path::interprocedural_p () const
1057{
1058 /* Ignore leading events that are outside of any function. */
1059 unsigned first_fn_event_idx;
1060 if (!get_first_event_in_a_function (out_idx: &first_fn_event_idx))
1061 return false;
1062
1063 const diagnostic_event &first_fn_event = get_event (idx: first_fn_event_idx);
1064 tree first_fndecl = first_fn_event.get_fndecl ();
1065 int first_fn_stack_depth = first_fn_event.get_stack_depth ();
1066
1067 const unsigned num = num_events ();
1068 for (unsigned i = first_fn_event_idx + 1; i < num; i++)
1069 {
1070 if (get_event (idx: i).get_fndecl () != first_fndecl)
1071 return true;
1072 if (get_event (idx: i).get_stack_depth () != first_fn_stack_depth)
1073 return true;
1074 }
1075 return false;
1076}
1077
1078void
1079default_diagnostic_starter (diagnostic_context *context,
1080 const diagnostic_info *diagnostic)
1081{
1082 diagnostic_report_current_module (context, where: diagnostic_location (diagnostic));
1083 pp_set_prefix (context->printer, diagnostic_build_prefix (context,
1084 diagnostic));
1085}
1086
1087void
1088default_diagnostic_start_span_fn (diagnostic_context *context,
1089 expanded_location exploc)
1090{
1091 label_text text = context->get_location_text (s: exploc);
1092 pp_string (context->printer, text.get ());
1093 pp_newline (context->printer);
1094}
1095
1096void
1097default_diagnostic_finalizer (diagnostic_context *context,
1098 const diagnostic_info *diagnostic,
1099 diagnostic_t)
1100{
1101 char *saved_prefix = pp_take_prefix (context->printer);
1102 pp_set_prefix (context->printer, NULL);
1103 pp_newline (context->printer);
1104 diagnostic_show_locus (context, richloc: diagnostic->richloc, diagnostic_kind: diagnostic->kind);
1105 pp_set_prefix (context->printer, saved_prefix);
1106 pp_flush (context->printer);
1107}
1108
1109/* Interface to specify diagnostic kind overrides. Returns the
1110 previous setting, or DK_UNSPECIFIED if the parameters are out of
1111 range. If OPTION_INDEX is zero, the new setting is for all the
1112 diagnostics. */
1113diagnostic_t
1114diagnostic_option_classifier::
1115classify_diagnostic (const diagnostic_context *context,
1116 int option_index,
1117 diagnostic_t new_kind,
1118 location_t where)
1119{
1120 diagnostic_t old_kind;
1121
1122 if (option_index < 0
1123 || option_index >= m_n_opts
1124 || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
1125 return DK_UNSPECIFIED;
1126
1127 old_kind = m_classify_diagnostic[option_index];
1128
1129 /* Handle pragmas separately, since we need to keep track of *where*
1130 the pragmas were. */
1131 if (where != UNKNOWN_LOCATION)
1132 {
1133 int i;
1134
1135 /* Record the command-line status, so we can reset it back on DK_POP. */
1136 if (old_kind == DK_UNSPECIFIED)
1137 {
1138 old_kind = !context->option_enabled_p (option_index)
1139 ? DK_IGNORED : DK_ANY;
1140 m_classify_diagnostic[option_index] = old_kind;
1141 }
1142
1143 for (i = m_n_classification_history - 1; i >= 0; i --)
1144 if (m_classification_history[i].option == option_index)
1145 {
1146 old_kind = m_classification_history[i].kind;
1147 break;
1148 }
1149
1150 i = m_n_classification_history;
1151 m_classification_history =
1152 (diagnostic_classification_change_t *) xrealloc (m_classification_history, (i + 1)
1153 * sizeof (diagnostic_classification_change_t));
1154 m_classification_history[i].location = where;
1155 m_classification_history[i].option = option_index;
1156 m_classification_history[i].kind = new_kind;
1157 m_n_classification_history ++;
1158 }
1159 else
1160 m_classify_diagnostic[option_index] = new_kind;
1161
1162 return old_kind;
1163}
1164
1165/* Helper function for print_parseable_fixits. Print TEXT to PP, obeying the
1166 escaping rules for -fdiagnostics-parseable-fixits. */
1167
1168static void
1169print_escaped_string (pretty_printer *pp, const char *text)
1170{
1171 gcc_assert (pp);
1172 gcc_assert (text);
1173
1174 pp_character (pp, '"');
1175 for (const char *ch = text; *ch; ch++)
1176 {
1177 switch (*ch)
1178 {
1179 case '\\':
1180 /* Escape backslash as two backslashes. */
1181 pp_string (pp, "\\\\");
1182 break;
1183 case '\t':
1184 /* Escape tab as "\t". */
1185 pp_string (pp, "\\t");
1186 break;
1187 case '\n':
1188 /* Escape newline as "\n". */
1189 pp_string (pp, "\\n");
1190 break;
1191 case '"':
1192 /* Escape doublequotes as \". */
1193 pp_string (pp, "\\\"");
1194 break;
1195 default:
1196 if (ISPRINT (*ch))
1197 pp_character (pp, *ch);
1198 else
1199 /* Use octal for non-printable chars. */
1200 {
1201 unsigned char c = (*ch & 0xff);
1202 pp_printf (pp, "\\%o%o%o", (c / 64), (c / 8) & 007, c & 007);
1203 }
1204 break;
1205 }
1206 }
1207 pp_character (pp, '"');
1208}
1209
1210/* Implementation of -fdiagnostics-parseable-fixits and
1211 GCC_EXTRA_DIAGNOSTIC_OUTPUT.
1212 Print a machine-parseable version of all fixits in RICHLOC to PP,
1213 using COLUMN_UNIT to express columns.
1214 Use TABSTOP when handling DIAGNOSTICS_COLUMN_UNIT_DISPLAY. */
1215
1216static void
1217print_parseable_fixits (file_cache &fc,
1218 pretty_printer *pp, rich_location *richloc,
1219 enum diagnostics_column_unit column_unit,
1220 int tabstop)
1221{
1222 gcc_assert (pp);
1223 gcc_assert (richloc);
1224
1225 char *saved_prefix = pp_take_prefix (pp);
1226 pp_set_prefix (pp, NULL);
1227
1228 for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++)
1229 {
1230 const fixit_hint *hint = richloc->get_fixit_hint (idx: i);
1231 location_t start_loc = hint->get_start_loc ();
1232 expanded_location start_exploc = expand_location (start_loc);
1233 pp_string (pp, "fix-it:");
1234 print_escaped_string (pp, text: start_exploc.file);
1235 /* For compatibility with clang, print as a half-open range. */
1236 location_t next_loc = hint->get_next_loc ();
1237 expanded_location next_exploc = expand_location (next_loc);
1238 int start_col
1239 = convert_column_unit (fc, column_unit, tabstop, s: start_exploc);
1240 int next_col
1241 = convert_column_unit (fc, column_unit, tabstop, s: next_exploc);
1242 pp_printf (pp, ":{%i:%i-%i:%i}:",
1243 start_exploc.line, start_col,
1244 next_exploc.line, next_col);
1245 print_escaped_string (pp, text: hint->get_string ());
1246 pp_newline (pp);
1247 }
1248
1249 pp_set_prefix (pp, saved_prefix);
1250}
1251
1252/* Update the inlining info in this context for a DIAGNOSTIC. */
1253
1254void
1255diagnostic_context::get_any_inlining_info (diagnostic_info *diagnostic)
1256{
1257 auto &ilocs = diagnostic->m_iinfo.m_ilocs;
1258
1259 if (m_set_locations_cb)
1260 /* Retrieve the locations into which the expression about to be
1261 diagnosed has been inlined, including those of all the callers
1262 all the way down the inlining stack. */
1263 m_set_locations_cb (this, diagnostic);
1264 else
1265 {
1266 /* When there's no callback use just the one location provided
1267 by the caller of the diagnostic function. */
1268 location_t loc = diagnostic_location (diagnostic);
1269 ilocs.safe_push (obj: loc);
1270 diagnostic->m_iinfo.m_allsyslocs = in_system_header_at (loc);
1271 }
1272}
1273
1274/* Update the kind of DIAGNOSTIC based on its location(s), including
1275 any of those in its inlining stack, relative to any
1276 #pragma GCC diagnostic
1277 directives recorded within this object.
1278
1279 Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
1280 otherwise. */
1281
1282diagnostic_t
1283diagnostic_option_classifier::
1284update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
1285{
1286 if (m_n_classification_history <= 0)
1287 return DK_UNSPECIFIED;
1288
1289 /* Iterate over the locations, checking the diagnostic disposition
1290 for the diagnostic at each. If it's explicitly set as opposed
1291 to unspecified, update the disposition for this instance of
1292 the diagnostic and return it. */
1293 for (location_t loc: diagnostic->m_iinfo.m_ilocs)
1294 {
1295 /* FIXME: Stupid search. Optimize later. */
1296 for (int i = m_n_classification_history - 1; i >= 0; i --)
1297 {
1298 const diagnostic_classification_change_t &hist
1299 = m_classification_history[i];
1300
1301 location_t pragloc = hist.location;
1302 if (!linemap_location_before_p (set: line_table, loc_a: pragloc, loc_b: loc))
1303 continue;
1304
1305 if (hist.kind == (int) DK_POP)
1306 {
1307 /* Move on to the next region. */
1308 i = hist.option;
1309 continue;
1310 }
1311
1312 int option = hist.option;
1313 /* The option 0 is for all the diagnostics. */
1314 if (option == 0 || option == diagnostic->option_index)
1315 {
1316 diagnostic_t kind = hist.kind;
1317 if (kind != DK_UNSPECIFIED)
1318 diagnostic->kind = kind;
1319 return kind;
1320 }
1321 }
1322 }
1323
1324 return DK_UNSPECIFIED;
1325}
1326
1327/* Generate a URL string describing CWE. The caller is responsible for
1328 freeing the string. */
1329
1330char *
1331get_cwe_url (int cwe)
1332{
1333 return xasprintf ("https://cwe.mitre.org/data/definitions/%i.html", cwe);
1334}
1335
1336/* If DIAGNOSTIC has a CWE identifier, print it.
1337
1338 For example, if the diagnostic metadata associates it with CWE-119,
1339 " [CWE-119]" will be printed, suitably colorized, and with a URL of a
1340 description of the security issue. */
1341
1342void
1343diagnostic_context::print_any_cwe (const diagnostic_info &diagnostic)
1344{
1345 if (diagnostic.metadata == NULL)
1346 return;
1347
1348 int cwe = diagnostic.metadata->get_cwe ();
1349 if (cwe)
1350 {
1351 pretty_printer * const pp = this->printer;
1352 char *saved_prefix = pp_take_prefix (pp);
1353 pp_string (pp, " [");
1354 pp_string (pp, colorize_start (pp_show_color (pp),
1355 name: diagnostic_kind_color[diagnostic.kind]));
1356 if (pp->url_format != URL_FORMAT_NONE)
1357 {
1358 char *cwe_url = get_cwe_url (cwe);
1359 pp_begin_url (pp, url: cwe_url);
1360 free (ptr: cwe_url);
1361 }
1362 pp_printf (pp, "CWE-%i", cwe);
1363 pp_set_prefix (pp, saved_prefix);
1364 if (pp->url_format != URL_FORMAT_NONE)
1365 pp_end_url (pp);
1366 pp_string (pp, colorize_stop (pp_show_color (pp)));
1367 pp_character (pp, ']');
1368 }
1369}
1370
1371/* If DIAGNOSTIC has any rules associated with it, print them.
1372
1373 For example, if the diagnostic metadata associates it with a rule
1374 named "STR34-C", then " [STR34-C]" will be printed, suitably colorized,
1375 with any URL provided by the rule. */
1376
1377void
1378diagnostic_context::print_any_rules (const diagnostic_info &diagnostic)
1379{
1380 if (diagnostic.metadata == NULL)
1381 return;
1382
1383 for (unsigned idx = 0; idx < diagnostic.metadata->get_num_rules (); idx++)
1384 {
1385 const diagnostic_metadata::rule &rule
1386 = diagnostic.metadata->get_rule (idx);
1387 if (char *desc = rule.make_description ())
1388 {
1389 pretty_printer * const pp = this->printer;
1390 char *saved_prefix = pp_take_prefix (pp);
1391 pp_string (pp, " [");
1392 pp_string (pp,
1393 colorize_start (pp_show_color (pp),
1394 name: diagnostic_kind_color[diagnostic.kind]));
1395 char *url = NULL;
1396 if (pp->url_format != URL_FORMAT_NONE)
1397 {
1398 url = rule.make_url ();
1399 if (url)
1400 pp_begin_url (pp, url);
1401 }
1402 pp_string (pp, desc);
1403 pp_set_prefix (pp, saved_prefix);
1404 if (pp->url_format != URL_FORMAT_NONE)
1405 if (url)
1406 pp_end_url (pp);
1407 free (ptr: url);
1408 pp_string (pp, colorize_stop (pp_show_color (pp)));
1409 pp_character (pp, ']');
1410 free (ptr: desc);
1411 }
1412 }
1413}
1414
1415/* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
1416 printer, e.g. " [-Werror=uninitialized]".
1417 Subroutine of diagnostic_context::report_diagnostic. */
1418
1419void
1420diagnostic_context::print_option_information (const diagnostic_info &diagnostic,
1421 diagnostic_t orig_diag_kind)
1422{
1423 if (char *option_text = make_option_name (option_index: diagnostic.option_index,
1424 orig_diag_kind, diag_kind: diagnostic.kind))
1425 {
1426 char *option_url = nullptr;
1427 if (this->printer->url_format != URL_FORMAT_NONE)
1428 option_url = make_option_url (option_index: diagnostic.option_index);
1429 pretty_printer * const pp = this->printer;
1430 pp_string (pp, " [");
1431 pp_string (pp, colorize_start (pp_show_color (pp),
1432 name: diagnostic_kind_color[diagnostic.kind]));
1433 if (option_url)
1434 pp_begin_url (pp, url: option_url);
1435 pp_string (pp, option_text);
1436 if (option_url)
1437 {
1438 pp_end_url (pp);
1439 free (ptr: option_url);
1440 }
1441 pp_string (pp, colorize_stop (pp_show_color (pp)));
1442 pp_character (pp, ']');
1443 free (ptr: option_text);
1444 }
1445}
1446
1447/* Returns whether a DIAGNOSTIC should be printed, and adjusts diagnostic->kind
1448 as appropriate for #pragma GCC diagnostic and -Werror=foo. */
1449
1450bool
1451diagnostic_context::diagnostic_enabled (diagnostic_info *diagnostic)
1452{
1453 /* Update the inlining stack for this diagnostic. */
1454 get_any_inlining_info (diagnostic);
1455
1456 /* Diagnostics with no option or -fpermissive are always enabled. */
1457 if (!diagnostic->option_index
1458 || diagnostic->option_index == permissive_error_option (this))
1459 return true;
1460
1461 /* This tests if the user provided the appropriate -Wfoo or
1462 -Wno-foo option. */
1463 if (!option_enabled_p (option_index: diagnostic->option_index))
1464 return false;
1465
1466 /* This tests for #pragma diagnostic changes. */
1467 diagnostic_t diag_class
1468 = m_option_classifier.update_effective_level_from_pragmas (diagnostic);
1469
1470 /* This tests if the user provided the appropriate -Werror=foo
1471 option. */
1472 if (diag_class == DK_UNSPECIFIED
1473 && !option_unspecified_p (opt: diagnostic->option_index))
1474 {
1475 const diagnostic_t new_kind
1476 = m_option_classifier.get_current_override (opt: diagnostic->option_index);
1477 if (new_kind != DK_ANY)
1478 /* DK_ANY means the diagnostic is not to be ignored, but we don't want
1479 to change it specifically to DK_ERROR or DK_WARNING; we want to
1480 preserve whatever the caller has specified. */
1481 diagnostic->kind = new_kind;
1482 }
1483
1484 /* This allows for future extensions, like temporarily disabling
1485 warnings for ranges of source code. */
1486 if (diagnostic->kind == DK_IGNORED)
1487 return false;
1488
1489 return true;
1490}
1491
1492/* Returns whether warning OPT is enabled at LOC. */
1493
1494bool
1495diagnostic_context::warning_enabled_at (location_t loc, int opt)
1496{
1497 if (!diagnostic_report_warnings_p (this, loc))
1498 return false;
1499
1500 rich_location richloc (line_table, loc);
1501 diagnostic_info diagnostic = {};
1502 diagnostic.option_index = opt;
1503 diagnostic.richloc = &richloc;
1504 diagnostic.message.m_richloc = &richloc;
1505 diagnostic.kind = DK_WARNING;
1506 return diagnostic_enabled (diagnostic: &diagnostic);
1507}
1508
1509/* Report a diagnostic message (an error or a warning) as specified by
1510 this diagnostic_context.
1511 front-end independent format specifiers are exactly those described
1512 in the documentation of output_format.
1513 Return true if a diagnostic was printed, false otherwise. */
1514
1515bool
1516diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
1517{
1518 diagnostic_t orig_diag_kind = diagnostic->kind;
1519
1520 gcc_assert (m_output_format);
1521
1522 /* Give preference to being able to inhibit warnings, before they
1523 get reclassified to something else. */
1524 bool was_warning = (diagnostic->kind == DK_WARNING
1525 || diagnostic->kind == DK_PEDWARN);
1526 if (was_warning && m_inhibit_warnings)
1527 return false;
1528
1529 if (diagnostic->kind == DK_PEDWARN)
1530 {
1531 diagnostic->kind = pedantic_warning_kind (this);
1532 /* We do this to avoid giving the message for -pedantic-errors. */
1533 orig_diag_kind = diagnostic->kind;
1534 }
1535
1536 if (diagnostic->kind == DK_NOTE && m_inhibit_notes_p)
1537 return false;
1538
1539 if (m_lock > 0)
1540 {
1541 /* If we're reporting an ICE in the middle of some other error,
1542 try to flush out the previous error, then let this one
1543 through. Don't do this more than once. */
1544 if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
1545 && m_lock == 1)
1546 pp_newline_and_flush (this->printer);
1547 else
1548 error_recursion ();
1549 }
1550
1551 /* If the user requested that warnings be treated as errors, so be
1552 it. Note that we do this before the next block so that
1553 individual warnings can be overridden back to warnings with
1554 -Wno-error=*. */
1555 if (m_warning_as_error_requested
1556 && diagnostic->kind == DK_WARNING)
1557 diagnostic->kind = DK_ERROR;
1558
1559 diagnostic->message.m_data = &diagnostic->x_data;
1560
1561 /* Check to see if the diagnostic is enabled at the location and
1562 not disabled by #pragma GCC diagnostic anywhere along the inlining
1563 stack. . */
1564 if (!diagnostic_enabled (diagnostic))
1565 return false;
1566
1567 if ((was_warning || diagnostic->kind == DK_WARNING)
1568 && ((!m_warn_system_headers
1569 && diagnostic->m_iinfo.m_allsyslocs)
1570 || m_inhibit_warnings))
1571 /* Bail if the warning is not to be reported because all locations in the
1572 inlining stack (if there is one) are in system headers. */
1573 return false;
1574
1575 if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
1576 diagnostic_check_max_errors (context: this);
1577
1578 m_lock++;
1579
1580 if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
1581 {
1582 /* When not checking, ICEs are converted to fatal errors when an
1583 error has already occurred. This is counteracted by
1584 abort_on_error. */
1585 if (!CHECKING_P
1586 && (m_diagnostic_count[DK_ERROR] > 0
1587 || m_diagnostic_count[DK_SORRY] > 0)
1588 && !m_abort_on_error)
1589 {
1590 expanded_location s
1591 = expand_location (diagnostic_location (diagnostic));
1592 fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
1593 s.file, s.line);
1594 exit (ICE_EXIT_CODE);
1595 }
1596 if (m_internal_error)
1597 (*m_internal_error) (this,
1598 diagnostic->message.m_format_spec,
1599 diagnostic->message.m_args_ptr);
1600 }
1601 if (diagnostic->kind == DK_ERROR && orig_diag_kind == DK_WARNING)
1602 ++m_diagnostic_count[DK_WERROR];
1603 else
1604 ++m_diagnostic_count[diagnostic->kind];
1605
1606 /* Is this the initial diagnostic within the stack of groups? */
1607 if (m_diagnostic_groups.m_emission_count == 0)
1608 m_output_format->on_begin_group ();
1609 m_diagnostic_groups.m_emission_count++;
1610
1611 pp_format (this->printer, &diagnostic->message, m_urlifier);
1612 m_output_format->on_begin_diagnostic (*diagnostic);
1613 pp_output_formatted_text (this->printer, m_urlifier);
1614 if (m_show_cwe)
1615 print_any_cwe (diagnostic: *diagnostic);
1616 if (m_show_rules)
1617 print_any_rules (diagnostic: *diagnostic);
1618 if (m_show_option_requested)
1619 print_option_information (diagnostic: *diagnostic, orig_diag_kind);
1620 m_output_format->on_end_diagnostic (*diagnostic, orig_diag_kind);
1621 switch (m_extra_output_kind)
1622 {
1623 default:
1624 break;
1625 case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1:
1626 print_parseable_fixits (fc&: get_file_cache (),
1627 pp: this->printer, richloc: diagnostic->richloc,
1628 column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE,
1629 tabstop: m_tabstop);
1630 pp_flush (this->printer);
1631 break;
1632 case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2:
1633 print_parseable_fixits (fc&: get_file_cache (),
1634 pp: this->printer, richloc: diagnostic->richloc,
1635 column_unit: DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
1636 tabstop: m_tabstop);
1637 pp_flush (this->printer);
1638 break;
1639 }
1640 diagnostic_action_after_output (context: this, diag_kind: diagnostic->kind);
1641 diagnostic->x_data = NULL;
1642
1643 if (m_edit_context_ptr)
1644 if (diagnostic->richloc->fixits_can_be_auto_applied_p ())
1645 m_edit_context_ptr->add_fixits (richloc: diagnostic->richloc);
1646
1647 m_lock--;
1648
1649 show_any_path (diagnostic: *diagnostic);
1650
1651 return true;
1652}
1653
1654/* Get the number of digits in the decimal representation of VALUE. */
1655
1656int
1657num_digits (int value)
1658{
1659 /* Perhaps simpler to use log10 for this, but doing it this way avoids
1660 using floating point. */
1661 gcc_assert (value >= 0);
1662
1663 if (value == 0)
1664 return 1;
1665
1666 int digits = 0;
1667 while (value > 0)
1668 {
1669 digits++;
1670 value /= 10;
1671 }
1672 return digits;
1673}
1674
1675/* Given a partial pathname as input, return another pathname that
1676 shares no directory elements with the pathname of __FILE__. This
1677 is used by fancy_abort() to print `internal compiler error in expr.cc'
1678 instead of `internal compiler error in ../../GCC/gcc/expr.cc'. */
1679
1680const char *
1681trim_filename (const char *name)
1682{
1683 static const char this_file[] = __FILE__;
1684 const char *p = name, *q = this_file;
1685
1686 /* First skip any "../" in each filename. This allows us to give a proper
1687 reference to a file in a subdirectory. */
1688 while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2]))
1689 p += 3;
1690
1691 while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2]))
1692 q += 3;
1693
1694 /* Now skip any parts the two filenames have in common. */
1695 while (*p == *q && *p != 0 && *q != 0)
1696 p++, q++;
1697
1698 /* Now go backwards until the previous directory separator. */
1699 while (p > name && !IS_DIR_SEPARATOR (p[-1]))
1700 p--;
1701
1702 return p;
1703}
1704
1705/* Standard error reporting routines in increasing order of severity.
1706 All of these take arguments like printf. */
1707
1708/* Text to be emitted verbatim to the error message stream; this
1709 produces no prefix and disables line-wrapping. Use rarely. */
1710void
1711verbatim (const char *gmsgid, ...)
1712{
1713 va_list ap;
1714
1715 va_start (ap, gmsgid);
1716 text_info text (_(gmsgid), &ap, errno);
1717 pp_format_verbatim (global_dc->printer, &text);
1718 pp_newline_and_flush (global_dc->printer);
1719 va_end (ap);
1720}
1721
1722/* Add a note with text GMSGID and with LOCATION to the diagnostic CONTEXT. */
1723void
1724diagnostic_append_note (diagnostic_context *context,
1725 location_t location,
1726 const char * gmsgid, ...)
1727{
1728 diagnostic_info diagnostic;
1729 va_list ap;
1730 rich_location richloc (line_table, location);
1731
1732 va_start (ap, gmsgid);
1733 diagnostic_set_info (diagnostic: &diagnostic, gmsgid, args: &ap, richloc: &richloc, kind: DK_NOTE);
1734 if (context->m_inhibit_notes_p)
1735 {
1736 va_end (ap);
1737 return;
1738 }
1739 char *saved_prefix = pp_take_prefix (context->printer);
1740 pp_set_prefix (context->printer,
1741 diagnostic_build_prefix (context, diagnostic: &diagnostic));
1742 pp_format (context->printer, &diagnostic.message);
1743 pp_output_formatted_text (context->printer);
1744 pp_destroy_prefix (context->printer);
1745 pp_set_prefix (context->printer, saved_prefix);
1746 pp_newline (context->printer);
1747 diagnostic_show_locus (context, richloc: &richloc, diagnostic_kind: DK_NOTE);
1748 va_end (ap);
1749}
1750
1751/* Implement emit_diagnostic, inform, warning, warning_at, pedwarn,
1752 permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
1753 and internal_error_no_backtrace, as documented and defined below. */
1754static bool
1755diagnostic_impl (rich_location *richloc, const diagnostic_metadata *metadata,
1756 int opt, const char *gmsgid,
1757 va_list *ap, diagnostic_t kind)
1758{
1759 diagnostic_info diagnostic;
1760 if (kind == DK_PERMERROR)
1761 {
1762 diagnostic_set_info (diagnostic: &diagnostic, gmsgid, args: ap, richloc,
1763 permissive_error_kind (global_dc));
1764 diagnostic.option_index = (opt != -1 ? opt
1765 : permissive_error_option (global_dc));
1766 }
1767 else
1768 {
1769 diagnostic_set_info (diagnostic: &diagnostic, gmsgid, args: ap, richloc, kind);
1770 if (kind == DK_WARNING || kind == DK_PEDWARN)
1771 diagnostic.option_index = opt;
1772 }
1773 diagnostic.metadata = metadata;
1774 return global_dc->report_diagnostic (diagnostic: &diagnostic);
1775}
1776
1777/* Implement inform_n, warning_n, and error_n, as documented and
1778 defined below. */
1779static bool
1780diagnostic_n_impl (rich_location *richloc, const diagnostic_metadata *metadata,
1781 int opt, unsigned HOST_WIDE_INT n,
1782 const char *singular_gmsgid,
1783 const char *plural_gmsgid,
1784 va_list *ap, diagnostic_t kind)
1785{
1786 diagnostic_info diagnostic;
1787 unsigned long gtn;
1788
1789 if (sizeof n <= sizeof gtn)
1790 gtn = n;
1791 else
1792 /* Use the largest number ngettext can handle, otherwise
1793 preserve the six least significant decimal digits for
1794 languages where the plural form depends on them. */
1795 gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU;
1796
1797 const char *text = ngettext (msgid1: singular_gmsgid, msgid2: plural_gmsgid, n: gtn);
1798 diagnostic_set_info_translated (diagnostic: &diagnostic, msg: text, args: ap, richloc, kind);
1799 if (kind == DK_WARNING)
1800 diagnostic.option_index = opt;
1801 diagnostic.metadata = metadata;
1802 return global_dc->report_diagnostic (diagnostic: &diagnostic);
1803}
1804
1805/* Wrapper around diagnostic_impl taking a variable argument list. */
1806
1807bool
1808emit_diagnostic (diagnostic_t kind, location_t location, int opt,
1809 const char *gmsgid, ...)
1810{
1811 auto_diagnostic_group d;
1812 va_list ap;
1813 va_start (ap, gmsgid);
1814 rich_location richloc (line_table, location);
1815 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap: &ap, kind);
1816 va_end (ap);
1817 return ret;
1818}
1819
1820/* As above, but for rich_location *. */
1821
1822bool
1823emit_diagnostic (diagnostic_t kind, rich_location *richloc, int opt,
1824 const char *gmsgid, ...)
1825{
1826 auto_diagnostic_group d;
1827 va_list ap;
1828 va_start (ap, gmsgid);
1829 bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, ap: &ap, kind);
1830 va_end (ap);
1831 return ret;
1832}
1833
1834/* Wrapper around diagnostic_impl taking a va_list parameter. */
1835
1836bool
1837emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
1838 const char *gmsgid, va_list *ap)
1839{
1840 rich_location richloc (line_table, location);
1841 return diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap, kind);
1842}
1843
1844/* As above, but with rich_location and metadata. */
1845
1846bool
1847emit_diagnostic_valist_meta (diagnostic_t kind,
1848 rich_location *richloc,
1849 const diagnostic_metadata *metadata,
1850 int opt,
1851 const char *gmsgid, va_list *ap)
1852{
1853 return diagnostic_impl (richloc, metadata, opt, gmsgid, ap, kind);
1854}
1855
1856/* An informative note at LOCATION. Use this for additional details on an error
1857 message. */
1858void
1859inform (location_t location, const char *gmsgid, ...)
1860{
1861 auto_diagnostic_group d;
1862 va_list ap;
1863 va_start (ap, gmsgid);
1864 rich_location richloc (line_table, location);
1865 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_NOTE);
1866 va_end (ap);
1867}
1868
1869/* Same as "inform" above, but at RICHLOC. */
1870void
1871inform (rich_location *richloc, const char *gmsgid, ...)
1872{
1873 gcc_assert (richloc);
1874
1875 auto_diagnostic_group d;
1876 va_list ap;
1877 va_start (ap, gmsgid);
1878 diagnostic_impl (richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_NOTE);
1879 va_end (ap);
1880}
1881
1882/* An informative note at LOCATION. Use this for additional details on an
1883 error message. */
1884void
1885inform_n (location_t location, unsigned HOST_WIDE_INT n,
1886 const char *singular_gmsgid, const char *plural_gmsgid, ...)
1887{
1888 va_list ap;
1889 va_start (ap, plural_gmsgid);
1890 auto_diagnostic_group d;
1891 rich_location richloc (line_table, location);
1892 diagnostic_n_impl (richloc: &richloc, NULL, opt: -1, n, singular_gmsgid, plural_gmsgid,
1893 ap: &ap, kind: DK_NOTE);
1894 va_end (ap);
1895}
1896
1897/* A warning at INPUT_LOCATION. Use this for code which is correct according
1898 to the relevant language specification but is likely to be buggy anyway.
1899 Returns true if the warning was printed, false if it was inhibited. */
1900bool
1901warning (int opt, const char *gmsgid, ...)
1902{
1903 auto_diagnostic_group d;
1904 va_list ap;
1905 va_start (ap, gmsgid);
1906 rich_location richloc (line_table, input_location);
1907 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_WARNING);
1908 va_end (ap);
1909 return ret;
1910}
1911
1912/* A warning at LOCATION. Use this for code which is correct according to the
1913 relevant language specification but is likely to be buggy anyway.
1914 Returns true if the warning was printed, false if it was inhibited. */
1915
1916bool
1917warning_at (location_t location, int opt, const char *gmsgid, ...)
1918{
1919 auto_diagnostic_group d;
1920 va_list ap;
1921 va_start (ap, gmsgid);
1922 rich_location richloc (line_table, location);
1923 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_WARNING);
1924 va_end (ap);
1925 return ret;
1926}
1927
1928/* Same as "warning at" above, but using RICHLOC. */
1929
1930bool
1931warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
1932{
1933 gcc_assert (richloc);
1934
1935 auto_diagnostic_group d;
1936 va_list ap;
1937 va_start (ap, gmsgid);
1938 bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_WARNING);
1939 va_end (ap);
1940 return ret;
1941}
1942
1943/* Same as "warning at" above, but using METADATA. */
1944
1945bool
1946warning_meta (rich_location *richloc,
1947 const diagnostic_metadata &metadata,
1948 int opt, const char *gmsgid, ...)
1949{
1950 gcc_assert (richloc);
1951
1952 auto_diagnostic_group d;
1953 va_list ap;
1954 va_start (ap, gmsgid);
1955 bool ret
1956 = diagnostic_impl (richloc, metadata: &metadata, opt, gmsgid, ap: &ap,
1957 kind: DK_WARNING);
1958 va_end (ap);
1959 return ret;
1960}
1961
1962/* Same as warning_n plural variant below, but using RICHLOC. */
1963
1964bool
1965warning_n (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
1966 const char *singular_gmsgid, const char *plural_gmsgid, ...)
1967{
1968 gcc_assert (richloc);
1969
1970 auto_diagnostic_group d;
1971 va_list ap;
1972 va_start (ap, plural_gmsgid);
1973 bool ret = diagnostic_n_impl (richloc, NULL, opt, n,
1974 singular_gmsgid, plural_gmsgid,
1975 ap: &ap, kind: DK_WARNING);
1976 va_end (ap);
1977 return ret;
1978}
1979
1980/* A warning at LOCATION. Use this for code which is correct according to the
1981 relevant language specification but is likely to be buggy anyway.
1982 Returns true if the warning was printed, false if it was inhibited. */
1983
1984bool
1985warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
1986 const char *singular_gmsgid, const char *plural_gmsgid, ...)
1987{
1988 auto_diagnostic_group d;
1989 va_list ap;
1990 va_start (ap, plural_gmsgid);
1991 rich_location richloc (line_table, location);
1992 bool ret = diagnostic_n_impl (richloc: &richloc, NULL, opt, n,
1993 singular_gmsgid, plural_gmsgid,
1994 ap: &ap, kind: DK_WARNING);
1995 va_end (ap);
1996 return ret;
1997}
1998
1999/* A "pedantic" warning at LOCATION: issues a warning unless
2000 -pedantic-errors was given on the command line, in which case it
2001 issues an error. Use this for diagnostics required by the relevant
2002 language standard, if you have chosen not to make them errors.
2003
2004 Note that these diagnostics are issued independent of the setting
2005 of the -Wpedantic command-line switch. To get a warning enabled
2006 only with that switch, use either "if (pedantic) pedwarn
2007 (OPT_Wpedantic,...)" or just "pedwarn (OPT_Wpedantic,..)". To get a
2008 pedwarn independently of the -Wpedantic switch use "pedwarn (0,...)".
2009
2010 Returns true if the warning was printed, false if it was inhibited. */
2011
2012bool
2013pedwarn (location_t location, int opt, const char *gmsgid, ...)
2014{
2015 auto_diagnostic_group d;
2016 va_list ap;
2017 va_start (ap, gmsgid);
2018 rich_location richloc (line_table, location);
2019 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_PEDWARN);
2020 va_end (ap);
2021 return ret;
2022}
2023
2024/* Same as pedwarn above, but using RICHLOC. */
2025
2026bool
2027pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
2028{
2029 gcc_assert (richloc);
2030
2031 auto_diagnostic_group d;
2032 va_list ap;
2033 va_start (ap, gmsgid);
2034 bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_PEDWARN);
2035 va_end (ap);
2036 return ret;
2037}
2038
2039/* A "permissive" error at LOCATION: issues an error unless
2040 -fpermissive was given on the command line, in which case it issues
2041 a warning. Use this for things that really should be errors but we
2042 want to support legacy code.
2043
2044 Returns true if the warning was printed, false if it was inhibited. */
2045
2046bool
2047permerror (location_t location, const char *gmsgid, ...)
2048{
2049 auto_diagnostic_group d;
2050 va_list ap;
2051 va_start (ap, gmsgid);
2052 rich_location richloc (line_table, location);
2053 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_PERMERROR);
2054 va_end (ap);
2055 return ret;
2056}
2057
2058/* Same as "permerror" above, but at RICHLOC. */
2059
2060bool
2061permerror (rich_location *richloc, const char *gmsgid, ...)
2062{
2063 gcc_assert (richloc);
2064
2065 auto_diagnostic_group d;
2066 va_list ap;
2067 va_start (ap, gmsgid);
2068 bool ret = diagnostic_impl (richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_PERMERROR);
2069 va_end (ap);
2070 return ret;
2071}
2072
2073/* Similar to the above, but controlled by a flag other than -fpermissive.
2074 As above, an error by default or a warning with -fpermissive, but this
2075 diagnostic can also be downgraded by -Wno-error=opt. */
2076
2077bool
2078permerror_opt (location_t location, int opt, const char *gmsgid, ...)
2079{
2080 auto_diagnostic_group d;
2081 va_list ap;
2082 va_start (ap, gmsgid);
2083 rich_location richloc (line_table, location);
2084 bool ret = diagnostic_impl (richloc: &richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_PERMERROR);
2085 va_end (ap);
2086 return ret;
2087}
2088
2089/* Same as "permerror" above, but at RICHLOC. */
2090
2091bool
2092permerror_opt (rich_location *richloc, int opt, const char *gmsgid, ...)
2093{
2094 gcc_assert (richloc);
2095
2096 auto_diagnostic_group d;
2097 va_list ap;
2098 va_start (ap, gmsgid);
2099 bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, ap: &ap, kind: DK_PERMERROR);
2100 va_end (ap);
2101 return ret;
2102}
2103
2104/* A hard error: the code is definitely ill-formed, and an object file
2105 will not be produced. */
2106void
2107error (const char *gmsgid, ...)
2108{
2109 auto_diagnostic_group d;
2110 va_list ap;
2111 va_start (ap, gmsgid);
2112 rich_location richloc (line_table, input_location);
2113 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_ERROR);
2114 va_end (ap);
2115}
2116
2117/* A hard error: the code is definitely ill-formed, and an object file
2118 will not be produced. */
2119void
2120error_n (location_t location, unsigned HOST_WIDE_INT n,
2121 const char *singular_gmsgid, const char *plural_gmsgid, ...)
2122{
2123 auto_diagnostic_group d;
2124 va_list ap;
2125 va_start (ap, plural_gmsgid);
2126 rich_location richloc (line_table, location);
2127 diagnostic_n_impl (richloc: &richloc, NULL, opt: -1, n, singular_gmsgid, plural_gmsgid,
2128 ap: &ap, kind: DK_ERROR);
2129 va_end (ap);
2130}
2131
2132/* Same as above, but use location LOC instead of input_location. */
2133void
2134error_at (location_t loc, const char *gmsgid, ...)
2135{
2136 auto_diagnostic_group d;
2137 va_list ap;
2138 va_start (ap, gmsgid);
2139 rich_location richloc (line_table, loc);
2140 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_ERROR);
2141 va_end (ap);
2142}
2143
2144/* Same as above, but use RICH_LOC. */
2145
2146void
2147error_at (rich_location *richloc, const char *gmsgid, ...)
2148{
2149 gcc_assert (richloc);
2150
2151 auto_diagnostic_group d;
2152 va_list ap;
2153 va_start (ap, gmsgid);
2154 diagnostic_impl (richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_ERROR);
2155 va_end (ap);
2156}
2157
2158/* Same as above, but with metadata. */
2159
2160void
2161error_meta (rich_location *richloc, const diagnostic_metadata &metadata,
2162 const char *gmsgid, ...)
2163{
2164 gcc_assert (richloc);
2165
2166 auto_diagnostic_group d;
2167 va_list ap;
2168 va_start (ap, gmsgid);
2169 diagnostic_impl (richloc, metadata: &metadata, opt: -1, gmsgid, ap: &ap, kind: DK_ERROR);
2170 va_end (ap);
2171}
2172
2173/* "Sorry, not implemented." Use for a language feature which is
2174 required by the relevant specification but not implemented by GCC.
2175 An object file will not be produced. */
2176void
2177sorry (const char *gmsgid, ...)
2178{
2179 auto_diagnostic_group d;
2180 va_list ap;
2181 va_start (ap, gmsgid);
2182 rich_location richloc (line_table, input_location);
2183 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_SORRY);
2184 va_end (ap);
2185}
2186
2187/* Same as above, but use location LOC instead of input_location. */
2188void
2189sorry_at (location_t loc, const char *gmsgid, ...)
2190{
2191 auto_diagnostic_group d;
2192 va_list ap;
2193 va_start (ap, gmsgid);
2194 rich_location richloc (line_table, loc);
2195 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_SORRY);
2196 va_end (ap);
2197}
2198
2199/* Return true if an error or a "sorry" has been seen. Various
2200 processing is disabled after errors. */
2201bool
2202seen_error (void)
2203{
2204 return errorcount || sorrycount;
2205}
2206
2207/* An error which is severe enough that we make no attempt to
2208 continue. Do not use this for internal consistency checks; that's
2209 internal_error. Use of this function should be rare. */
2210void
2211fatal_error (location_t loc, const char *gmsgid, ...)
2212{
2213 auto_diagnostic_group d;
2214 va_list ap;
2215 va_start (ap, gmsgid);
2216 rich_location richloc (line_table, loc);
2217 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_FATAL);
2218 va_end (ap);
2219
2220 gcc_unreachable ();
2221}
2222
2223/* An internal consistency check has failed. We make no attempt to
2224 continue. */
2225void
2226internal_error (const char *gmsgid, ...)
2227{
2228 auto_diagnostic_group d;
2229 va_list ap;
2230 va_start (ap, gmsgid);
2231 rich_location richloc (line_table, input_location);
2232 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_ICE);
2233 va_end (ap);
2234
2235 gcc_unreachable ();
2236}
2237
2238/* Like internal_error, but no backtrace will be printed. Used when
2239 the internal error does not happen at the current location, but happened
2240 somewhere else. */
2241void
2242internal_error_no_backtrace (const char *gmsgid, ...)
2243{
2244 auto_diagnostic_group d;
2245 va_list ap;
2246 va_start (ap, gmsgid);
2247 rich_location richloc (line_table, input_location);
2248 diagnostic_impl (richloc: &richloc, NULL, opt: -1, gmsgid, ap: &ap, kind: DK_ICE_NOBT);
2249 va_end (ap);
2250
2251 gcc_unreachable ();
2252}
2253
2254/* Emit DIAGRAM to this context, respecting the output format. */
2255
2256void
2257diagnostic_context::emit_diagram (const diagnostic_diagram &diagram)
2258{
2259 if (m_diagrams.m_theme == nullptr)
2260 return;
2261
2262 gcc_assert (m_output_format);
2263 m_output_format->on_diagram (diagram);
2264}
2265
2266/* Special case error functions. Most are implemented in terms of the
2267 above, or should be. */
2268
2269/* Print a diagnostic MSGID on FILE. This is just fprintf, except it
2270 runs its second argument through gettext. */
2271void
2272fnotice (FILE *file, const char *cmsgid, ...)
2273{
2274 /* If the user requested one of the machine-readable diagnostic output
2275 formats on stderr (e.g. -fdiagnostics-format=sarif-stderr), then
2276 emitting free-form text on stderr will lead to corrupt output.
2277 Skip the message for such cases. */
2278 if (file == stderr && global_dc)
2279 if (const diagnostic_output_format *output_format
2280 = global_dc->get_output_format ())
2281 if (output_format->machine_readable_stderr_p ())
2282 return;
2283
2284 va_list ap;
2285
2286 va_start (ap, cmsgid);
2287 vfprintf (s: file, _(cmsgid), arg: ap);
2288 va_end (ap);
2289}
2290
2291/* Inform the user that an error occurred while trying to report some
2292 other error. This indicates catastrophic internal inconsistencies,
2293 so give up now. But do try to flush out the previous error.
2294 This mustn't use internal_error, that will cause infinite recursion. */
2295
2296void
2297diagnostic_context::error_recursion ()
2298{
2299 if (m_lock < 3)
2300 pp_newline_and_flush (this->printer);
2301
2302 fnotice (stderr,
2303 cmsgid: "internal compiler error: error reporting routines re-entered.\n");
2304
2305 /* Call diagnostic_action_after_output to get the "please submit a bug
2306 report" message. */
2307 diagnostic_action_after_output (context: this, diag_kind: DK_ICE);
2308
2309 /* Do not use gcc_unreachable here; that goes through internal_error
2310 and therefore would cause infinite recursion. */
2311 real_abort ();
2312}
2313
2314/* Report an internal compiler error in a friendly manner. This is
2315 the function that gets called upon use of abort() in the source
2316 code generally, thanks to a special macro. */
2317
2318void
2319fancy_abort (const char *file, int line, const char *function)
2320{
2321 /* If fancy_abort is called before the diagnostic subsystem is initialized,
2322 internal_error will crash internally in a way that prevents a
2323 useful message reaching the user.
2324 This can happen with libgccjit in the case of gcc_assert failures
2325 that occur outside of the libgccjit mutex that guards the rest of
2326 gcc's state, including global_dc (when global_dc may not be
2327 initialized yet, or might be in use by another thread).
2328 Handle such cases as gracefully as possible by falling back to a
2329 minimal abort handler that only relies on i18n. */
2330 if (global_dc->printer == NULL)
2331 {
2332 /* Print the error message. */
2333 fnotice (stderr, cmsgid: diagnostic_kind_text[DK_ICE]);
2334 fnotice (stderr, cmsgid: "in %s, at %s:%d", function, trim_filename (name: file), line);
2335 fputc (c: '\n', stderr);
2336
2337 /* Attempt to print a backtrace. */
2338 struct backtrace_state *state
2339 = backtrace_create_state (NULL, threaded: 0, error_callback: bt_err_callback, NULL);
2340 int count = 0;
2341 if (state != NULL)
2342 backtrace_full (state, skip: 2, callback: bt_callback, error_callback: bt_err_callback,
2343 data: (void *) &count);
2344
2345 /* We can't call warn_if_plugins or emergency_dump_function as these
2346 rely on GCC state that might not be initialized, or might be in
2347 use by another thread. */
2348
2349 /* Abort the process. */
2350 real_abort ();
2351 }
2352
2353 internal_error (gmsgid: "in %s, at %s:%d", function, trim_filename (name: file), line);
2354}
2355
2356/* class diagnostic_context. */
2357
2358void
2359diagnostic_context::begin_group ()
2360{
2361 m_diagnostic_groups.m_nesting_depth++;
2362}
2363
2364void
2365diagnostic_context::end_group ()
2366{
2367 if (--m_diagnostic_groups.m_nesting_depth == 0)
2368 {
2369 /* Handle the case where we've popped the final diagnostic group.
2370 If any diagnostics were emitted, give the context a chance
2371 to do something. */
2372 if (m_diagnostic_groups.m_emission_count > 0)
2373 m_output_format->on_end_group ();
2374 m_diagnostic_groups.m_emission_count = 0;
2375 }
2376}
2377
2378/* class auto_diagnostic_group. */
2379
2380/* Constructor: "push" this group into global_dc. */
2381
2382auto_diagnostic_group::auto_diagnostic_group ()
2383{
2384 global_dc->begin_group ();
2385}
2386
2387/* Destructor: "pop" this group from global_dc. */
2388
2389auto_diagnostic_group::~auto_diagnostic_group ()
2390{
2391 global_dc->end_group ();
2392}
2393
2394/* class diagnostic_text_output_format : public diagnostic_output_format. */
2395
2396diagnostic_text_output_format::~diagnostic_text_output_format ()
2397{
2398 /* Some of the errors may actually have been warnings. */
2399 if (m_context.diagnostic_count (kind: DK_WERROR))
2400 {
2401 /* -Werror was given. */
2402 if (m_context.warning_as_error_requested_p ())
2403 pp_verbatim (m_context.printer,
2404 _("%s: all warnings being treated as errors"),
2405 progname);
2406 /* At least one -Werror= was given. */
2407 else
2408 pp_verbatim (m_context.printer,
2409 _("%s: some warnings being treated as errors"),
2410 progname);
2411 pp_newline_and_flush (m_context.printer);
2412 }
2413}
2414
2415void
2416diagnostic_text_output_format::on_begin_diagnostic (const diagnostic_info &diagnostic)
2417{
2418 (*diagnostic_starter (context: &m_context)) (&m_context, &diagnostic);
2419}
2420
2421void
2422diagnostic_text_output_format::on_end_diagnostic (const diagnostic_info &diagnostic,
2423 diagnostic_t orig_diag_kind)
2424{
2425 (*diagnostic_finalizer (context: &m_context)) (&m_context, &diagnostic,
2426 orig_diag_kind);
2427}
2428
2429void
2430diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
2431{
2432 char *saved_prefix = pp_take_prefix (m_context.printer);
2433 pp_set_prefix (m_context.printer, NULL);
2434 /* Use a newline before and after and a two-space indent
2435 to make the diagram stand out a little from the wall of text. */
2436 pp_newline (m_context.printer);
2437 diagram.get_canvas ().print_to_pp (pp: m_context.printer, per_line_prefix: " ");
2438 pp_newline (m_context.printer);
2439 pp_set_prefix (m_context.printer, saved_prefix);
2440 pp_flush (m_context.printer);
2441}
2442
2443/* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for
2444 file-based output formats. */
2445
2446void
2447diagnostic_output_format_init (diagnostic_context *context,
2448 const char *base_file_name,
2449 enum diagnostics_output_format format,
2450 bool json_formatting)
2451{
2452 switch (format)
2453 {
2454 default:
2455 gcc_unreachable ();
2456 case DIAGNOSTICS_OUTPUT_FORMAT_TEXT:
2457 /* The default; do nothing. */
2458 break;
2459
2460 case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR:
2461 diagnostic_output_format_init_json_stderr (context,
2462 formatted: json_formatting);
2463 break;
2464
2465 case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE:
2466 diagnostic_output_format_init_json_file (context,
2467 formatted: json_formatting,
2468 base_file_name);
2469 break;
2470
2471 case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR:
2472 diagnostic_output_format_init_sarif_stderr (context,
2473 formatted: json_formatting);
2474 break;
2475
2476 case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
2477 diagnostic_output_format_init_sarif_file (context,
2478 formatted: json_formatting,
2479 base_file_name);
2480 break;
2481 }
2482}
2483
2484/* Initialize this context's m_diagrams based on CHARSET.
2485 Specifically, make a text_art::theme object for m_diagrams.m_theme,
2486 (or NULL for "no diagrams"). */
2487
2488void
2489diagnostic_context::
2490set_text_art_charset (enum diagnostic_text_art_charset charset)
2491{
2492 delete m_diagrams.m_theme;
2493 switch (charset)
2494 {
2495 default:
2496 gcc_unreachable ();
2497
2498 case DIAGNOSTICS_TEXT_ART_CHARSET_NONE:
2499 m_diagrams.m_theme = nullptr;
2500 break;
2501
2502 case DIAGNOSTICS_TEXT_ART_CHARSET_ASCII:
2503 m_diagrams.m_theme = new text_art::ascii_theme ();
2504 break;
2505
2506 case DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE:
2507 m_diagrams.m_theme = new text_art::unicode_theme ();
2508 break;
2509
2510 case DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI:
2511 m_diagrams.m_theme = new text_art::emoji_theme ();
2512 break;
2513 }
2514}
2515
2516/* class simple_diagnostic_path : public diagnostic_path. */
2517
2518simple_diagnostic_path::simple_diagnostic_path (pretty_printer *event_pp)
2519 : m_event_pp (event_pp)
2520{
2521 add_thread (name: "main");
2522}
2523
2524/* Implementation of diagnostic_path::num_events vfunc for
2525 simple_diagnostic_path: simply get the number of events in the vec. */
2526
2527unsigned
2528simple_diagnostic_path::num_events () const
2529{
2530 return m_events.length ();
2531}
2532
2533/* Implementation of diagnostic_path::get_event vfunc for
2534 simple_diagnostic_path: simply return the event in the vec. */
2535
2536const diagnostic_event &
2537simple_diagnostic_path::get_event (int idx) const
2538{
2539 return *m_events[idx];
2540}
2541
2542unsigned
2543simple_diagnostic_path::num_threads () const
2544{
2545 return m_threads.length ();
2546}
2547
2548const diagnostic_thread &
2549simple_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
2550{
2551 return *m_threads[idx];
2552}
2553
2554diagnostic_thread_id_t
2555simple_diagnostic_path::add_thread (const char *name)
2556{
2557 m_threads.safe_push (obj: new simple_diagnostic_thread (name));
2558 return m_threads.length () - 1;
2559}
2560
2561/* Add an event to this path at LOC within function FNDECL at
2562 stack depth DEPTH.
2563
2564 Use m_context's printer to format FMT, as the text of the new
2565 event.
2566
2567 Return the id of the new event. */
2568
2569diagnostic_event_id_t
2570simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth,
2571 const char *fmt, ...)
2572{
2573 pretty_printer *pp = m_event_pp;
2574 pp_clear_output_area (pp);
2575
2576 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
2577
2578 va_list ap;
2579
2580 va_start (ap, fmt);
2581
2582 text_info ti (_(fmt), &ap, 0, nullptr, &rich_loc);
2583 pp_format (pp, &ti);
2584 pp_output_formatted_text (pp);
2585
2586 va_end (ap);
2587
2588 simple_diagnostic_event *new_event
2589 = new simple_diagnostic_event (loc, fndecl, depth, pp_formatted_text (pp));
2590 m_events.safe_push (obj: new_event);
2591
2592 pp_clear_output_area (pp);
2593
2594 return diagnostic_event_id_t (m_events.length () - 1);
2595}
2596
2597diagnostic_event_id_t
2598simple_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
2599 location_t loc,
2600 tree fndecl,
2601 int depth,
2602 const char *fmt, ...)
2603{
2604 pretty_printer *pp = m_event_pp;
2605 pp_clear_output_area (pp);
2606
2607 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
2608
2609 va_list ap;
2610
2611 va_start (ap, fmt);
2612
2613 text_info ti (_(fmt), &ap, 0, nullptr, &rich_loc);
2614
2615 pp_format (pp, &ti);
2616 pp_output_formatted_text (pp);
2617
2618 va_end (ap);
2619
2620 simple_diagnostic_event *new_event
2621 = new simple_diagnostic_event (loc, fndecl, depth, pp_formatted_text (pp),
2622 thread_id);
2623 m_events.safe_push (obj: new_event);
2624
2625 pp_clear_output_area (pp);
2626
2627 return diagnostic_event_id_t (m_events.length () - 1);
2628}
2629
2630/* struct simple_diagnostic_event. */
2631
2632/* simple_diagnostic_event's ctor. */
2633
2634simple_diagnostic_event::
2635simple_diagnostic_event (location_t loc,
2636 tree fndecl,
2637 int depth,
2638 const char *desc,
2639 diagnostic_thread_id_t thread_id)
2640: m_loc (loc), m_fndecl (fndecl), m_depth (depth), m_desc (xstrdup (desc)),
2641 m_thread_id (thread_id)
2642{
2643}
2644
2645/* simple_diagnostic_event's dtor. */
2646
2647simple_diagnostic_event::~simple_diagnostic_event ()
2648{
2649 free (ptr: m_desc);
2650}
2651
2652/* Print PATH by emitting a dummy "note" associated with it. */
2653
2654DEBUG_FUNCTION
2655void debug (diagnostic_path *path)
2656{
2657 rich_location richloc (line_table, UNKNOWN_LOCATION);
2658 richloc.set_path (path);
2659 inform (richloc: &richloc, gmsgid: "debug path");
2660}
2661
2662/* Really call the system 'abort'. This has to go right at the end of
2663 this file, so that there are no functions after it that call abort
2664 and get the system abort instead of our macro. */
2665#undef abort
2666static void
2667real_abort (void)
2668{
2669 abort ();
2670}
2671
2672#if CHECKING_P
2673
2674namespace selftest {
2675
2676/* Helper function for test_print_escaped_string. */
2677
2678static void
2679assert_print_escaped_string (const location &loc, const char *expected_output,
2680 const char *input)
2681{
2682 pretty_printer pp;
2683 print_escaped_string (pp: &pp, text: input);
2684 ASSERT_STREQ_AT (loc, expected_output, pp_formatted_text (&pp));
2685}
2686
2687#define ASSERT_PRINT_ESCAPED_STRING_STREQ(EXPECTED_OUTPUT, INPUT) \
2688 assert_print_escaped_string (SELFTEST_LOCATION, EXPECTED_OUTPUT, INPUT)
2689
2690/* Tests of print_escaped_string. */
2691
2692static void
2693test_print_escaped_string ()
2694{
2695 /* Empty string. */
2696 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"\"", "");
2697
2698 /* Non-empty string. */
2699 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"hello world\"", "hello world");
2700
2701 /* Various things that need to be escaped: */
2702 /* Backslash. */
2703 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\\after\"",
2704 "before\\after");
2705 /* Tab. */
2706 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\tafter\"",
2707 "before\tafter");
2708 /* Newline. */
2709 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\nafter\"",
2710 "before\nafter");
2711 /* Double quote. */
2712 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\"after\"",
2713 "before\"after");
2714
2715 /* Non-printable characters: BEL: '\a': 0x07 */
2716 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\007after\"",
2717 "before\aafter");
2718 /* Non-printable characters: vertical tab: '\v': 0x0b */
2719 ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\013after\"",
2720 "before\vafter");
2721}
2722
2723/* Tests of print_parseable_fixits. */
2724
2725/* Verify that print_parseable_fixits emits the empty string if there
2726 are no fixits. */
2727
2728static void
2729test_print_parseable_fixits_none ()
2730{
2731 pretty_printer pp;
2732 file_cache fc;
2733 rich_location richloc (line_table, UNKNOWN_LOCATION);
2734
2735 print_parseable_fixits (fc, pp: &pp, richloc: &richloc, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE, tabstop: 8);
2736 ASSERT_STREQ ("", pp_formatted_text (&pp));
2737}
2738
2739/* Verify that print_parseable_fixits does the right thing if there
2740 is an insertion fixit hint. */
2741
2742static void
2743test_print_parseable_fixits_insert ()
2744{
2745 pretty_printer pp;
2746 file_cache fc;
2747 rich_location richloc (line_table, UNKNOWN_LOCATION);
2748
2749 linemap_add (line_table, LC_ENTER, sysp: false, to_file: "test.c", to_line: 0);
2750 linemap_line_start (set: line_table, to_line: 5, max_column_hint: 100);
2751 linemap_add (line_table, LC_LEAVE, sysp: false, NULL, to_line: 0);
2752 location_t where = linemap_position_for_column (line_table, 10);
2753 richloc.add_fixit_insert_before (where, new_content: "added content");
2754
2755 print_parseable_fixits (fc, pp: &pp, richloc: &richloc, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE, tabstop: 8);
2756 ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n",
2757 pp_formatted_text (&pp));
2758}
2759
2760/* Verify that print_parseable_fixits does the right thing if there
2761 is an removal fixit hint. */
2762
2763static void
2764test_print_parseable_fixits_remove ()
2765{
2766 pretty_printer pp;
2767 file_cache fc;
2768 rich_location richloc (line_table, UNKNOWN_LOCATION);
2769
2770 linemap_add (line_table, LC_ENTER, sysp: false, to_file: "test.c", to_line: 0);
2771 linemap_line_start (set: line_table, to_line: 5, max_column_hint: 100);
2772 linemap_add (line_table, LC_LEAVE, sysp: false, NULL, to_line: 0);
2773 source_range where;
2774 where.m_start = linemap_position_for_column (line_table, 10);
2775 where.m_finish = linemap_position_for_column (line_table, 20);
2776 richloc.add_fixit_remove (src_range: where);
2777
2778 print_parseable_fixits (fc, pp: &pp, richloc: &richloc, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE, tabstop: 8);
2779 ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"\"\n",
2780 pp_formatted_text (&pp));
2781}
2782
2783/* Verify that print_parseable_fixits does the right thing if there
2784 is an replacement fixit hint. */
2785
2786static void
2787test_print_parseable_fixits_replace ()
2788{
2789 pretty_printer pp;
2790 file_cache fc;
2791 rich_location richloc (line_table, UNKNOWN_LOCATION);
2792
2793 linemap_add (line_table, LC_ENTER, sysp: false, to_file: "test.c", to_line: 0);
2794 linemap_line_start (set: line_table, to_line: 5, max_column_hint: 100);
2795 linemap_add (line_table, LC_LEAVE, sysp: false, NULL, to_line: 0);
2796 source_range where;
2797 where.m_start = linemap_position_for_column (line_table, 10);
2798 where.m_finish = linemap_position_for_column (line_table, 20);
2799 richloc.add_fixit_replace (src_range: where, new_content: "replacement");
2800
2801 print_parseable_fixits (fc, pp: &pp, richloc: &richloc, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE, tabstop: 8);
2802 ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"replacement\"\n",
2803 pp_formatted_text (&pp));
2804}
2805
2806/* Verify that print_parseable_fixits correctly handles
2807 DIAGNOSTICS_COLUMN_UNIT_BYTE vs DIAGNOSTICS_COLUMN_UNIT_COLUMN. */
2808
2809static void
2810test_print_parseable_fixits_bytes_vs_display_columns ()
2811{
2812 line_table_test ltt;
2813 rich_location richloc (line_table, UNKNOWN_LOCATION);
2814
2815 /* 1-based byte offsets: 12345677778888999900001234567. */
2816 const char *const content = "smile \xf0\x9f\x98\x82 colour\n";
2817 /* 1-based display cols: 123456[......7-8.....]9012345. */
2818 const int tabstop = 8;
2819
2820 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
2821 file_cache fc;
2822 const char *const fname = tmp.get_filename ();
2823
2824 linemap_add (line_table, LC_ENTER, sysp: false, to_file: fname, to_line: 0);
2825 linemap_line_start (set: line_table, to_line: 1, max_column_hint: 100);
2826 linemap_add (line_table, LC_LEAVE, sysp: false, NULL, to_line: 0);
2827 source_range where;
2828 where.m_start = linemap_position_for_column (line_table, 12);
2829 where.m_finish = linemap_position_for_column (line_table, 17);
2830 richloc.add_fixit_replace (src_range: where, new_content: "color");
2831
2832 /* Escape fname. */
2833 pretty_printer tmp_pp;
2834 print_escaped_string (pp: &tmp_pp, text: fname);
2835 char *escaped_fname = xstrdup (pp_formatted_text (&tmp_pp));
2836
2837 const int buf_len = strlen (s: escaped_fname) + 100;
2838 char *const expected = XNEWVEC (char, buf_len);
2839
2840 {
2841 pretty_printer pp;
2842 print_parseable_fixits (fc, pp: &pp, richloc: &richloc,
2843 column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE,
2844 tabstop);
2845 snprintf (s: expected, maxlen: buf_len,
2846 format: "fix-it:%s:{1:12-1:18}:\"color\"\n", escaped_fname);
2847 ASSERT_STREQ (expected, pp_formatted_text (&pp));
2848 }
2849 {
2850 pretty_printer pp;
2851 print_parseable_fixits (fc, pp: &pp, richloc: &richloc,
2852 column_unit: DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
2853 tabstop);
2854 snprintf (s: expected, maxlen: buf_len,
2855 format: "fix-it:%s:{1:10-1:16}:\"color\"\n", escaped_fname);
2856 ASSERT_STREQ (expected, pp_formatted_text (&pp));
2857 }
2858
2859 XDELETEVEC (expected);
2860 free (ptr: escaped_fname);
2861}
2862
2863/* Verify that
2864 diagnostic_get_location_text (..., SHOW_COLUMN)
2865 generates EXPECTED_LOC_TEXT, given FILENAME, LINE, COLUMN, with
2866 colorization disabled. */
2867
2868static void
2869assert_location_text (const char *expected_loc_text,
2870 const char *filename, int line, int column,
2871 bool show_column,
2872 int origin = 1,
2873 enum diagnostics_column_unit column_unit
2874 = DIAGNOSTICS_COLUMN_UNIT_BYTE)
2875{
2876 test_diagnostic_context dc;
2877 dc.m_show_column = show_column;
2878 dc.m_column_unit = column_unit;
2879 dc.m_column_origin = origin;
2880
2881 expanded_location xloc;
2882 xloc.file = filename;
2883 xloc.line = line;
2884 xloc.column = column;
2885 xloc.data = NULL;
2886 xloc.sysp = false;
2887
2888 label_text actual_loc_text = dc.get_location_text (s: xloc);
2889 ASSERT_STREQ (expected_loc_text, actual_loc_text.get ());
2890}
2891
2892/* Verify that diagnostic_get_location_text works as expected. */
2893
2894static void
2895test_diagnostic_get_location_text ()
2896{
2897 const char *old_progname = progname;
2898 progname = "PROGNAME";
2899 assert_location_text (expected_loc_text: "PROGNAME:", NULL, line: 0, column: 0, show_column: true);
2900 char *built_in_colon = concat (special_fname_builtin (), ":", (char *) 0);
2901 assert_location_text (expected_loc_text: built_in_colon, filename: special_fname_builtin (),
2902 line: 42, column: 10, show_column: true);
2903 free (ptr: built_in_colon);
2904 assert_location_text (expected_loc_text: "foo.c:42:10:", filename: "foo.c", line: 42, column: 10, show_column: true);
2905 assert_location_text (expected_loc_text: "foo.c:42:9:", filename: "foo.c", line: 42, column: 10, show_column: true, origin: 0);
2906 assert_location_text (expected_loc_text: "foo.c:42:1010:", filename: "foo.c", line: 42, column: 10, show_column: true, origin: 1001);
2907 for (int origin = 0; origin != 2; ++origin)
2908 assert_location_text (expected_loc_text: "foo.c:42:", filename: "foo.c", line: 42, column: 0, show_column: true, origin);
2909 assert_location_text (expected_loc_text: "foo.c:", filename: "foo.c", line: 0, column: 10, show_column: true);
2910 assert_location_text (expected_loc_text: "foo.c:42:", filename: "foo.c", line: 42, column: 10, show_column: false);
2911 assert_location_text (expected_loc_text: "foo.c:", filename: "foo.c", line: 0, column: 10, show_column: false);
2912
2913 maybe_line_and_column (INT_MAX, INT_MAX);
2914 maybe_line_and_column (INT_MIN, INT_MIN);
2915
2916 {
2917 /* In order to test display columns vs byte columns, we need to create a
2918 file for location_get_source_line() to read. */
2919
2920 const char *const content = "smile \xf0\x9f\x98\x82\n";
2921 const int line_bytes = strlen (s: content) - 1;
2922 const int def_tabstop = 8;
2923 const cpp_char_column_policy policy (def_tabstop, cpp_wcwidth);
2924 const int display_width = cpp_display_width (data: content, data_length: line_bytes, policy);
2925 ASSERT_EQ (line_bytes - 2, display_width);
2926 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
2927 const char *const fname = tmp.get_filename ();
2928 const int buf_len = strlen (s: fname) + 16;
2929 char *const expected = XNEWVEC (char, buf_len);
2930
2931 snprintf (s: expected, maxlen: buf_len, format: "%s:1:%d:", fname, line_bytes);
2932 assert_location_text (expected_loc_text: expected, filename: fname, line: 1, column: line_bytes, show_column: true,
2933 origin: 1, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE);
2934
2935 snprintf (s: expected, maxlen: buf_len, format: "%s:1:%d:", fname, line_bytes - 1);
2936 assert_location_text (expected_loc_text: expected, filename: fname, line: 1, column: line_bytes, show_column: true,
2937 origin: 0, column_unit: DIAGNOSTICS_COLUMN_UNIT_BYTE);
2938
2939 snprintf (s: expected, maxlen: buf_len, format: "%s:1:%d:", fname, display_width);
2940 assert_location_text (expected_loc_text: expected, filename: fname, line: 1, column: line_bytes, show_column: true,
2941 origin: 1, column_unit: DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
2942
2943 snprintf (s: expected, maxlen: buf_len, format: "%s:1:%d:", fname, display_width - 1);
2944 assert_location_text (expected_loc_text: expected, filename: fname, line: 1, column: line_bytes, show_column: true,
2945 origin: 0, column_unit: DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
2946
2947 XDELETEVEC (expected);
2948 }
2949
2950
2951 progname = old_progname;
2952}
2953
2954/* Selftest for num_digits. */
2955
2956static void
2957test_num_digits ()
2958{
2959 ASSERT_EQ (1, num_digits (0));
2960 ASSERT_EQ (1, num_digits (9));
2961 ASSERT_EQ (2, num_digits (10));
2962 ASSERT_EQ (2, num_digits (99));
2963 ASSERT_EQ (3, num_digits (100));
2964 ASSERT_EQ (3, num_digits (999));
2965 ASSERT_EQ (4, num_digits (1000));
2966 ASSERT_EQ (4, num_digits (9999));
2967 ASSERT_EQ (5, num_digits (10000));
2968 ASSERT_EQ (5, num_digits (99999));
2969 ASSERT_EQ (6, num_digits (100000));
2970 ASSERT_EQ (6, num_digits (999999));
2971 ASSERT_EQ (7, num_digits (1000000));
2972 ASSERT_EQ (7, num_digits (9999999));
2973 ASSERT_EQ (8, num_digits (10000000));
2974 ASSERT_EQ (8, num_digits (99999999));
2975}
2976
2977/* Run all of the selftests within this file. */
2978
2979void
2980c_diagnostic_cc_tests ()
2981{
2982 test_print_escaped_string ();
2983 test_print_parseable_fixits_none ();
2984 test_print_parseable_fixits_insert ();
2985 test_print_parseable_fixits_remove ();
2986 test_print_parseable_fixits_replace ();
2987 test_print_parseable_fixits_bytes_vs_display_columns ();
2988 test_diagnostic_get_location_text ();
2989 test_num_digits ();
2990
2991}
2992
2993} // namespace selftest
2994
2995#endif /* #if CHECKING_P */
2996
2997#if __GNUC__ >= 10
2998# pragma GCC diagnostic pop
2999#endif
3000

source code of gcc/diagnostic.cc