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