Branch data Line data Source code
1 : : /* Language-independent diagnostic subroutines for the GNU Compiler Collection
2 : : Copyright (C) 1999-2025 Free Software Foundation, Inc.
3 : : Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along 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 "diagnostic-format.h"
41 : : #include "diagnostic-format-sarif.h"
42 : : #include "diagnostic-format-text.h"
43 : : #include "edit-context.h"
44 : : #include "selftest.h"
45 : : #include "selftest-diagnostic.h"
46 : : #include "opts.h"
47 : : #include "cpplib.h"
48 : : #include "text-art/theme.h"
49 : : #include "pretty-print-urlifier.h"
50 : : #include "logical-location.h"
51 : : #include "diagnostic-buffer.h"
52 : : #include "make-unique.h"
53 : :
54 : : #ifdef HAVE_TERMIOS_H
55 : : # include <termios.h>
56 : : #endif
57 : :
58 : : #ifdef GWINSZ_IN_SYS_IOCTL
59 : : # include <sys/ioctl.h>
60 : : #endif
61 : :
62 : : /* Disable warnings about quoting issues in the pp_xxx calls below
63 : : that (intentionally) don't follow GCC diagnostic conventions. */
64 : : #if __GNUC__ >= 10
65 : : # pragma GCC diagnostic push
66 : : # pragma GCC diagnostic ignored "-Wformat-diag"
67 : : #endif
68 : :
69 : : static void real_abort (void) ATTRIBUTE_NORETURN;
70 : :
71 : : /* Name of program invoked, sans directories. */
72 : :
73 : : const char *progname;
74 : :
75 : :
76 : : /* Return a malloc'd string containing MSG formatted a la printf. The
77 : : caller is responsible for freeing the memory. */
78 : : char *
79 : 3055191 : build_message_string (const char *msg, ...)
80 : : {
81 : 3055191 : char *str;
82 : 3055191 : va_list ap;
83 : :
84 : 3055191 : va_start (ap, msg);
85 : 3055191 : str = xvasprintf (msg, ap);
86 : 3055191 : va_end (ap);
87 : :
88 : 3055191 : return str;
89 : : }
90 : :
91 : :
92 : : /* Return the value of the getenv("COLUMNS") as an integer. If the
93 : : value is not set to a positive integer, use ioctl to get the
94 : : terminal width. If it fails, return INT_MAX. */
95 : : int
96 : 741883 : get_terminal_width (void)
97 : : {
98 : 741883 : const char * s = getenv ("COLUMNS");
99 : 741883 : if (s != NULL) {
100 : 126 : int n = atoi (s);
101 : 126 : if (n > 0)
102 : : return n;
103 : : }
104 : :
105 : : #ifdef TIOCGWINSZ
106 : 741757 : struct winsize w;
107 : 741757 : w.ws_col = 0;
108 : 741757 : if (ioctl (0, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
109 : 0 : return w.ws_col;
110 : : #endif
111 : :
112 : : return INT_MAX;
113 : : }
114 : :
115 : : /* Set caret_max_width to value. */
116 : : void
117 : 787783 : diagnostic_set_caret_max_width (diagnostic_context *context, int value)
118 : : {
119 : : /* One minus to account for the leading empty space. */
120 : 787783 : value = value ? value - 1
121 : 787783 : : (isatty (fileno (pp_buffer (context->get_reference_printer ())->m_stream))
122 : 787783 : ? get_terminal_width () - 1 : INT_MAX);
123 : :
124 : 741816 : if (value <= 0)
125 : 45967 : value = INT_MAX;
126 : :
127 : 787783 : context->m_source_printing.max_width = value;
128 : 787783 : }
129 : :
130 : : void
131 : 687251 : diagnostic_option_classifier::init (int n_opts)
132 : : {
133 : 687251 : m_n_opts = n_opts;
134 : 687251 : m_classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
135 : 677970980 : for (int i = 0; i < n_opts; i++)
136 : 677283729 : m_classify_diagnostic[i] = DK_UNSPECIFIED;
137 : 687251 : m_push_list = vNULL;
138 : 687251 : m_classification_history = vNULL;
139 : 687251 : }
140 : :
141 : : void
142 : 296913 : diagnostic_option_classifier::fini ()
143 : : {
144 : 296913 : XDELETEVEC (m_classify_diagnostic);
145 : 296913 : m_classify_diagnostic = nullptr;
146 : 296913 : m_classification_history.release ();
147 : 296913 : m_push_list.release ();
148 : 296913 : }
149 : :
150 : : /* Save the diagnostic_option_classifier state to F for PCH
151 : : output. Returns 0 on success, -1 on error. */
152 : :
153 : : int
154 : 428 : diagnostic_option_classifier::pch_save (FILE *f)
155 : : {
156 : 428 : unsigned int lengths[2] = { m_classification_history.length (),
157 : 428 : m_push_list.length () };
158 : 428 : if (fwrite (lengths, sizeof (lengths), 1, f) != 1
159 : 428 : || (lengths[0]
160 : 64 : && fwrite (m_classification_history.address (),
161 : : sizeof (diagnostic_classification_change_t),
162 : 32 : lengths[0], f) != lengths[0])
163 : 856 : || (lengths[1]
164 : 0 : && fwrite (m_push_list.address (), sizeof (int),
165 : 0 : lengths[1], f) != lengths[1]))
166 : 0 : return -1;
167 : : return 0;
168 : : }
169 : :
170 : : /* Read the diagnostic_option_classifier state from F for PCH
171 : : read. Returns 0 on success, -1 on error. */
172 : :
173 : : int
174 : 347 : diagnostic_option_classifier::pch_restore (FILE *f)
175 : : {
176 : 347 : unsigned int lengths[2];
177 : 347 : if (fread (lengths, sizeof (lengths), 1, f) != 1)
178 : : return -1;
179 : 347 : gcc_checking_assert (m_classification_history.is_empty ());
180 : 347 : gcc_checking_assert (m_push_list.is_empty ());
181 : 347 : m_classification_history.safe_grow (lengths[0]);
182 : 347 : m_push_list.safe_grow (lengths[1]);
183 : 347 : if ((lengths[0]
184 : 48 : && fread (m_classification_history.address (),
185 : : sizeof (diagnostic_classification_change_t),
186 : 24 : lengths[0], f) != lengths[0])
187 : 371 : || (lengths[1]
188 : 0 : && fread (m_push_list.address (), sizeof (int),
189 : 0 : lengths[1], f) != lengths[1]))
190 : 0 : return -1;
191 : : return 0;
192 : : }
193 : :
194 : : /* Save all diagnostic classifications in a stack. */
195 : :
196 : : void
197 : 3391450 : diagnostic_option_classifier::push ()
198 : : {
199 : 6745460 : m_push_list.safe_push (m_classification_history.length ());
200 : 3391450 : }
201 : :
202 : : /* Restore the topmost classification set off the stack. If the stack
203 : : is empty, revert to the state based on command line parameters. */
204 : :
205 : : void
206 : 3390843 : diagnostic_option_classifier::pop (location_t where)
207 : : {
208 : 3390843 : int jump_to;
209 : :
210 : 3390843 : if (!m_push_list.is_empty ())
211 : 3390830 : jump_to = m_push_list.pop ();
212 : : else
213 : : jump_to = 0;
214 : :
215 : 3390843 : diagnostic_classification_change_t v = { where, jump_to, DK_POP };
216 : 3390843 : m_classification_history.safe_push (v);
217 : 3390843 : }
218 : :
219 : : /* Initialize the diagnostic message outputting machinery. */
220 : :
221 : : void
222 : 687251 : diagnostic_context::initialize (int n_opts)
223 : : {
224 : : /* Allocate a basic pretty-printer. Clients will replace this a
225 : : much more elaborated pretty-printer if they wish. */
226 : 687251 : m_reference_printer = ::make_unique<pretty_printer> ().release ();
227 : :
228 : 687251 : m_file_cache = new file_cache ();
229 : 687251 : m_diagnostic_counters.clear ();
230 : 687251 : m_warning_as_error_requested = false;
231 : 687251 : m_n_opts = n_opts;
232 : 687251 : m_option_classifier.init (n_opts);
233 : 687251 : m_source_printing.enabled = false;
234 : 687251 : diagnostic_set_caret_max_width (this, pp_line_cutoff (get_reference_printer ()));
235 : 2749004 : for (int i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
236 : 2061753 : m_source_printing.caret_chars[i] = '^';
237 : 687251 : m_show_cwe = false;
238 : 687251 : m_show_rules = false;
239 : 687251 : m_path_format = DPF_NONE;
240 : 687251 : m_show_path_depths = false;
241 : 687251 : m_show_option_requested = false;
242 : 687251 : m_abort_on_error = false;
243 : 687251 : m_show_column = false;
244 : 687251 : m_pedantic_errors = false;
245 : 687251 : m_permissive = false;
246 : 687251 : m_opt_permissive = 0;
247 : 687251 : m_fatal_errors = false;
248 : 687251 : m_inhibit_warnings = false;
249 : 687251 : m_warn_system_headers = false;
250 : 687251 : m_max_errors = 0;
251 : 687251 : m_internal_error = nullptr;
252 : 687251 : m_adjust_diagnostic_info = nullptr;
253 : 687251 : m_text_callbacks.m_begin_diagnostic = default_diagnostic_text_starter;
254 : 687251 : m_text_callbacks.m_start_span = default_diagnostic_start_span_fn;
255 : 687251 : m_text_callbacks.m_end_diagnostic = default_diagnostic_text_finalizer;
256 : 687251 : m_option_mgr = nullptr;
257 : 687251 : m_urlifier_stack = new auto_vec<urlifier_stack_node> ();
258 : 687251 : m_last_location = UNKNOWN_LOCATION;
259 : 687251 : m_client_aux_data = nullptr;
260 : 687251 : m_lock = 0;
261 : 687251 : m_inhibit_notes_p = false;
262 : 687251 : m_source_printing.colorize_source_p = false;
263 : 687251 : m_source_printing.show_labels_p = false;
264 : 687251 : m_source_printing.show_line_numbers_p = false;
265 : 687251 : m_source_printing.min_margin_width = 0;
266 : 687251 : m_source_printing.show_ruler_p = false;
267 : 687251 : m_source_printing.show_event_links_p = false;
268 : 687251 : m_report_bug = false;
269 : 687251 : m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_none;
270 : 687251 : if (const char *var = getenv ("GCC_EXTRA_DIAGNOSTIC_OUTPUT"))
271 : : {
272 : 4 : if (!strcmp (var, "fixits-v1"))
273 : 2 : m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1;
274 : 2 : else if (!strcmp (var, "fixits-v2"))
275 : 2 : m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2;
276 : : /* Silently ignore unrecognized values. */
277 : : }
278 : 687251 : m_column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
279 : 687251 : m_column_origin = 1;
280 : 687251 : m_tabstop = 8;
281 : 687251 : m_escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
282 : 687251 : m_edit_context_ptr = nullptr;
283 : 687251 : m_diagnostic_groups.m_group_nesting_depth = 0;
284 : 687251 : m_diagnostic_groups.m_diagnostic_nesting_level = 0;
285 : 687251 : m_diagnostic_groups.m_emission_count = 0;
286 : 687251 : m_output_sinks.safe_push
287 : 687251 : (new diagnostic_text_output_format (*this, nullptr, true));
288 : 687251 : m_set_locations_cb = nullptr;
289 : 687251 : m_client_data_hooks = nullptr;
290 : 687251 : m_diagrams.m_theme = nullptr;
291 : 687251 : m_original_argv = nullptr;
292 : 687251 : m_diagnostic_buffer = nullptr;
293 : :
294 : 687251 : enum diagnostic_text_art_charset text_art_charset
295 : : = DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI;
296 : 687251 : if (const char *lang = getenv ("LANG"))
297 : : {
298 : : /* For LANG=C, don't assume the terminal supports anything
299 : : other than ASCII. */
300 : 684971 : if (!strcmp (lang, "C"))
301 : 687251 : text_art_charset = DIAGNOSTICS_TEXT_ART_CHARSET_ASCII;
302 : : }
303 : 687251 : set_text_art_charset (text_art_charset);
304 : 687251 : }
305 : :
306 : : /* Maybe initialize the color support. We require clients to do this
307 : : explicitly, since most clients don't want color. When called
308 : : without a VALUE, it initializes with DIAGNOSTICS_COLOR_DEFAULT. */
309 : :
310 : : void
311 : 1364424 : diagnostic_context::color_init (int value)
312 : : {
313 : : /* value == -1 is the default value. */
314 : 1364424 : if (value < 0)
315 : : {
316 : : /* If DIAGNOSTICS_COLOR_DEFAULT is -1, default to
317 : : -fdiagnostics-color=auto if GCC_COLORS is in the environment,
318 : : otherwise default to -fdiagnostics-color=never, for other
319 : : values default to that
320 : : -fdiagnostics-color={never,auto,always}. */
321 : 576484 : if (DIAGNOSTICS_COLOR_DEFAULT == -1)
322 : : {
323 : : if (!getenv ("GCC_COLORS"))
324 : : return;
325 : : value = DIAGNOSTICS_COLOR_AUTO;
326 : : }
327 : : else
328 : 576484 : value = DIAGNOSTICS_COLOR_DEFAULT;
329 : : }
330 : 2728848 : pp_show_color (m_reference_printer)
331 : 1364424 : = colorize_init ((diagnostic_color_rule_t) value);
332 : 5457696 : for (auto sink : m_output_sinks)
333 : 1364424 : if (sink->follows_reference_printer_p ())
334 : 1364424 : pp_show_color (sink->get_printer ())
335 : 1364424 : = pp_show_color (m_reference_printer);
336 : : }
337 : :
338 : : /* Initialize URL support within this context based on VALUE,
339 : : handling "auto". */
340 : :
341 : : void
342 : 1353787 : diagnostic_context::urls_init (int value)
343 : : {
344 : : /* value == -1 is the default value. */
345 : 1353787 : if (value < 0)
346 : : {
347 : : /* If DIAGNOSTICS_URLS_DEFAULT is -1, default to
348 : : -fdiagnostics-urls=auto if GCC_URLS or TERM_URLS is in the
349 : : environment, otherwise default to -fdiagnostics-urls=never,
350 : : for other values default to that
351 : : -fdiagnostics-urls={never,auto,always}. */
352 : 576484 : if (DIAGNOSTICS_URLS_DEFAULT == -1)
353 : : {
354 : : if (!getenv ("GCC_URLS") && !getenv ("TERM_URLS"))
355 : : return;
356 : : value = DIAGNOSTICS_URL_AUTO;
357 : : }
358 : : else
359 : 576484 : value = DIAGNOSTICS_URLS_DEFAULT;
360 : : }
361 : :
362 : 1353787 : m_reference_printer->set_url_format
363 : 1353787 : (determine_url_format ((diagnostic_url_rule_t) value));
364 : 5415148 : for (auto sink : m_output_sinks)
365 : 1353787 : if (sink->follows_reference_printer_p ())
366 : 1353787 : sink->get_printer ()->set_url_format
367 : 1353787 : (m_reference_printer->get_url_format ());
368 : : }
369 : :
370 : : /* Create the file_cache, if not already created, and tell it how to
371 : : translate files on input. */
372 : : void
373 : 202823 : diagnostic_context::
374 : : initialize_input_context (diagnostic_input_charset_callback ccb,
375 : : bool should_skip_bom)
376 : : {
377 : 202823 : m_file_cache->initialize_input_context (ccb, should_skip_bom);
378 : 202823 : }
379 : :
380 : : /* Do any cleaning up required after the last diagnostic is emitted. */
381 : :
382 : : void
383 : 296913 : diagnostic_context::finish ()
384 : : {
385 : : /* We might be handling a fatal error.
386 : : Close any active diagnostic groups, which may trigger flushing
387 : : sinks. */
388 : 297653 : while (m_diagnostic_groups.m_group_nesting_depth > 0)
389 : 740 : end_group ();
390 : :
391 : 296913 : set_diagnostic_buffer (nullptr);
392 : :
393 : : /* Clean ups. */
394 : :
395 : 890744 : while (!m_output_sinks.is_empty ())
396 : 296918 : delete m_output_sinks.pop ();
397 : :
398 : 296913 : if (m_diagrams.m_theme)
399 : : {
400 : 39500 : delete m_diagrams.m_theme;
401 : 39500 : m_diagrams.m_theme = nullptr;
402 : : }
403 : :
404 : 296913 : delete m_file_cache;
405 : 296913 : m_file_cache = nullptr;
406 : :
407 : 296913 : m_option_classifier.fini ();
408 : :
409 : 296913 : delete m_reference_printer;
410 : 296913 : m_reference_printer = nullptr;
411 : :
412 : 296913 : if (m_edit_context_ptr)
413 : : {
414 : 17 : delete m_edit_context_ptr;
415 : 17 : m_edit_context_ptr = nullptr;
416 : : }
417 : :
418 : 296913 : if (m_client_data_hooks)
419 : : {
420 : 276528 : delete m_client_data_hooks;
421 : 276528 : m_client_data_hooks = nullptr;
422 : : }
423 : :
424 : 296913 : delete m_option_mgr;
425 : 296913 : m_option_mgr = nullptr;
426 : :
427 : 296913 : if (m_urlifier_stack)
428 : : {
429 : 574741 : while (!m_urlifier_stack->is_empty ())
430 : 277828 : pop_urlifier ();
431 : 296913 : delete m_urlifier_stack;
432 : 296913 : m_urlifier_stack = nullptr;
433 : : }
434 : :
435 : 296913 : freeargv (m_original_argv);
436 : 296913 : m_original_argv = nullptr;
437 : 296913 : }
438 : :
439 : : /* Dump state of this diagnostic_context to OUT, for debugging. */
440 : :
441 : : void
442 : 0 : diagnostic_context::dump (FILE *out) const
443 : : {
444 : 0 : fprintf (out, "diagnostic_context:\n");
445 : 0 : m_diagnostic_counters.dump (out, 2);
446 : 0 : fprintf (out, " reference printer:\n");
447 : 0 : m_reference_printer->dump (out, 4);
448 : 0 : fprintf (out, " output sinks:\n");
449 : 0 : if (m_output_sinks.length () > 0)
450 : : {
451 : 0 : for (unsigned i = 0; i < m_output_sinks.length (); ++i)
452 : : {
453 : 0 : fprintf (out, " sink %i:\n", i);
454 : 0 : m_output_sinks[i]->dump (out, 4);
455 : : }
456 : : }
457 : : else
458 : 0 : fprintf (out, " (none):\n");
459 : 0 : fprintf (out, " diagnostic buffer:\n");
460 : 0 : if (m_diagnostic_buffer)
461 : 0 : m_diagnostic_buffer->dump (out, 4);
462 : : else
463 : 0 : fprintf (out, " (none):\n");
464 : 0 : fprintf (out, " file cache:\n");
465 : 0 : if (m_file_cache)
466 : 0 : m_file_cache->dump (out, 4);
467 : : else
468 : 0 : fprintf (out, " (none):\n");
469 : 0 : }
470 : :
471 : : /* Return true if sufficiently severe diagnostics have been seen that
472 : : we ought to exit with a non-zero exit code. */
473 : :
474 : : bool
475 : 276304 : diagnostic_context::execution_failed_p () const
476 : : {
477 : : /* Equivalent to (seen_error () || werrorcount), but on
478 : : this context, rather than global_dc. */
479 : 276304 : return (diagnostic_count (DK_ERROR)
480 : 250104 : || diagnostic_count (DK_SORRY)
481 : 526246 : || diagnostic_count (DK_WERROR));
482 : : }
483 : :
484 : : void
485 : 1571 : diagnostic_context::remove_all_output_sinks ()
486 : : {
487 : 4713 : while (!m_output_sinks.is_empty ())
488 : 1571 : delete m_output_sinks.pop ();
489 : 1571 : }
490 : :
491 : : void
492 : 1571 : diagnostic_context::
493 : : set_output_format (std::unique_ptr<diagnostic_output_format> output_format)
494 : : {
495 : 1571 : remove_all_output_sinks ();
496 : 1571 : m_output_sinks.safe_push (output_format.release ());
497 : 1571 : }
498 : :
499 : : diagnostic_output_format &
500 : 18646 : diagnostic_context::get_output_format (size_t idx) const
501 : : {
502 : 18646 : gcc_assert (idx < m_output_sinks.length ());
503 : 18646 : gcc_assert (m_output_sinks[idx]);
504 : 18646 : return *m_output_sinks[idx];
505 : : }
506 : :
507 : : void
508 : 5 : diagnostic_context::add_sink (std::unique_ptr<diagnostic_output_format> sink)
509 : : {
510 : 5 : m_output_sinks.safe_push (sink.release ());
511 : 5 : }
512 : :
513 : : /* Return true if there are no machine-readable formats writing to stderr. */
514 : :
515 : : bool
516 : 17467 : diagnostic_context::supports_fnotice_on_stderr_p () const
517 : : {
518 : 69802 : for (auto sink : m_output_sinks)
519 : 17401 : if (sink->machine_readable_stderr_p ())
520 : : return false;
521 : : return true;
522 : : }
523 : :
524 : : void
525 : 330758 : diagnostic_context::
526 : : set_client_data_hooks (std::unique_ptr<diagnostic_client_data_hooks> hooks)
527 : : {
528 : 330758 : delete m_client_data_hooks;
529 : : /* Ideally the field would be a std::unique_ptr here. */
530 : 330758 : m_client_data_hooks = hooks.release ();
531 : 330758 : }
532 : :
533 : : void
534 : 277917 : diagnostic_context::set_original_argv (unique_argv original_argv)
535 : : {
536 : : /* Ideally we'd use a unique_argv for m_original_argv, but
537 : : diagnostic_context doesn't yet have a ctor/dtor pair. */
538 : :
539 : : // Ensure any old value is freed
540 : 277917 : freeargv (m_original_argv);
541 : :
542 : : // Take ownership of the new value
543 : 277917 : m_original_argv = original_argv.release ();
544 : 277917 : }
545 : :
546 : : void
547 : 289818 : diagnostic_context::
548 : : set_option_manager (std::unique_ptr<diagnostic_option_manager> mgr,
549 : : unsigned lang_mask)
550 : : {
551 : 289818 : delete m_option_mgr;
552 : 289818 : m_option_mgr = mgr.release ();
553 : 289818 : m_lang_mask = lang_mask;
554 : 289818 : }
555 : :
556 : : void
557 : 564595 : diagnostic_context::push_owned_urlifier (std::unique_ptr<urlifier> ptr)
558 : : {
559 : 564595 : gcc_assert (m_urlifier_stack);
560 : 564595 : const urlifier_stack_node node = { ptr.release (), true };
561 : 564595 : m_urlifier_stack->safe_push (node);
562 : 564595 : }
563 : :
564 : : void
565 : 1825996198 : diagnostic_context::push_borrowed_urlifier (const urlifier &loan)
566 : : {
567 : 1825996198 : gcc_assert (m_urlifier_stack);
568 : 1825996198 : const urlifier_stack_node node = { const_cast <urlifier *> (&loan), false };
569 : 1825996198 : m_urlifier_stack->safe_push (node);
570 : 1825996198 : }
571 : :
572 : : void
573 : 1826274025 : diagnostic_context::pop_urlifier ()
574 : : {
575 : 1826274025 : gcc_assert (m_urlifier_stack);
576 : 1826274025 : gcc_assert (m_urlifier_stack->length () > 0);
577 : :
578 : 1826274025 : const urlifier_stack_node node = m_urlifier_stack->pop ();
579 : 1826274025 : if (node.m_owned)
580 : 277827 : delete node.m_urlifier;
581 : 1826274025 : }
582 : :
583 : : const urlifier *
584 : 1495072 : diagnostic_context::get_urlifier () const
585 : : {
586 : 1495072 : if (!m_urlifier_stack)
587 : : return nullptr;
588 : 1495072 : if (m_urlifier_stack->is_empty ())
589 : : return nullptr;
590 : 1494735 : return m_urlifier_stack->last ().m_urlifier;
591 : : }
592 : :
593 : :
594 : : /* Set PP as the reference printer for this context.
595 : : Refresh all output sinks. */
596 : :
597 : : void
598 : 201755 : diagnostic_context::set_pretty_printer (std::unique_ptr<pretty_printer> pp)
599 : : {
600 : 201755 : delete m_reference_printer;
601 : 201755 : m_reference_printer = pp.release ();
602 : 201755 : refresh_output_sinks ();
603 : 201755 : }
604 : :
605 : : /* Give all output sinks a chance to rebuild their pretty_printer. */
606 : :
607 : : void
608 : 479672 : diagnostic_context::refresh_output_sinks ()
609 : : {
610 : 1918688 : for (auto sink : m_output_sinks)
611 : 479672 : sink->update_printer ();
612 : 479672 : }
613 : :
614 : : /* Set FORMAT_DECODER on the reference printer and on the pretty_printer
615 : : of all output sinks. */
616 : :
617 : : void
618 : 563000 : diagnostic_context::set_format_decoder (printer_fn format_decoder)
619 : : {
620 : 563000 : pp_format_decoder (m_reference_printer) = format_decoder;
621 : 2252000 : for (auto sink : m_output_sinks)
622 : 563000 : pp_format_decoder (sink->get_printer ()) = format_decoder;
623 : 563000 : }
624 : :
625 : : void
626 : 555884 : diagnostic_context::set_show_highlight_colors (bool val)
627 : : {
628 : 555884 : pp_show_highlight_colors (m_reference_printer) = val;
629 : 2223536 : for (auto sink : m_output_sinks)
630 : 555884 : if (sink->follows_reference_printer_p ())
631 : 555884 : pp_show_highlight_colors (sink->get_printer ()) = val;
632 : 555884 : }
633 : :
634 : : void
635 : 416 : diagnostic_context::set_prefixing_rule (diagnostic_prefixing_rule_t rule)
636 : : {
637 : 416 : pp_prefixing_rule (m_reference_printer) = rule;
638 : 1664 : for (auto sink : m_output_sinks)
639 : 416 : if (sink->follows_reference_printer_p ())
640 : 416 : pp_prefixing_rule (sink->get_printer ()) = rule;
641 : 416 : }
642 : :
643 : : void
644 : 17 : diagnostic_context::create_edit_context ()
645 : : {
646 : 17 : delete m_edit_context_ptr;
647 : 17 : gcc_assert (m_file_cache);
648 : 17 : m_edit_context_ptr = new edit_context (*m_file_cache);
649 : 17 : }
650 : :
651 : : /* Initialize DIAGNOSTIC, where the message MSG has already been
652 : : translated. */
653 : : void
654 : 94006870 : diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
655 : : va_list *args, rich_location *richloc,
656 : : diagnostic_t kind)
657 : : {
658 : 94006870 : gcc_assert (richloc);
659 : 94006870 : diagnostic->message.m_err_no = errno;
660 : 94006870 : diagnostic->message.m_args_ptr = args;
661 : 94006870 : diagnostic->message.m_format_spec = msg;
662 : 94006870 : diagnostic->message.m_richloc = richloc;
663 : 94006870 : diagnostic->richloc = richloc;
664 : 94006870 : diagnostic->metadata = NULL;
665 : 94006870 : diagnostic->kind = kind;
666 : 94006870 : diagnostic->option_id = 0;
667 : 94006870 : }
668 : :
669 : : /* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
670 : : translated. */
671 : : void
672 : 93852090 : diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
673 : : va_list *args, rich_location *richloc,
674 : : diagnostic_t kind)
675 : : {
676 : 93852090 : gcc_assert (richloc);
677 : 93852090 : diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
678 : 93852090 : }
679 : :
680 : : static const char *const diagnostic_kind_color[] = {
681 : : #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
682 : : #include "diagnostic.def"
683 : : #undef DEFINE_DIAGNOSTIC_KIND
684 : : NULL
685 : : };
686 : :
687 : : /* Get a color name for diagnostics of type KIND
688 : : Result could be NULL. */
689 : :
690 : : const char *
691 : 1655085 : diagnostic_get_color_for_kind (diagnostic_t kind)
692 : : {
693 : 1655085 : return diagnostic_kind_color[kind];
694 : : }
695 : :
696 : : /* Given an expanded_location, convert the column (which is in 1-based bytes)
697 : : to the requested units, without converting the origin.
698 : : Return -1 if the column is invalid (<= 0). */
699 : :
700 : : static int
701 : 302560 : convert_column_unit (file_cache &fc,
702 : : enum diagnostics_column_unit column_unit,
703 : : int tabstop,
704 : : expanded_location s)
705 : : {
706 : 302560 : if (s.column <= 0)
707 : : return -1;
708 : :
709 : 299831 : switch (column_unit)
710 : : {
711 : 0 : default:
712 : 0 : gcc_unreachable ();
713 : :
714 : 299546 : case DIAGNOSTICS_COLUMN_UNIT_DISPLAY:
715 : 299546 : {
716 : 299546 : cpp_char_column_policy policy (tabstop, cpp_wcwidth);
717 : 299546 : return location_compute_display_column (fc, s, policy);
718 : : }
719 : :
720 : : case DIAGNOSTICS_COLUMN_UNIT_BYTE:
721 : : return s.column;
722 : : }
723 : : }
724 : :
725 : 2246683 : diagnostic_column_policy::
726 : 2246683 : diagnostic_column_policy (const diagnostic_context &dc)
727 : 2246683 : : m_file_cache (dc.get_file_cache ()),
728 : 2246683 : m_column_unit (dc.m_column_unit),
729 : 2246683 : m_column_origin (dc.m_column_origin),
730 : 2246683 : m_tabstop (dc.m_tabstop)
731 : : {
732 : 2246683 : }
733 : :
734 : : /* Given an expanded_location, convert the column (which is in 1-based bytes)
735 : : to the requested units and origin. Return -1 if the column is
736 : : invalid (<= 0). */
737 : : int
738 : 302482 : diagnostic_column_policy::converted_column (expanded_location s) const
739 : : {
740 : 604964 : int one_based_col = convert_column_unit (m_file_cache,
741 : 302482 : m_column_unit, m_tabstop, s);
742 : 302482 : if (one_based_col <= 0)
743 : : return -1;
744 : 299753 : return one_based_col + (m_column_origin - 1);
745 : : }
746 : :
747 : : /* Return a string describing a location e.g. "foo.c:42:10". */
748 : :
749 : : label_text
750 : 329448 : diagnostic_column_policy::get_location_text (const expanded_location &s,
751 : : bool show_column,
752 : : bool colorize) const
753 : : {
754 : 329448 : const char *locus_cs = colorize_start (colorize, "locus");
755 : 329448 : const char *locus_ce = colorize_stop (colorize);
756 : 329448 : const char *file = s.file ? s.file : progname;
757 : 329448 : int line = 0;
758 : 329448 : int col = -1;
759 : 329448 : if (strcmp (file, special_fname_builtin ()))
760 : : {
761 : 328937 : line = s.line;
762 : 328937 : if (show_column)
763 : 301258 : col = converted_column (s);
764 : : }
765 : :
766 : 329448 : const char *line_col = maybe_line_and_column (line, col);
767 : 329448 : return label_text::take (build_message_string ("%s%s%s:%s", locus_cs, file,
768 : 329448 : line_col, locus_ce));
769 : : }
770 : :
771 : 48077 : diagnostic_location_print_policy::
772 : 48077 : diagnostic_location_print_policy (const diagnostic_context &dc)
773 : 48077 : : m_column_policy (dc),
774 : 48077 : m_show_column (dc.m_show_column)
775 : : {
776 : 48077 : }
777 : :
778 : 1180699 : diagnostic_location_print_policy::
779 : 1180699 : diagnostic_location_print_policy (const diagnostic_text_output_format &text_output)
780 : : :
781 : 1180699 : m_column_policy (text_output.get_context ()),
782 : 1180699 : m_show_column (text_output.get_context ().m_show_column)
783 : : {
784 : 1180699 : }
785 : :
786 : : static const char *const diagnostic_kind_text[] = {
787 : : #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
788 : : #include "diagnostic.def"
789 : : #undef DEFINE_DIAGNOSTIC_KIND
790 : : "must-not-happen"
791 : : };
792 : :
793 : : /* Get unlocalized string describing KIND. */
794 : :
795 : : const char *
796 : 328042 : get_diagnostic_kind_text (diagnostic_t kind)
797 : : {
798 : 328042 : return diagnostic_kind_text[kind];
799 : : }
800 : :
801 : : /* Functions at which to stop the backtrace print. It's not
802 : : particularly helpful to print the callers of these functions. */
803 : :
804 : : static const char * const bt_stop[] =
805 : : {
806 : : "main",
807 : : "toplev::main",
808 : : "execute_one_pass",
809 : : "compile_file",
810 : : };
811 : :
812 : : /* A callback function passed to the backtrace_full function. */
813 : :
814 : : static int
815 : 345 : bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
816 : : const char *function)
817 : : {
818 : 345 : int *pcount = (int *) data;
819 : :
820 : : /* If we don't have any useful information, don't print
821 : : anything. */
822 : 345 : if (filename == NULL && function == NULL)
823 : : return 0;
824 : :
825 : : /* Skip functions in diagnostic.cc. */
826 : 343 : if (*pcount == 0
827 : 44 : && filename != NULL
828 : 387 : && strcmp (lbasename (filename), "diagnostic.cc") == 0)
829 : : return 0;
830 : :
831 : : /* Print up to 20 functions. We could make this a --param, but
832 : : since this is only for debugging just use a constant for now. */
833 : 321 : if (*pcount >= 20)
834 : : {
835 : : /* Returning a non-zero value stops the backtrace. */
836 : : return 1;
837 : : }
838 : 315 : ++*pcount;
839 : :
840 : 315 : char *alc = NULL;
841 : 315 : if (function != NULL)
842 : : {
843 : 315 : char *str = cplus_demangle_v3 (function,
844 : : (DMGL_VERBOSE | DMGL_ANSI
845 : : | DMGL_GNU_V3 | DMGL_PARAMS));
846 : 315 : if (str != NULL)
847 : : {
848 : 186 : alc = str;
849 : 186 : function = str;
850 : : }
851 : :
852 : 1547 : for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
853 : : {
854 : 1248 : size_t len = strlen (bt_stop[i]);
855 : 1248 : if (strncmp (function, bt_stop[i], len) == 0
856 : 16 : && (function[len] == '\0' || function[len] == '('))
857 : : {
858 : 16 : if (alc != NULL)
859 : 12 : free (alc);
860 : : /* Returning a non-zero value stops the backtrace. */
861 : 16 : return 1;
862 : : }
863 : : }
864 : : }
865 : :
866 : 598 : fprintf (stderr, "0x%lx %s\n\t%s:%d\n",
867 : : (unsigned long) pc,
868 : : function == NULL ? "???" : function,
869 : : filename == NULL ? "???" : filename,
870 : : lineno);
871 : :
872 : 299 : if (alc != NULL)
873 : 174 : free (alc);
874 : :
875 : : return 0;
876 : : }
877 : :
878 : : /* A callback function passed to the backtrace_full function. This is
879 : : called if backtrace_full has an error. */
880 : :
881 : : static void
882 : 0 : bt_err_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
883 : : {
884 : 0 : if (errnum < 0)
885 : : {
886 : : /* This means that no debug info was available. Just quietly
887 : : skip printing backtrace info. */
888 : : return;
889 : : }
890 : 0 : fprintf (stderr, "%s%s%s\n", msg, errnum == 0 ? "" : ": ",
891 : 0 : errnum == 0 ? "" : xstrerror (errnum));
892 : : }
893 : :
894 : : /* Check if we've met the maximum error limit, and if so fatally exit
895 : : with a message.
896 : : FLUSH indicates whether a diagnostic_context::finish call is needed. */
897 : :
898 : : void
899 : 1394969 : diagnostic_context::check_max_errors (bool flush)
900 : : {
901 : 1394969 : if (!m_max_errors)
902 : : return;
903 : :
904 : 3670 : int count = (diagnostic_count (DK_ERROR)
905 : 3670 : + diagnostic_count (DK_SORRY)
906 : 3670 : + diagnostic_count (DK_WERROR));
907 : :
908 : 3670 : if (count >= m_max_errors)
909 : : {
910 : 7 : fnotice (stderr,
911 : : "compilation terminated due to -fmax-errors=%u.\n",
912 : : m_max_errors);
913 : 7 : if (flush)
914 : 3 : finish ();
915 : 7 : exit (FATAL_EXIT_CODE);
916 : : }
917 : : }
918 : :
919 : : /* Take any action which is expected to happen after the diagnostic
920 : : is written out. This function does not always return. */
921 : : void
922 : 336204 : diagnostic_context::action_after_output (diagnostic_t diag_kind)
923 : : {
924 : 336204 : switch (diag_kind)
925 : : {
926 : : case DK_DEBUG:
927 : : case DK_NOTE:
928 : : case DK_ANACHRONISM:
929 : : case DK_WARNING:
930 : : break;
931 : :
932 : 136696 : case DK_ERROR:
933 : 136696 : case DK_SORRY:
934 : 136696 : if (m_abort_on_error)
935 : 0 : real_abort ();
936 : 136696 : if (m_fatal_errors)
937 : : {
938 : 7 : fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n");
939 : 7 : finish ();
940 : 7 : exit (FATAL_EXIT_CODE);
941 : : }
942 : : break;
943 : :
944 : 22 : case DK_ICE:
945 : 22 : case DK_ICE_NOBT:
946 : 22 : {
947 : : /* Attempt to ensure that any outputs are flushed e.g. that .sarif
948 : : files are written out.
949 : : Only do it once. */
950 : 22 : static bool finishing_due_to_ice = false;
951 : 22 : if (!finishing_due_to_ice)
952 : : {
953 : 22 : finishing_due_to_ice = true;
954 : 22 : finish ();
955 : : }
956 : :
957 : 22 : struct backtrace_state *state = NULL;
958 : 22 : if (diag_kind == DK_ICE)
959 : 22 : state = backtrace_create_state (NULL, 0, bt_err_callback, NULL);
960 : 22 : int count = 0;
961 : 22 : if (state != NULL)
962 : 22 : backtrace_full (state, 2, bt_callback, bt_err_callback,
963 : : (void *) &count);
964 : :
965 : 22 : if (m_abort_on_error)
966 : 0 : real_abort ();
967 : :
968 : 22 : if (m_report_bug)
969 : 0 : fnotice (stderr, "Please submit a full bug report, "
970 : : "with preprocessed source.\n");
971 : : else
972 : 22 : fnotice (stderr, "Please submit a full bug report, "
973 : : "with preprocessed source (by using -freport-bug).\n");
974 : :
975 : 22 : if (count > 0)
976 : 22 : fnotice (stderr, "Please include the complete backtrace "
977 : : "with any bug report.\n");
978 : 22 : fnotice (stderr, "See %s for instructions.\n", bug_report_url);
979 : :
980 : 22 : exit (ICE_EXIT_CODE);
981 : : }
982 : :
983 : 677 : case DK_FATAL:
984 : 677 : if (m_abort_on_error)
985 : 0 : real_abort ();
986 : 677 : fnotice (stderr, "compilation terminated.\n");
987 : 677 : finish ();
988 : 677 : exit (FATAL_EXIT_CODE);
989 : :
990 : 0 : default:
991 : 0 : gcc_unreachable ();
992 : : }
993 : 335498 : }
994 : :
995 : : /* class logical_location. */
996 : :
997 : : /* Return true iff this is a function or method. */
998 : :
999 : : bool
1000 : 3882 : logical_location::function_p () const
1001 : : {
1002 : 3882 : switch (get_kind ())
1003 : : {
1004 : 0 : default:
1005 : 0 : gcc_unreachable ();
1006 : : case LOGICAL_LOCATION_KIND_UNKNOWN:
1007 : : case LOGICAL_LOCATION_KIND_MODULE:
1008 : : case LOGICAL_LOCATION_KIND_NAMESPACE:
1009 : : case LOGICAL_LOCATION_KIND_TYPE:
1010 : : case LOGICAL_LOCATION_KIND_RETURN_TYPE:
1011 : : case LOGICAL_LOCATION_KIND_PARAMETER:
1012 : : case LOGICAL_LOCATION_KIND_VARIABLE:
1013 : : return false;
1014 : :
1015 : 3882 : case LOGICAL_LOCATION_KIND_FUNCTION:
1016 : 3882 : case LOGICAL_LOCATION_KIND_MEMBER:
1017 : 3882 : return true;
1018 : : }
1019 : : }
1020 : :
1021 : : void
1022 : 1792 : default_diagnostic_start_span_fn (const diagnostic_location_print_policy &loc_policy,
1023 : : pretty_printer *pp,
1024 : : expanded_location exploc)
1025 : : {
1026 : 1792 : const diagnostic_column_policy &column_policy
1027 : 1792 : = loc_policy.get_column_policy ();
1028 : 1792 : label_text text
1029 : : = column_policy.get_location_text (exploc,
1030 : 1792 : loc_policy.show_column_p (),
1031 : 1792 : pp_show_color (pp));
1032 : 1792 : pp_string (pp, text.get ());
1033 : 1792 : pp_newline (pp);
1034 : 1792 : }
1035 : :
1036 : : /* Interface to specify diagnostic kind overrides. Returns the
1037 : : previous setting, or DK_UNSPECIFIED if the parameters are out of
1038 : : range. If OPTION_ID is zero, the new setting is for all the
1039 : : diagnostics. */
1040 : : diagnostic_t
1041 : 4027176 : diagnostic_option_classifier::
1042 : : classify_diagnostic (const diagnostic_context *context,
1043 : : diagnostic_option_id option_id,
1044 : : diagnostic_t new_kind,
1045 : : location_t where)
1046 : : {
1047 : 4027176 : diagnostic_t old_kind;
1048 : :
1049 : 4027176 : if (option_id.m_idx < 0
1050 : 4027176 : || option_id.m_idx >= m_n_opts
1051 : 4027176 : || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
1052 : : return DK_UNSPECIFIED;
1053 : :
1054 : 4027176 : old_kind = m_classify_diagnostic[option_id.m_idx];
1055 : :
1056 : : /* Handle pragmas separately, since we need to keep track of *where*
1057 : : the pragmas were. */
1058 : 4027176 : if (where != UNKNOWN_LOCATION)
1059 : : {
1060 : 2994131 : unsigned i;
1061 : :
1062 : : /* Record the command-line status, so we can reset it back on DK_POP. */
1063 : 2994131 : if (old_kind == DK_UNSPECIFIED)
1064 : : {
1065 : 307220 : old_kind = (!context->option_enabled_p (option_id)
1066 : 307220 : ? DK_IGNORED : DK_ANY);
1067 : 307220 : m_classify_diagnostic[option_id.m_idx] = old_kind;
1068 : : }
1069 : :
1070 : 2994131 : diagnostic_classification_change_t *p;
1071 : 98299855 : FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
1072 : 95030431 : if (p->option == option_id.m_idx)
1073 : : {
1074 : 2681288 : old_kind = p->kind;
1075 : 2681288 : break;
1076 : : }
1077 : :
1078 : 2994131 : diagnostic_classification_change_t v
1079 : 2994131 : = { where, option_id.m_idx, new_kind };
1080 : 2994131 : m_classification_history.safe_push (v);
1081 : : }
1082 : : else
1083 : 1033045 : m_classify_diagnostic[option_id.m_idx] = new_kind;
1084 : :
1085 : : return old_kind;
1086 : : }
1087 : :
1088 : : /* Helper function for print_parseable_fixits. Print TEXT to PP, obeying the
1089 : : escaping rules for -fdiagnostics-parseable-fixits. */
1090 : :
1091 : : static void
1092 : 105 : print_escaped_string (pretty_printer *pp, const char *text)
1093 : : {
1094 : 105 : gcc_assert (pp);
1095 : 105 : gcc_assert (text);
1096 : :
1097 : 105 : pp_character (pp, '"');
1098 : 3786 : for (const char *ch = text; *ch; ch++)
1099 : : {
1100 : 3681 : switch (*ch)
1101 : : {
1102 : 3 : case '\\':
1103 : : /* Escape backslash as two backslashes. */
1104 : 3 : pp_string (pp, "\\\\");
1105 : 3 : break;
1106 : 3 : case '\t':
1107 : : /* Escape tab as "\t". */
1108 : 3 : pp_string (pp, "\\t");
1109 : 3 : break;
1110 : 6 : case '\n':
1111 : : /* Escape newline as "\n". */
1112 : 6 : pp_string (pp, "\\n");
1113 : 6 : break;
1114 : 3 : case '"':
1115 : : /* Escape doublequotes as \". */
1116 : 3 : pp_string (pp, "\\\"");
1117 : 3 : break;
1118 : 3666 : default:
1119 : 3666 : if (ISPRINT (*ch))
1120 : 3660 : pp_character (pp, *ch);
1121 : : else
1122 : : /* Use octal for non-printable chars. */
1123 : : {
1124 : 6 : unsigned char c = (*ch & 0xff);
1125 : 6 : pp_printf (pp, "\\%o%o%o", (c / 64), (c / 8) & 007, c & 007);
1126 : : }
1127 : : break;
1128 : : }
1129 : : }
1130 : 105 : pp_character (pp, '"');
1131 : 105 : }
1132 : :
1133 : : /* Implementation of -fdiagnostics-parseable-fixits and
1134 : : GCC_EXTRA_DIAGNOSTIC_OUTPUT.
1135 : : Print a machine-parseable version of all fixits in RICHLOC to PP,
1136 : : using COLUMN_UNIT to express columns.
1137 : : Use TABSTOP when handling DIAGNOSTICS_COLUMN_UNIT_DISPLAY. */
1138 : :
1139 : : static void
1140 : 39 : print_parseable_fixits (file_cache &fc,
1141 : : pretty_printer *pp, rich_location *richloc,
1142 : : enum diagnostics_column_unit column_unit,
1143 : : int tabstop)
1144 : : {
1145 : 39 : gcc_assert (pp);
1146 : 39 : gcc_assert (richloc);
1147 : :
1148 : 39 : char *saved_prefix = pp_take_prefix (pp);
1149 : 39 : pp_set_prefix (pp, NULL);
1150 : :
1151 : 78 : for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++)
1152 : : {
1153 : 39 : const fixit_hint *hint = richloc->get_fixit_hint (i);
1154 : 39 : location_t start_loc = hint->get_start_loc ();
1155 : 39 : expanded_location start_exploc = expand_location (start_loc);
1156 : 39 : pp_string (pp, "fix-it:");
1157 : 39 : print_escaped_string (pp, start_exploc.file);
1158 : : /* For compatibility with clang, print as a half-open range. */
1159 : 39 : location_t next_loc = hint->get_next_loc ();
1160 : 39 : expanded_location next_exploc = expand_location (next_loc);
1161 : 39 : int start_col
1162 : 39 : = convert_column_unit (fc, column_unit, tabstop, start_exploc);
1163 : 39 : int next_col
1164 : 39 : = convert_column_unit (fc, column_unit, tabstop, next_exploc);
1165 : 39 : pp_printf (pp, ":{%i:%i-%i:%i}:",
1166 : : start_exploc.line, start_col,
1167 : : next_exploc.line, next_col);
1168 : 39 : print_escaped_string (pp, hint->get_string ());
1169 : 39 : pp_newline (pp);
1170 : : }
1171 : :
1172 : 39 : pp_set_prefix (pp, saved_prefix);
1173 : 39 : }
1174 : :
1175 : : /* Update the inlining info in this context for a DIAGNOSTIC. */
1176 : :
1177 : : void
1178 : 90917940 : diagnostic_context::get_any_inlining_info (diagnostic_info *diagnostic)
1179 : : {
1180 : 90917940 : auto &ilocs = diagnostic->m_iinfo.m_ilocs;
1181 : :
1182 : 90917940 : if (m_set_locations_cb)
1183 : : /* Retrieve the locations into which the expression about to be
1184 : : diagnosed has been inlined, including those of all the callers
1185 : : all the way down the inlining stack. */
1186 : 90916574 : m_set_locations_cb (this, diagnostic);
1187 : : else
1188 : : {
1189 : : /* When there's no callback use just the one location provided
1190 : : by the caller of the diagnostic function. */
1191 : 1366 : location_t loc = diagnostic_location (diagnostic);
1192 : 1366 : ilocs.safe_push (loc);
1193 : 1366 : diagnostic->m_iinfo.m_allsyslocs = in_system_header_at (loc);
1194 : : }
1195 : 90917940 : }
1196 : :
1197 : : /* Update the kind of DIAGNOSTIC based on its location(s), including
1198 : : any of those in its inlining stack, relative to any
1199 : : #pragma GCC diagnostic
1200 : : directives recorded within this object.
1201 : :
1202 : : Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
1203 : : otherwise. */
1204 : :
1205 : : diagnostic_t
1206 : 1971218 : diagnostic_option_classifier::
1207 : : update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
1208 : : {
1209 : 2339016 : if (m_classification_history.is_empty ())
1210 : : return DK_UNSPECIFIED;
1211 : :
1212 : : /* Iterate over the locations, checking the diagnostic disposition
1213 : : for the diagnostic at each. If it's explicitly set as opposed
1214 : : to unspecified, update the disposition for this instance of
1215 : : the diagnostic and return it. */
1216 : 6000677 : for (location_t loc: diagnostic->m_iinfo.m_ilocs)
1217 : : {
1218 : : /* FIXME: Stupid search. Optimize later. */
1219 : 1877747 : unsigned int i;
1220 : 1877747 : diagnostic_classification_change_t *p;
1221 : 42585837 : FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
1222 : : {
1223 : 39972132 : location_t pragloc = p->location;
1224 : 39972132 : if (!linemap_location_before_p (line_table, pragloc, loc))
1225 : 38462364 : continue;
1226 : :
1227 : 27380666 : if (p->kind == (int) DK_POP)
1228 : : {
1229 : : /* Move on to the next region. */
1230 : 25809291 : i = p->option;
1231 : 25809291 : continue;
1232 : : }
1233 : :
1234 : 1571375 : diagnostic_option_id option = p->option;
1235 : : /* The option 0 is for all the diagnostics. */
1236 : 1571375 : if (option == 0 || option == diagnostic->option_id)
1237 : : {
1238 : 1509768 : diagnostic_t kind = p->kind;
1239 : 1509768 : if (kind != DK_UNSPECIFIED)
1240 : 1509768 : diagnostic->kind = kind;
1241 : 1509768 : return kind;
1242 : : }
1243 : : }
1244 : : }
1245 : :
1246 : : return DK_UNSPECIFIED;
1247 : : }
1248 : :
1249 : : /* Generate a URL string describing CWE. The caller is responsible for
1250 : : freeing the string. */
1251 : :
1252 : : char *
1253 : 18 : get_cwe_url (int cwe)
1254 : : {
1255 : 18 : return xasprintf ("https://cwe.mitre.org/data/definitions/%i.html", cwe);
1256 : : }
1257 : :
1258 : : /* Returns whether a DIAGNOSTIC should be printed, and adjusts diagnostic->kind
1259 : : as appropriate for #pragma GCC diagnostic and -Werror=foo. */
1260 : :
1261 : : bool
1262 : 90917940 : diagnostic_context::diagnostic_enabled (diagnostic_info *diagnostic)
1263 : : {
1264 : : /* Update the inlining stack for this diagnostic. */
1265 : 90917940 : get_any_inlining_info (diagnostic);
1266 : :
1267 : : /* Diagnostics with no option or -fpermissive are always enabled. */
1268 : 90917940 : if (!diagnostic->option_id.m_idx
1269 : 90917940 : || diagnostic->option_id == m_opt_permissive)
1270 : : return true;
1271 : :
1272 : : /* This tests if the user provided the appropriate -Wfoo or
1273 : : -Wno-foo option. */
1274 : 89242243 : if (!option_enabled_p (diagnostic->option_id))
1275 : : return false;
1276 : :
1277 : : /* This tests for #pragma diagnostic changes. */
1278 : 1971218 : diagnostic_t diag_class
1279 : 1971218 : = m_option_classifier.update_effective_level_from_pragmas (diagnostic);
1280 : :
1281 : : /* This tests if the user provided the appropriate -Werror=foo
1282 : : option. */
1283 : 1971218 : if (diag_class == DK_UNSPECIFIED
1284 : 2432668 : && !option_unspecified_p (diagnostic->option_id))
1285 : : {
1286 : 9778 : const diagnostic_t new_kind
1287 : 9778 : = m_option_classifier.get_current_override (diagnostic->option_id);
1288 : 9778 : if (new_kind != DK_ANY)
1289 : : /* DK_ANY means the diagnostic is not to be ignored, but we don't want
1290 : : to change it specifically to DK_ERROR or DK_WARNING; we want to
1291 : : preserve whatever the caller has specified. */
1292 : 6706 : diagnostic->kind = new_kind;
1293 : : }
1294 : :
1295 : : /* This allows for future extensions, like temporarily disabling
1296 : : warnings for ranges of source code. */
1297 : 1971218 : if (diagnostic->kind == DK_IGNORED)
1298 : : return false;
1299 : :
1300 : : return true;
1301 : : }
1302 : :
1303 : : /* Returns whether warning OPTION_ID is enabled at LOC. */
1304 : :
1305 : : bool
1306 : 272532 : diagnostic_context::warning_enabled_at (location_t loc,
1307 : : diagnostic_option_id option_id)
1308 : : {
1309 : 534190 : if (!diagnostic_report_warnings_p (this, loc))
1310 : 93949 : return false;
1311 : :
1312 : 178583 : rich_location richloc (line_table, loc);
1313 : 178583 : diagnostic_info diagnostic = {};
1314 : 178583 : diagnostic.option_id = option_id;
1315 : 178583 : diagnostic.richloc = &richloc;
1316 : 178583 : diagnostic.message.m_richloc = &richloc;
1317 : 178583 : diagnostic.kind = DK_WARNING;
1318 : 178583 : return diagnostic_enabled (&diagnostic);
1319 : 178583 : }
1320 : :
1321 : : /* Emit a diagnostic within a diagnostic group on this context. */
1322 : :
1323 : : bool
1324 : 8 : diagnostic_context::
1325 : : emit_diagnostic_with_group (diagnostic_t kind,
1326 : : rich_location &richloc,
1327 : : const diagnostic_metadata *metadata,
1328 : : diagnostic_option_id option_id,
1329 : : const char *gmsgid, ...)
1330 : : {
1331 : 8 : begin_group ();
1332 : :
1333 : 8 : va_list ap;
1334 : 8 : va_start (ap, gmsgid);
1335 : 8 : bool ret = emit_diagnostic_with_group_va (kind, richloc, metadata, option_id,
1336 : : gmsgid, &ap);
1337 : 8 : va_end (ap);
1338 : :
1339 : 8 : end_group ();
1340 : :
1341 : 8 : return ret;
1342 : : }
1343 : :
1344 : : /* As above, but taking a va_list *. */
1345 : :
1346 : : bool
1347 : 8 : diagnostic_context::
1348 : : emit_diagnostic_with_group_va (diagnostic_t kind,
1349 : : rich_location &richloc,
1350 : : const diagnostic_metadata *metadata,
1351 : : diagnostic_option_id option_id,
1352 : : const char *gmsgid, va_list *ap)
1353 : : {
1354 : 8 : begin_group ();
1355 : :
1356 : 8 : bool ret = diagnostic_impl (&richloc, metadata, option_id,
1357 : : gmsgid, ap, kind);
1358 : :
1359 : 8 : end_group ();
1360 : :
1361 : 8 : return ret;
1362 : : }
1363 : :
1364 : : /* Report a diagnostic message (an error or a warning) as specified by
1365 : : this diagnostic_context.
1366 : : front-end independent format specifiers are exactly those described
1367 : : in the documentation of output_format.
1368 : : Return true if a diagnostic was printed, false otherwise. */
1369 : :
1370 : : bool
1371 : 93994243 : diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
1372 : : {
1373 : 93994243 : diagnostic_t orig_diag_kind = diagnostic->kind;
1374 : :
1375 : : /* Every call to report_diagnostic should be within a
1376 : : begin_group/end_group pair so that output formats can reliably
1377 : : flush diagnostics with on_end_group when the topmost group is ended. */
1378 : 93994243 : gcc_assert (m_diagnostic_groups.m_group_nesting_depth > 0);
1379 : :
1380 : : /* Give preference to being able to inhibit warnings, before they
1381 : : get reclassified to something else. */
1382 : 93994243 : bool was_warning = (diagnostic->kind == DK_WARNING
1383 : 93994243 : || diagnostic->kind == DK_PEDWARN);
1384 : 93994243 : if (was_warning && m_inhibit_warnings)
1385 : : return false;
1386 : :
1387 : 90739357 : if (m_adjust_diagnostic_info)
1388 : 84407793 : m_adjust_diagnostic_info (this, diagnostic);
1389 : :
1390 : 90739357 : if (diagnostic->kind == DK_PEDWARN)
1391 : : {
1392 : 1030594 : diagnostic->kind = m_pedantic_errors ? DK_ERROR : DK_WARNING;
1393 : :
1394 : : /* We do this to avoid giving the message for -pedantic-errors. */
1395 : 1030594 : orig_diag_kind = diagnostic->kind;
1396 : : }
1397 : :
1398 : 90739357 : if (diagnostic->kind == DK_NOTE && m_inhibit_notes_p)
1399 : : return false;
1400 : :
1401 : : /* If the user requested that warnings be treated as errors, so be
1402 : : it. Note that we do this before the next block so that
1403 : : individual warnings can be overridden back to warnings with
1404 : : -Wno-error=*. */
1405 : 90739357 : if (m_warning_as_error_requested
1406 : 238538 : && diagnostic->kind == DK_WARNING)
1407 : 203311 : diagnostic->kind = DK_ERROR;
1408 : :
1409 : 90739357 : diagnostic->message.m_data = &diagnostic->x_data;
1410 : :
1411 : : /* Check to see if the diagnostic is enabled at the location and
1412 : : not disabled by #pragma GCC diagnostic anywhere along the inlining
1413 : : stack. . */
1414 : 90739357 : if (!diagnostic_enabled (diagnostic))
1415 : : return false;
1416 : :
1417 : 1975580 : if ((was_warning || diagnostic->kind == DK_WARNING)
1418 : 589251 : && ((!m_warn_system_headers
1419 : 588908 : && diagnostic->m_iinfo.m_allsyslocs)
1420 : 108745 : || m_inhibit_warnings))
1421 : : /* Bail if the warning is not to be reported because all locations in the
1422 : : inlining stack (if there is one) are in system headers. */
1423 : : return false;
1424 : :
1425 : 1495059 : if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
1426 : 1387838 : check_max_errors (false);
1427 : :
1428 : 1495055 : if (m_lock > 0)
1429 : : {
1430 : : /* If we're reporting an ICE in the middle of some other error,
1431 : : try to flush out the previous error, then let this one
1432 : : through. Don't do this more than once. */
1433 : 0 : if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
1434 : 0 : && m_lock == 1)
1435 : 0 : pp_newline_and_flush (m_reference_printer);
1436 : : else
1437 : 0 : error_recursion ();
1438 : : }
1439 : :
1440 : 1495055 : m_lock++;
1441 : :
1442 : 1495055 : if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
1443 : : {
1444 : : /* When not checking, ICEs are converted to fatal errors when an
1445 : : error has already occurred. This is counteracted by
1446 : : abort_on_error. */
1447 : 24 : if (!CHECKING_P
1448 : : && (diagnostic_count (DK_ERROR) > 0
1449 : : || diagnostic_count (DK_SORRY) > 0)
1450 : : && !m_abort_on_error)
1451 : : {
1452 : : expanded_location s
1453 : : = expand_location (diagnostic_location (diagnostic));
1454 : : fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
1455 : : s.file, s.line);
1456 : : exit (ICE_EXIT_CODE);
1457 : : }
1458 : 24 : if (m_internal_error)
1459 : 24 : (*m_internal_error) (this,
1460 : : diagnostic->message.m_format_spec,
1461 : : diagnostic->message.m_args_ptr);
1462 : : }
1463 : :
1464 : : /* Increment the counter for the appropriate diagnostic kind, either
1465 : : within this context, or within the diagnostic_buffer. */
1466 : 1495055 : {
1467 : 2990110 : const diagnostic_t kind_for_count =
1468 : 1283426 : ((diagnostic->kind == DK_ERROR && orig_diag_kind == DK_WARNING)
1469 : 1495055 : ? DK_WERROR
1470 : : : diagnostic->kind);
1471 : 1495055 : diagnostic_counters &counters
1472 : 1495055 : = (m_diagnostic_buffer
1473 : : ? m_diagnostic_buffer->m_diagnostic_counters
1474 : : : m_diagnostic_counters);
1475 : 1495055 : ++counters.m_count_for_kind[kind_for_count];
1476 : : }
1477 : :
1478 : : /* Is this the initial diagnostic within the stack of groups? */
1479 : 1495055 : if (m_diagnostic_groups.m_emission_count == 0)
1480 : 5606121 : for (auto sink : m_output_sinks)
1481 : 1401534 : sink->on_begin_group ();
1482 : 1495055 : m_diagnostic_groups.m_emission_count++;
1483 : :
1484 : 1495055 : va_list *orig_args = diagnostic->message.m_args_ptr;
1485 : 5980235 : for (auto sink : m_output_sinks)
1486 : : {
1487 : : /* Formatting the message is done per-output-format,
1488 : : so that each output format gets its own set of pp_token_lists
1489 : : to work with.
1490 : :
1491 : : Run phases 1 and 2 of formatting the message before calling
1492 : : the format's on_report_diagnostic.
1493 : : In particular, some format codes may have side-effects here which
1494 : : need to happen before sending the diagnostic to the output format.
1495 : : For example, Fortran's %C and %L formatting codes populate the
1496 : : rich_location.
1497 : : Such side-effects must be idempotent, since they are run per
1498 : : output-format.
1499 : :
1500 : : Make a duplicate of the varargs for each call to pp_format,
1501 : : so that each has its own set to consume. */
1502 : 1495072 : va_list copied_args;
1503 : 1495072 : va_copy (copied_args, *orig_args);
1504 : 1495072 : diagnostic->message.m_args_ptr = &copied_args;
1505 : 1495072 : pp_format (sink->get_printer (), &diagnostic->message);
1506 : 1495072 : va_end (copied_args);
1507 : :
1508 : : /* Call vfunc in the output format. This is responsible for
1509 : : phase 3 of formatting, and for printing the result. */
1510 : 1495072 : sink->on_report_diagnostic (*diagnostic, orig_diag_kind);
1511 : : }
1512 : :
1513 : 1495053 : switch (m_extra_output_kind)
1514 : : {
1515 : : default:
1516 : : break;
1517 : 15 : case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1:
1518 : 15 : print_parseable_fixits (get_file_cache (),
1519 : : m_reference_printer, diagnostic->richloc,
1520 : : DIAGNOSTICS_COLUMN_UNIT_BYTE,
1521 : : m_tabstop);
1522 : 15 : pp_flush (m_reference_printer);
1523 : 15 : break;
1524 : 6 : case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2:
1525 : 6 : print_parseable_fixits (get_file_cache (),
1526 : : m_reference_printer, diagnostic->richloc,
1527 : : DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
1528 : : m_tabstop);
1529 : 6 : pp_flush (m_reference_printer);
1530 : 6 : break;
1531 : : }
1532 : 1495053 : if (m_diagnostic_buffer == nullptr
1533 : 1165980 : || diagnostic->kind == DK_ICE
1534 : 1165980 : || diagnostic->kind == DK_ICE_NOBT)
1535 : 329073 : action_after_output (diagnostic->kind);
1536 : 1494347 : diagnostic->x_data = NULL;
1537 : :
1538 : 1494347 : if (m_edit_context_ptr)
1539 : 60 : if (diagnostic->richloc->fixits_can_be_auto_applied_p ())
1540 : 58 : if (!m_diagnostic_buffer)
1541 : 58 : m_edit_context_ptr->add_fixits (diagnostic->richloc);
1542 : :
1543 : 1494347 : m_lock--;
1544 : :
1545 : 1494347 : if (!m_diagnostic_buffer)
1546 : 1313485 : for (auto sink : m_output_sinks)
1547 : 328384 : sink->after_diagnostic (*diagnostic);
1548 : :
1549 : : return true;
1550 : : }
1551 : :
1552 : : void
1553 : 0 : diagnostic_context::report_verbatim (text_info &text)
1554 : : {
1555 : 0 : va_list *orig_args = text.m_args_ptr;
1556 : 0 : for (auto sink : m_output_sinks)
1557 : : {
1558 : 0 : va_list copied_args;
1559 : 0 : va_copy (copied_args, *orig_args);
1560 : 0 : text.m_args_ptr = &copied_args;
1561 : 0 : sink->on_report_verbatim (text);
1562 : 0 : va_end (copied_args);
1563 : : }
1564 : 0 : }
1565 : :
1566 : : /* Get the number of digits in the decimal representation of VALUE. */
1567 : :
1568 : : int
1569 : 72883 : num_digits (int value)
1570 : : {
1571 : : /* Perhaps simpler to use log10 for this, but doing it this way avoids
1572 : : using floating point. */
1573 : 72883 : gcc_assert (value >= 0);
1574 : :
1575 : 72883 : if (value == 0)
1576 : : return 1;
1577 : :
1578 : : int digits = 0;
1579 : 227605 : while (value > 0)
1580 : : {
1581 : 154763 : digits++;
1582 : 154763 : value /= 10;
1583 : : }
1584 : : return digits;
1585 : : }
1586 : :
1587 : : /* Given a partial pathname as input, return another pathname that
1588 : : shares no directory elements with the pathname of __FILE__. This
1589 : : is used by fancy_abort() to print `internal compiler error in expr.cc'
1590 : : instead of `internal compiler error in ../../GCC/gcc/expr.cc'. */
1591 : :
1592 : : const char *
1593 : 10 : trim_filename (const char *name)
1594 : : {
1595 : 10 : static const char this_file[] = __FILE__;
1596 : 10 : const char *p = name, *q = this_file;
1597 : :
1598 : : /* First skip any "../" in each filename. This allows us to give a proper
1599 : : reference to a file in a subdirectory. */
1600 : 10 : while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2]))
1601 : 0 : p += 3;
1602 : :
1603 : : while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2]))
1604 : : q += 3;
1605 : :
1606 : : /* Now skip any parts the two filenames have in common. */
1607 : 470 : while (*p == *q && *p != 0 && *q != 0)
1608 : 460 : p++, q++;
1609 : :
1610 : : /* Now go backwards until the previous directory separator. */
1611 : 10 : while (p > name && !IS_DIR_SEPARATOR (p[-1]))
1612 : 0 : p--;
1613 : :
1614 : 10 : return p;
1615 : : }
1616 : :
1617 : : /* Implement emit_diagnostic, inform, warning, warning_at, pedwarn,
1618 : : permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
1619 : : and internal_error_no_backtrace, as documented and defined below. */
1620 : : bool
1621 : 89606169 : diagnostic_context::diagnostic_impl (rich_location *richloc,
1622 : : const diagnostic_metadata *metadata,
1623 : : diagnostic_option_id option_id,
1624 : : const char *gmsgid,
1625 : : va_list *ap, diagnostic_t kind)
1626 : : {
1627 : 89606169 : diagnostic_info diagnostic;
1628 : 89606169 : if (kind == DK_PERMERROR)
1629 : : {
1630 : 18130 : diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
1631 : 18130 : m_permissive ? DK_WARNING : DK_ERROR);
1632 : 18130 : diagnostic.option_id = (option_id.m_idx != -1 ? option_id : m_opt_permissive);
1633 : : }
1634 : : else
1635 : : {
1636 : 89588039 : diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
1637 : 89588039 : if (kind == DK_WARNING || kind == DK_PEDWARN)
1638 : 89379730 : diagnostic.option_id = option_id;
1639 : : }
1640 : 89606169 : diagnostic.metadata = metadata;
1641 : 89606169 : return report_diagnostic (&diagnostic);
1642 : 89605821 : }
1643 : :
1644 : : /* Implement inform_n, warning_n, and error_n, as documented and
1645 : : defined below. */
1646 : : bool
1647 : 11636 : diagnostic_context::diagnostic_n_impl (rich_location *richloc,
1648 : : const diagnostic_metadata *metadata,
1649 : : diagnostic_option_id option_id,
1650 : : unsigned HOST_WIDE_INT n,
1651 : : const char *singular_gmsgid,
1652 : : const char *plural_gmsgid,
1653 : : va_list *ap, diagnostic_t kind)
1654 : : {
1655 : 11636 : diagnostic_info diagnostic;
1656 : 11636 : unsigned long gtn;
1657 : :
1658 : 11636 : if (sizeof n <= sizeof gtn)
1659 : 11636 : gtn = n;
1660 : : else
1661 : : /* Use the largest number ngettext can handle, otherwise
1662 : : preserve the six least significant decimal digits for
1663 : : languages where the plural form depends on them. */
1664 : : gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU;
1665 : :
1666 : 11636 : const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
1667 : 11636 : diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
1668 : 11636 : if (kind == DK_WARNING)
1669 : 4467 : diagnostic.option_id = option_id;
1670 : 11636 : diagnostic.metadata = metadata;
1671 : 11636 : return report_diagnostic (&diagnostic);
1672 : 11636 : }
1673 : :
1674 : :
1675 : : /* Emit DIAGRAM to this context, respecting the output format. */
1676 : :
1677 : : void
1678 : 86 : diagnostic_context::emit_diagram (const diagnostic_diagram &diagram)
1679 : : {
1680 : 86 : if (m_diagrams.m_theme == nullptr)
1681 : : return;
1682 : :
1683 : 336 : for (auto sink : m_output_sinks)
1684 : 84 : sink->on_diagram (diagram);
1685 : : }
1686 : :
1687 : : /* Inform the user that an error occurred while trying to report some
1688 : : other error. This indicates catastrophic internal inconsistencies,
1689 : : so give up now. But do try to flush out the previous error.
1690 : : This mustn't use internal_error, that will cause infinite recursion. */
1691 : :
1692 : : void
1693 : 0 : diagnostic_context::error_recursion ()
1694 : : {
1695 : 0 : if (m_lock < 3)
1696 : 0 : pp_newline_and_flush (m_reference_printer);
1697 : :
1698 : 0 : fnotice (stderr,
1699 : : "internal compiler error: error reporting routines re-entered.\n");
1700 : :
1701 : : /* Call action_after_output to get the "please submit a bug report"
1702 : : message. */
1703 : 0 : action_after_output (DK_ICE);
1704 : :
1705 : : /* Do not use gcc_unreachable here; that goes through internal_error
1706 : : and therefore would cause infinite recursion. */
1707 : 0 : real_abort ();
1708 : : }
1709 : :
1710 : : /* Report an internal compiler error in a friendly manner. This is
1711 : : the function that gets called upon use of abort() in the source
1712 : : code generally, thanks to a special macro. */
1713 : :
1714 : : void
1715 : 10 : fancy_abort (const char *file, int line, const char *function)
1716 : : {
1717 : : /* If fancy_abort is called before the diagnostic subsystem is initialized,
1718 : : internal_error will crash internally in a way that prevents a
1719 : : useful message reaching the user.
1720 : : This can happen with libgccjit in the case of gcc_assert failures
1721 : : that occur outside of the libgccjit mutex that guards the rest of
1722 : : gcc's state, including global_dc (when global_dc may not be
1723 : : initialized yet, or might be in use by another thread).
1724 : : Handle such cases as gracefully as possible by falling back to a
1725 : : minimal abort handler that only relies on i18n. */
1726 : 10 : if (global_dc->get_reference_printer () == nullptr)
1727 : : {
1728 : : /* Print the error message. */
1729 : 0 : fnotice (stderr, diagnostic_kind_text[DK_ICE]);
1730 : 0 : fnotice (stderr, "in %s, at %s:%d", function, trim_filename (file), line);
1731 : 0 : fputc ('\n', stderr);
1732 : :
1733 : : /* Attempt to print a backtrace. */
1734 : 0 : struct backtrace_state *state
1735 : 0 : = backtrace_create_state (NULL, 0, bt_err_callback, NULL);
1736 : 0 : int count = 0;
1737 : 0 : if (state != NULL)
1738 : 0 : backtrace_full (state, 2, bt_callback, bt_err_callback,
1739 : : (void *) &count);
1740 : :
1741 : : /* We can't call warn_if_plugins or emergency_dump_function as these
1742 : : rely on GCC state that might not be initialized, or might be in
1743 : : use by another thread. */
1744 : :
1745 : : /* Abort the process. */
1746 : 0 : real_abort ();
1747 : : }
1748 : :
1749 : 10 : internal_error ("in %s, at %s:%d", function, trim_filename (file), line);
1750 : : }
1751 : :
1752 : : /* class diagnostic_context. */
1753 : :
1754 : : void
1755 : 814162779 : diagnostic_context::begin_group ()
1756 : : {
1757 : 814162779 : m_diagnostic_groups.m_group_nesting_depth++;
1758 : 814162779 : }
1759 : :
1760 : : void
1761 : 814162773 : diagnostic_context::end_group ()
1762 : : {
1763 : 814162773 : if (--m_diagnostic_groups.m_group_nesting_depth == 0)
1764 : : {
1765 : : /* Handle the case where we've popped the final diagnostic group.
1766 : : If any diagnostics were emitted, give the context a chance
1767 : : to do something. */
1768 : 811874179 : if (m_diagnostic_groups.m_emission_count > 0)
1769 : 5606113 : for (auto sink : m_output_sinks)
1770 : 1401532 : sink->on_end_group ();
1771 : 811874179 : m_diagnostic_groups.m_emission_count = 0;
1772 : : }
1773 : 814162773 : }
1774 : :
1775 : : void
1776 : 23850 : diagnostic_context::push_nesting_level ()
1777 : : {
1778 : 23850 : ++m_diagnostic_groups.m_diagnostic_nesting_level;
1779 : 23850 : }
1780 : :
1781 : : void
1782 : 23850 : diagnostic_context::pop_nesting_level ()
1783 : : {
1784 : 23850 : --m_diagnostic_groups.m_diagnostic_nesting_level;
1785 : 23850 : }
1786 : :
1787 : : void
1788 : 0 : diagnostic_output_format::dump (FILE *out, int indent) const
1789 : : {
1790 : 0 : fprintf (out, "%*sprinter:\n", indent, "");
1791 : 0 : m_printer->dump (out, indent + 2);
1792 : 0 : }
1793 : :
1794 : : void
1795 : 0 : diagnostic_output_format::on_report_verbatim (text_info &)
1796 : : {
1797 : : /* No-op. */
1798 : 0 : }
1799 : :
1800 : : /* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for
1801 : : file-based output formats. */
1802 : :
1803 : : void
1804 : 130 : diagnostic_output_format_init (diagnostic_context &context,
1805 : : const char *main_input_filename_,
1806 : : const char *base_file_name,
1807 : : enum diagnostics_output_format format,
1808 : : bool json_formatting)
1809 : : {
1810 : 130 : switch (format)
1811 : : {
1812 : 0 : default:
1813 : 0 : gcc_unreachable ();
1814 : : case DIAGNOSTICS_OUTPUT_FORMAT_TEXT:
1815 : : /* The default; do nothing. */
1816 : : break;
1817 : :
1818 : 32 : case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR:
1819 : 32 : diagnostic_output_format_init_json_stderr (context,
1820 : : json_formatting);
1821 : 32 : break;
1822 : :
1823 : 12 : case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE:
1824 : 12 : diagnostic_output_format_init_json_file (context,
1825 : : json_formatting,
1826 : : base_file_name);
1827 : 12 : break;
1828 : :
1829 : 0 : case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR:
1830 : 0 : diagnostic_output_format_init_sarif_stderr (context,
1831 : : line_table,
1832 : : main_input_filename_,
1833 : : json_formatting,
1834 : : sarif_version::v2_1_0);
1835 : 0 : break;
1836 : :
1837 : 86 : case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
1838 : 86 : diagnostic_output_format_init_sarif_file (context,
1839 : : line_table,
1840 : : main_input_filename_,
1841 : : json_formatting,
1842 : : sarif_version::v2_1_0,
1843 : : base_file_name);
1844 : 86 : break;
1845 : : }
1846 : 130 : }
1847 : :
1848 : : /* Initialize this context's m_diagrams based on CHARSET.
1849 : : Specifically, make a text_art::theme object for m_diagrams.m_theme,
1850 : : (or NULL for "no diagrams"). */
1851 : :
1852 : : void
1853 : 1541679 : diagnostic_context::
1854 : : set_text_art_charset (enum diagnostic_text_art_charset charset)
1855 : : {
1856 : 1541679 : delete m_diagrams.m_theme;
1857 : 1541679 : switch (charset)
1858 : : {
1859 : 0 : default:
1860 : 0 : gcc_unreachable ();
1861 : :
1862 : 852948 : case DIAGNOSTICS_TEXT_ART_CHARSET_NONE:
1863 : 852948 : m_diagrams.m_theme = nullptr;
1864 : 852948 : break;
1865 : :
1866 : 604326 : case DIAGNOSTICS_TEXT_ART_CHARSET_ASCII:
1867 : 604326 : m_diagrams.m_theme = new text_art::ascii_theme ();
1868 : 604326 : break;
1869 : :
1870 : 295 : case DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE:
1871 : 295 : m_diagrams.m_theme = new text_art::unicode_theme ();
1872 : 295 : break;
1873 : :
1874 : 84110 : case DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI:
1875 : 84110 : m_diagrams.m_theme = new text_art::emoji_theme ();
1876 : 84110 : break;
1877 : : }
1878 : 1541679 : }
1879 : :
1880 : : /* If BUFFER is non-null, use BUFFER as the active diagnostic_buffer on
1881 : : this context. BUFFER is borrowed.
1882 : :
1883 : : If BUFFER is null, stop any buffering on this context until the next call
1884 : : to this function. */
1885 : :
1886 : : void
1887 : 2628893 : diagnostic_context::set_diagnostic_buffer (diagnostic_buffer *buffer)
1888 : : {
1889 : : /* We don't allow changing buffering within a diagnostic group
1890 : : (to simplify handling of buffered diagnostics within the
1891 : : diagnostic_format implementations). */
1892 : 2628893 : gcc_assert (m_diagnostic_groups.m_group_nesting_depth == 0);
1893 : :
1894 : : /* Likewise, for simplicity, we only allow changing buffers
1895 : : at nesting level 0. */
1896 : 2628893 : gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);
1897 : :
1898 : 2628893 : m_diagnostic_buffer = buffer;
1899 : :
1900 : 2628893 : if (buffer)
1901 : : {
1902 : 1165998 : buffer->ensure_per_format_buffers ();
1903 : 1165998 : gcc_assert (buffer->m_per_format_buffers);
1904 : 3497994 : gcc_assert (buffer->m_per_format_buffers->length ()
1905 : : == m_output_sinks.length ());
1906 : 2331996 : for (unsigned idx = 0; idx < m_output_sinks.length (); ++idx)
1907 : : {
1908 : 1165998 : auto sink = m_output_sinks[idx];
1909 : 1165998 : auto per_format_buffer = (*buffer->m_per_format_buffers)[idx];
1910 : 1165998 : sink->set_buffer (per_format_buffer);
1911 : : }
1912 : : }
1913 : : else
1914 : 5851585 : for (auto sink : m_output_sinks)
1915 : 1462900 : sink->set_buffer (nullptr);
1916 : 2628893 : }
1917 : :
1918 : : /* Clear BUFFER without flushing it. */
1919 : :
1920 : : void
1921 : 22441357 : diagnostic_context::clear_diagnostic_buffer (diagnostic_buffer &buffer)
1922 : : {
1923 : 22441357 : if (buffer.m_per_format_buffers)
1924 : 19413760 : for (auto per_format_buffer : *buffer.m_per_format_buffers)
1925 : 4853440 : per_format_buffer->clear ();
1926 : :
1927 : 22441357 : buffer.m_diagnostic_counters.clear ();
1928 : :
1929 : : /* We need to reset last_location, otherwise we may skip caret lines
1930 : : when we actually give a diagnostic. */
1931 : 22441357 : m_last_location = UNKNOWN_LOCATION;
1932 : 22441357 : }
1933 : :
1934 : : /* Flush the diagnostics in BUFFER to this context, clearing BUFFER. */
1935 : :
1936 : : void
1937 : 7131 : diagnostic_context::flush_diagnostic_buffer (diagnostic_buffer &buffer)
1938 : : {
1939 : 14262 : bool had_errors
1940 : 7131 : = (buffer.m_diagnostic_counters.m_count_for_kind[DK_ERROR] > 0
1941 : 7131 : || buffer.m_diagnostic_counters.m_count_for_kind[DK_WERROR] > 0);
1942 : 7131 : if (buffer.m_per_format_buffers)
1943 : 28524 : for (auto per_format_buffer : *buffer.m_per_format_buffers)
1944 : 7131 : per_format_buffer->flush ();
1945 : 7131 : buffer.m_diagnostic_counters.move_to (m_diagnostic_counters);
1946 : :
1947 : 11120 : action_after_output (had_errors ? DK_ERROR : DK_WARNING);
1948 : 7131 : check_max_errors (true);
1949 : 7128 : }
1950 : :
1951 : : /* struct diagnostic_counters. */
1952 : :
1953 : 8869557 : diagnostic_counters::diagnostic_counters ()
1954 : : {
1955 : 8869557 : clear ();
1956 : 8869557 : }
1957 : :
1958 : : void
1959 : 0 : diagnostic_counters::dump (FILE *out, int indent) const
1960 : : {
1961 : 0 : fprintf (out, "%*scounts:\n", indent, "");
1962 : 0 : bool none = true;
1963 : 0 : for (int i = 0; i < DK_LAST_DIAGNOSTIC_KIND; i++)
1964 : 0 : if (m_count_for_kind[i] > 0)
1965 : : {
1966 : 0 : fprintf (out, "%*s%s%i\n",
1967 : : indent + 2, "",
1968 : : get_diagnostic_kind_text (static_cast<diagnostic_t> (i)),
1969 : : m_count_for_kind[i]);
1970 : 0 : none = false;
1971 : : }
1972 : 0 : if (none)
1973 : 0 : fprintf (out, "%*s(none)\n", indent + 2, "");
1974 : 0 : }
1975 : :
1976 : : void
1977 : 109092 : diagnostic_counters::move_to (diagnostic_counters &dest)
1978 : : {
1979 : 1745472 : for (int i = 0; i < DK_LAST_DIAGNOSTIC_KIND; i++)
1980 : 1636380 : dest.m_count_for_kind[i] += m_count_for_kind[i];
1981 : 109092 : clear ();
1982 : 109092 : }
1983 : :
1984 : : void
1985 : 32107257 : diagnostic_counters::clear ()
1986 : : {
1987 : 32107257 : memset (&m_count_for_kind, 0, sizeof m_count_for_kind);
1988 : 32107257 : }
1989 : :
1990 : : /* class diagnostic_buffer. */
1991 : :
1992 : 8184461 : diagnostic_buffer::diagnostic_buffer (diagnostic_context &ctxt)
1993 : 8184461 : : m_ctxt (ctxt),
1994 : 8184461 : m_per_format_buffers (nullptr)
1995 : : {
1996 : 8184461 : }
1997 : :
1998 : 8153940 : diagnostic_buffer::~diagnostic_buffer ()
1999 : : {
2000 : 8153940 : if (m_per_format_buffers)
2001 : : {
2002 : 373776 : for (auto iter : *m_per_format_buffers)
2003 : 93444 : delete iter;
2004 : 186888 : delete m_per_format_buffers;
2005 : : }
2006 : 8153940 : }
2007 : :
2008 : : void
2009 : 0 : diagnostic_buffer::dump (FILE *out, int indent) const
2010 : : {
2011 : 0 : m_diagnostic_counters.dump (out, indent + 2);
2012 : 0 : fprintf (out, "%*sm_per_format_buffers:\n", indent, "");
2013 : 0 : if (m_per_format_buffers)
2014 : 0 : for (auto per_format_buffer : *m_per_format_buffers)
2015 : 0 : per_format_buffer->dump (out, indent + 2);
2016 : : else
2017 : 0 : fprintf (out, "%*s(none)\n", indent + 2, "");
2018 : 0 : }
2019 : :
2020 : : bool
2021 : 5843574 : diagnostic_buffer::empty_p () const
2022 : : {
2023 : 5843574 : if (m_per_format_buffers)
2024 : 9271050 : for (auto per_format_buffer : *m_per_format_buffers)
2025 : : /* Query initial buffer. */
2026 : 3090350 : return per_format_buffer->empty_p ();
2027 : : return true;
2028 : : }
2029 : :
2030 : : void
2031 : 101961 : diagnostic_buffer::move_to (diagnostic_buffer &dest)
2032 : : {
2033 : : /* Bail if there's nothing to move. */
2034 : 101961 : if (!m_per_format_buffers)
2035 : : return;
2036 : :
2037 : 101961 : m_diagnostic_counters.move_to (dest.m_diagnostic_counters);
2038 : :
2039 : 101961 : if (!dest.m_per_format_buffers)
2040 : : {
2041 : : /* Optimization for the "move to empty" case:
2042 : : simply move the vec to the dest. */
2043 : 80070 : dest.m_per_format_buffers = m_per_format_buffers;
2044 : 80070 : m_per_format_buffers = nullptr;
2045 : 80070 : return;
2046 : : }
2047 : :
2048 : 21891 : dest.ensure_per_format_buffers ();
2049 : 21891 : gcc_assert (m_per_format_buffers);
2050 : 65673 : gcc_assert (m_per_format_buffers->length ()
2051 : : == m_ctxt.m_output_sinks.length ());
2052 : 21891 : gcc_assert (dest.m_per_format_buffers);
2053 : 43782 : gcc_assert (dest.m_per_format_buffers->length ()
2054 : : == m_ctxt.m_output_sinks.length ());
2055 : 43782 : for (unsigned idx = 0; idx < m_ctxt.m_output_sinks.length (); ++idx)
2056 : : {
2057 : 21891 : auto per_format_buffer_src = (*m_per_format_buffers)[idx];
2058 : 21891 : auto per_format_buffer_dest = (*dest.m_per_format_buffers)[idx];
2059 : 21891 : per_format_buffer_src->move_to (*per_format_buffer_dest);
2060 : : }
2061 : : }
2062 : :
2063 : : /* Lazily get the output formats to create their own kind of buffers.
2064 : : We can't change the output sinks on a context once this has been called
2065 : : on any diagnostic_buffer instances for that context, since there's no
2066 : : way to update all diagnostic_buffer instances for that context. */
2067 : :
2068 : : void
2069 : 1187889 : diagnostic_buffer::ensure_per_format_buffers ()
2070 : : {
2071 : 1187889 : if (!m_per_format_buffers)
2072 : : {
2073 : 95319 : m_per_format_buffers = new auto_vec<diagnostic_per_format_buffer *> ();
2074 : 190638 : for (unsigned idx = 0; idx < m_ctxt.m_output_sinks.length (); ++idx)
2075 : : {
2076 : 95319 : auto sink = m_ctxt.m_output_sinks[idx];
2077 : 95319 : auto per_format_buffer = sink->make_per_format_buffer ();
2078 : 95319 : m_per_format_buffers->safe_push (per_format_buffer.release ());
2079 : 95319 : }
2080 : : }
2081 : 1187889 : gcc_assert (m_per_format_buffers);
2082 : 3563667 : gcc_assert (m_per_format_buffers->length ()
2083 : : == m_ctxt.m_output_sinks.length ());
2084 : 1187889 : }
2085 : :
2086 : : /* Really call the system 'abort'. This has to go right at the end of
2087 : : this file, so that there are no functions after it that call abort
2088 : : and get the system abort instead of our macro. */
2089 : : #undef abort
2090 : : static void
2091 : 0 : real_abort (void)
2092 : : {
2093 : 0 : abort ();
2094 : : }
2095 : :
2096 : : #if CHECKING_P
2097 : :
2098 : : namespace selftest {
2099 : :
2100 : : /* Helper function for test_print_escaped_string. */
2101 : :
2102 : : static void
2103 : 24 : assert_print_escaped_string (const location &loc, const char *expected_output,
2104 : : const char *input)
2105 : : {
2106 : 24 : pretty_printer pp;
2107 : 24 : print_escaped_string (&pp, input);
2108 : 24 : ASSERT_STREQ_AT (loc, expected_output, pp_formatted_text (&pp));
2109 : 24 : }
2110 : :
2111 : : #define ASSERT_PRINT_ESCAPED_STRING_STREQ(EXPECTED_OUTPUT, INPUT) \
2112 : : assert_print_escaped_string (SELFTEST_LOCATION, EXPECTED_OUTPUT, INPUT)
2113 : :
2114 : : /* Tests of print_escaped_string. */
2115 : :
2116 : : static void
2117 : 3 : test_print_escaped_string ()
2118 : : {
2119 : : /* Empty string. */
2120 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"\"", "");
2121 : :
2122 : : /* Non-empty string. */
2123 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"hello world\"", "hello world");
2124 : :
2125 : : /* Various things that need to be escaped: */
2126 : : /* Backslash. */
2127 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\\after\"",
2128 : : "before\\after");
2129 : : /* Tab. */
2130 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\tafter\"",
2131 : : "before\tafter");
2132 : : /* Newline. */
2133 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\nafter\"",
2134 : : "before\nafter");
2135 : : /* Double quote. */
2136 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\"after\"",
2137 : : "before\"after");
2138 : :
2139 : : /* Non-printable characters: BEL: '\a': 0x07 */
2140 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\007after\"",
2141 : : "before\aafter");
2142 : : /* Non-printable characters: vertical tab: '\v': 0x0b */
2143 : 3 : ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\013after\"",
2144 : : "before\vafter");
2145 : 3 : }
2146 : :
2147 : : /* Tests of print_parseable_fixits. */
2148 : :
2149 : : /* Verify that print_parseable_fixits emits the empty string if there
2150 : : are no fixits. */
2151 : :
2152 : : static void
2153 : 3 : test_print_parseable_fixits_none ()
2154 : : {
2155 : 3 : pretty_printer pp;
2156 : 3 : file_cache fc;
2157 : 3 : rich_location richloc (line_table, UNKNOWN_LOCATION);
2158 : :
2159 : 3 : print_parseable_fixits (fc, &pp, &richloc, DIAGNOSTICS_COLUMN_UNIT_BYTE, 8);
2160 : 3 : ASSERT_STREQ ("", pp_formatted_text (&pp));
2161 : 3 : }
2162 : :
2163 : : /* Verify that print_parseable_fixits does the right thing if there
2164 : : is an insertion fixit hint. */
2165 : :
2166 : : static void
2167 : 3 : test_print_parseable_fixits_insert ()
2168 : : {
2169 : 3 : pretty_printer pp;
2170 : 3 : file_cache fc;
2171 : 3 : rich_location richloc (line_table, UNKNOWN_LOCATION);
2172 : :
2173 : 3 : linemap_add (line_table, LC_ENTER, false, "test.c", 0);
2174 : 3 : linemap_line_start (line_table, 5, 100);
2175 : 3 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2176 : 3 : location_t where = linemap_position_for_column (line_table, 10);
2177 : 3 : richloc.add_fixit_insert_before (where, "added content");
2178 : :
2179 : 3 : print_parseable_fixits (fc, &pp, &richloc, DIAGNOSTICS_COLUMN_UNIT_BYTE, 8);
2180 : 3 : ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n",
2181 : : pp_formatted_text (&pp));
2182 : 3 : }
2183 : :
2184 : : /* Verify that print_parseable_fixits does the right thing if there
2185 : : is an removal fixit hint. */
2186 : :
2187 : : static void
2188 : 3 : test_print_parseable_fixits_remove ()
2189 : : {
2190 : 3 : pretty_printer pp;
2191 : 3 : file_cache fc;
2192 : 3 : rich_location richloc (line_table, UNKNOWN_LOCATION);
2193 : :
2194 : 3 : linemap_add (line_table, LC_ENTER, false, "test.c", 0);
2195 : 3 : linemap_line_start (line_table, 5, 100);
2196 : 3 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2197 : 3 : source_range where;
2198 : 3 : where.m_start = linemap_position_for_column (line_table, 10);
2199 : 3 : where.m_finish = linemap_position_for_column (line_table, 20);
2200 : 3 : richloc.add_fixit_remove (where);
2201 : :
2202 : 3 : print_parseable_fixits (fc, &pp, &richloc, DIAGNOSTICS_COLUMN_UNIT_BYTE, 8);
2203 : 3 : ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"\"\n",
2204 : : pp_formatted_text (&pp));
2205 : 3 : }
2206 : :
2207 : : /* Verify that print_parseable_fixits does the right thing if there
2208 : : is an replacement fixit hint. */
2209 : :
2210 : : static void
2211 : 3 : test_print_parseable_fixits_replace ()
2212 : : {
2213 : 3 : pretty_printer pp;
2214 : 3 : file_cache fc;
2215 : 3 : rich_location richloc (line_table, UNKNOWN_LOCATION);
2216 : :
2217 : 3 : linemap_add (line_table, LC_ENTER, false, "test.c", 0);
2218 : 3 : linemap_line_start (line_table, 5, 100);
2219 : 3 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2220 : 3 : source_range where;
2221 : 3 : where.m_start = linemap_position_for_column (line_table, 10);
2222 : 3 : where.m_finish = linemap_position_for_column (line_table, 20);
2223 : 3 : richloc.add_fixit_replace (where, "replacement");
2224 : :
2225 : 3 : print_parseable_fixits (fc, &pp, &richloc, DIAGNOSTICS_COLUMN_UNIT_BYTE, 8);
2226 : 3 : ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"replacement\"\n",
2227 : : pp_formatted_text (&pp));
2228 : 3 : }
2229 : :
2230 : : /* Verify that print_parseable_fixits correctly handles
2231 : : DIAGNOSTICS_COLUMN_UNIT_BYTE vs DIAGNOSTICS_COLUMN_UNIT_COLUMN. */
2232 : :
2233 : : static void
2234 : 3 : test_print_parseable_fixits_bytes_vs_display_columns ()
2235 : : {
2236 : 3 : line_table_test ltt;
2237 : 3 : rich_location richloc (line_table, UNKNOWN_LOCATION);
2238 : :
2239 : : /* 1-based byte offsets: 12345677778888999900001234567. */
2240 : 3 : const char *const content = "smile \xf0\x9f\x98\x82 colour\n";
2241 : : /* 1-based display cols: 123456[......7-8.....]9012345. */
2242 : 3 : const int tabstop = 8;
2243 : :
2244 : 3 : temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
2245 : 3 : file_cache fc;
2246 : 3 : const char *const fname = tmp.get_filename ();
2247 : :
2248 : 3 : linemap_add (line_table, LC_ENTER, false, fname, 0);
2249 : 3 : linemap_line_start (line_table, 1, 100);
2250 : 3 : linemap_add (line_table, LC_LEAVE, false, NULL, 0);
2251 : 3 : source_range where;
2252 : 3 : where.m_start = linemap_position_for_column (line_table, 12);
2253 : 3 : where.m_finish = linemap_position_for_column (line_table, 17);
2254 : 3 : richloc.add_fixit_replace (where, "color");
2255 : :
2256 : : /* Escape fname. */
2257 : 3 : pretty_printer tmp_pp;
2258 : 3 : print_escaped_string (&tmp_pp, fname);
2259 : 3 : char *escaped_fname = xstrdup (pp_formatted_text (&tmp_pp));
2260 : :
2261 : 3 : const int buf_len = strlen (escaped_fname) + 100;
2262 : 3 : char *const expected = XNEWVEC (char, buf_len);
2263 : :
2264 : 3 : {
2265 : 3 : pretty_printer pp;
2266 : 3 : print_parseable_fixits (fc, &pp, &richloc,
2267 : : DIAGNOSTICS_COLUMN_UNIT_BYTE,
2268 : : tabstop);
2269 : 3 : snprintf (expected, buf_len,
2270 : : "fix-it:%s:{1:12-1:18}:\"color\"\n", escaped_fname);
2271 : 3 : ASSERT_STREQ (expected, pp_formatted_text (&pp));
2272 : 3 : }
2273 : 3 : {
2274 : 3 : pretty_printer pp;
2275 : 3 : print_parseable_fixits (fc, &pp, &richloc,
2276 : : DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
2277 : : tabstop);
2278 : 3 : snprintf (expected, buf_len,
2279 : : "fix-it:%s:{1:10-1:16}:\"color\"\n", escaped_fname);
2280 : 3 : ASSERT_STREQ (expected, pp_formatted_text (&pp));
2281 : 3 : }
2282 : :
2283 : 3 : XDELETEVEC (expected);
2284 : 3 : free (escaped_fname);
2285 : 3 : }
2286 : :
2287 : : /* Verify that
2288 : : diagnostic_column_policy::get_location_text (..., SHOW_COLUMN, ...)
2289 : : generates EXPECTED_LOC_TEXT, given FILENAME, LINE, COLUMN, with
2290 : : colorization disabled. */
2291 : :
2292 : : static void
2293 : 42 : assert_location_text (const char *expected_loc_text,
2294 : : const char *filename, int line, int column,
2295 : : bool show_column,
2296 : : int origin = 1,
2297 : : enum diagnostics_column_unit column_unit
2298 : : = DIAGNOSTICS_COLUMN_UNIT_BYTE)
2299 : : {
2300 : 42 : test_diagnostic_context dc;
2301 : 42 : dc.m_column_unit = column_unit;
2302 : 42 : dc.m_column_origin = origin;
2303 : :
2304 : 42 : expanded_location xloc;
2305 : 42 : xloc.file = filename;
2306 : 42 : xloc.line = line;
2307 : 42 : xloc.column = column;
2308 : 42 : xloc.data = NULL;
2309 : 42 : xloc.sysp = false;
2310 : :
2311 : 42 : diagnostic_column_policy column_policy (dc);
2312 : 42 : label_text actual_loc_text
2313 : 42 : = column_policy.get_location_text (xloc, show_column, false);
2314 : 42 : ASSERT_STREQ (expected_loc_text, actual_loc_text.get ());
2315 : 42 : }
2316 : :
2317 : : /* Verify that get_location_text works as expected. */
2318 : :
2319 : : static void
2320 : 3 : test_get_location_text ()
2321 : : {
2322 : 3 : const char *old_progname = progname;
2323 : 3 : progname = "PROGNAME";
2324 : 3 : assert_location_text ("PROGNAME:", NULL, 0, 0, true);
2325 : 3 : char *built_in_colon = concat (special_fname_builtin (), ":", (char *) 0);
2326 : 3 : assert_location_text (built_in_colon, special_fname_builtin (),
2327 : : 42, 10, true);
2328 : 3 : free (built_in_colon);
2329 : 3 : assert_location_text ("foo.c:42:10:", "foo.c", 42, 10, true);
2330 : 3 : assert_location_text ("foo.c:42:9:", "foo.c", 42, 10, true, 0);
2331 : 3 : assert_location_text ("foo.c:42:1010:", "foo.c", 42, 10, true, 1001);
2332 : 9 : for (int origin = 0; origin != 2; ++origin)
2333 : 6 : assert_location_text ("foo.c:42:", "foo.c", 42, 0, true, origin);
2334 : 3 : assert_location_text ("foo.c:", "foo.c", 0, 10, true);
2335 : 3 : assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
2336 : 3 : assert_location_text ("foo.c:", "foo.c", 0, 10, false);
2337 : :
2338 : 3 : maybe_line_and_column (INT_MAX, INT_MAX);
2339 : 3 : maybe_line_and_column (INT_MIN, INT_MIN);
2340 : :
2341 : 3 : {
2342 : : /* In order to test display columns vs byte columns, we need to create a
2343 : : file for location_get_source_line() to read. */
2344 : :
2345 : 3 : const char *const content = "smile \xf0\x9f\x98\x82\n";
2346 : 3 : const int line_bytes = strlen (content) - 1;
2347 : 3 : const int def_tabstop = 8;
2348 : 3 : const cpp_char_column_policy policy (def_tabstop, cpp_wcwidth);
2349 : 3 : const int display_width = cpp_display_width (content, line_bytes, policy);
2350 : 3 : ASSERT_EQ (line_bytes - 2, display_width);
2351 : 3 : temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
2352 : 3 : const char *const fname = tmp.get_filename ();
2353 : 3 : const int buf_len = strlen (fname) + 16;
2354 : 3 : char *const expected = XNEWVEC (char, buf_len);
2355 : :
2356 : 3 : snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes);
2357 : 3 : assert_location_text (expected, fname, 1, line_bytes, true,
2358 : : 1, DIAGNOSTICS_COLUMN_UNIT_BYTE);
2359 : :
2360 : 3 : snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes - 1);
2361 : 3 : assert_location_text (expected, fname, 1, line_bytes, true,
2362 : : 0, DIAGNOSTICS_COLUMN_UNIT_BYTE);
2363 : :
2364 : 3 : snprintf (expected, buf_len, "%s:1:%d:", fname, display_width);
2365 : 3 : assert_location_text (expected, fname, 1, line_bytes, true,
2366 : : 1, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
2367 : :
2368 : 3 : snprintf (expected, buf_len, "%s:1:%d:", fname, display_width - 1);
2369 : 3 : assert_location_text (expected, fname, 1, line_bytes, true,
2370 : : 0, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
2371 : :
2372 : 3 : XDELETEVEC (expected);
2373 : 3 : }
2374 : :
2375 : :
2376 : 3 : progname = old_progname;
2377 : 3 : }
2378 : :
2379 : : /* Selftest for num_digits. */
2380 : :
2381 : : static void
2382 : 3 : test_num_digits ()
2383 : : {
2384 : 3 : ASSERT_EQ (1, num_digits (0));
2385 : 3 : ASSERT_EQ (1, num_digits (9));
2386 : 3 : ASSERT_EQ (2, num_digits (10));
2387 : 3 : ASSERT_EQ (2, num_digits (99));
2388 : 3 : ASSERT_EQ (3, num_digits (100));
2389 : 3 : ASSERT_EQ (3, num_digits (999));
2390 : 3 : ASSERT_EQ (4, num_digits (1000));
2391 : 3 : ASSERT_EQ (4, num_digits (9999));
2392 : 3 : ASSERT_EQ (5, num_digits (10000));
2393 : 3 : ASSERT_EQ (5, num_digits (99999));
2394 : 3 : ASSERT_EQ (6, num_digits (100000));
2395 : 3 : ASSERT_EQ (6, num_digits (999999));
2396 : 3 : ASSERT_EQ (7, num_digits (1000000));
2397 : 3 : ASSERT_EQ (7, num_digits (9999999));
2398 : 3 : ASSERT_EQ (8, num_digits (10000000));
2399 : 3 : ASSERT_EQ (8, num_digits (99999999));
2400 : 3 : }
2401 : :
2402 : : /* Run all of the selftests within this file. */
2403 : :
2404 : : void
2405 : 3 : c_diagnostic_cc_tests ()
2406 : : {
2407 : 3 : test_print_escaped_string ();
2408 : 3 : test_print_parseable_fixits_none ();
2409 : 3 : test_print_parseable_fixits_insert ();
2410 : 3 : test_print_parseable_fixits_remove ();
2411 : 3 : test_print_parseable_fixits_replace ();
2412 : 3 : test_print_parseable_fixits_bytes_vs_display_columns ();
2413 : 3 : test_get_location_text ();
2414 : 3 : test_num_digits ();
2415 : 3 : }
2416 : :
2417 : : } // namespace selftest
2418 : :
2419 : : #endif /* #if CHECKING_P */
2420 : :
2421 : : #if __GNUC__ >= 10
2422 : : # pragma GCC diagnostic pop
2423 : : #endif
|