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