Line data Source code
1 : /* Classic text-based output of diagnostics.
2 : Copyright (C) 1999-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 :
21 : #include "config.h"
22 : #define INCLUDE_VECTOR
23 : #include "system.h"
24 : #include "coretypes.h"
25 : #include "version.h"
26 : #include "intl.h"
27 : #include "diagnostics/color.h"
28 : #include "diagnostics/url.h"
29 : #include "diagnostics/metadata.h"
30 : #include "diagnostics/paths.h"
31 : #include "diagnostics/client-data-hooks.h"
32 : #include "diagnostics/diagram.h"
33 : #include "diagnostics/text-sink.h"
34 : #include "diagnostics/buffering.h"
35 : #include "diagnostics/dumping.h"
36 : #include "diagnostics/logging.h"
37 : #include "text-art/theme.h"
38 :
39 : /* Disable warnings about quoting issues in the pp_xxx calls below
40 : that (intentionally) don't follow GCC diagnostic conventions. */
41 : #if __GNUC__ >= 10
42 : # pragma GCC diagnostic push
43 : # pragma GCC diagnostic ignored "-Wformat-diag"
44 : #endif
45 :
46 : namespace diagnostics {
47 :
48 : /* Concrete buffering implementation subclass for text output. */
49 :
50 : class text_sink_buffer : public per_sink_buffer
51 : {
52 : public:
53 : friend class text_sink;
54 :
55 : text_sink_buffer (sink &sink_);
56 :
57 : void dump (FILE *out, int indent) const final override;
58 :
59 : bool empty_p () const final override;
60 : void move_to (per_sink_buffer &dest) final override;
61 : void clear () final override;
62 : void flush () final override;
63 :
64 : private:
65 : sink &m_sink;
66 : output_buffer m_output_buffer;
67 : };
68 :
69 : /* class text_sink_buffer : public per_sink_buffer. */
70 :
71 98391 : text_sink_buffer::text_sink_buffer (sink &sink_)
72 98391 : : m_sink (sink_)
73 : {
74 98391 : m_output_buffer.m_flush_p = false;
75 98391 : }
76 :
77 : void
78 0 : text_sink_buffer::dump (FILE *out, int indent) const
79 : {
80 0 : dumping::emit_heading (out, indent, "text_sink_buffer");
81 0 : m_output_buffer.dump (out, indent + 2);
82 0 : }
83 :
84 : bool
85 8444414 : text_sink_buffer::empty_p () const
86 : {
87 8444414 : return output_buffer_last_position_in_text (&m_output_buffer) == nullptr;
88 : }
89 :
90 : void
91 23450 : text_sink_buffer::move_to (per_sink_buffer &base_dest)
92 : {
93 23450 : text_sink_buffer &dest
94 : = static_cast<text_sink_buffer &> (base_dest);
95 23450 : const char *str = output_buffer_formatted_text (&m_output_buffer);
96 23450 : output_buffer_append_r (&dest.m_output_buffer, str, strlen (str));
97 :
98 23450 : obstack_free (m_output_buffer.m_obstack,
99 : obstack_base (m_output_buffer.m_obstack));
100 23450 : m_output_buffer.m_line_length = 0;
101 23450 : }
102 :
103 : void
104 5165915 : text_sink_buffer::clear ()
105 : {
106 5165915 : pretty_printer *const pp = m_sink.get_printer ();
107 5165915 : output_buffer *const old_output_buffer = pp_buffer (pp);
108 :
109 5165915 : pp_buffer (pp) = &m_output_buffer;
110 :
111 5165915 : pp_clear_output_area (pp);
112 5165915 : gcc_assert (empty_p ());
113 :
114 5165915 : pp_buffer (pp) = old_output_buffer;
115 5165915 : }
116 :
117 : void
118 7313 : text_sink_buffer::flush ()
119 : {
120 7313 : pretty_printer *const pp = m_sink.get_printer ();
121 7313 : output_buffer *const old_output_buffer = pp_buffer (pp);
122 :
123 7313 : pp_buffer (pp) = &m_output_buffer;
124 :
125 7313 : pp_really_flush (pp);
126 7313 : gcc_assert (empty_p ());
127 :
128 7313 : pp_buffer (pp) = old_output_buffer;
129 7313 : }
130 :
131 : /* class diagnostics::text_sink : public diagnostics::sink. */
132 :
133 617633 : text_sink::~text_sink ()
134 : {
135 : /* Some of the errors may actually have been warnings. */
136 310192 : if (m_context.diagnostic_count (kind::werror))
137 : {
138 190 : pretty_printer *pp = get_printer ();
139 : /* -Werror was given. */
140 190 : if (m_context.warning_as_error_requested_p ())
141 75 : pp_verbatim (pp,
142 75 : _("%s: all warnings being treated as errors"),
143 : progname);
144 : /* At least one -Werror= was given. */
145 : else
146 115 : pp_verbatim (pp,
147 115 : _("%s: some warnings being treated as errors"),
148 : progname);
149 190 : pp_newline_and_flush (pp);
150 : }
151 :
152 310192 : if (m_includes_seen)
153 : {
154 1031 : delete m_includes_seen;
155 1031 : m_includes_seen = nullptr;
156 : }
157 617633 : }
158 :
159 : void
160 0 : text_sink::dump (FILE *outfile, int indent) const
161 : {
162 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_follows_reference_printer);
163 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_nesting);
164 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_locations_in_nesting);
165 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_nesting_levels);
166 :
167 0 : sink::dump (outfile, indent);
168 0 : dumping::emit_heading (outfile, indent, "saved_output_buffer");
169 0 : if (m_saved_output_buffer)
170 0 : m_saved_output_buffer->dump (outfile, indent + 2);
171 : else
172 0 : dumping::emit_none (outfile, indent + 2);
173 0 : }
174 :
175 : void
176 2444428 : text_sink::set_buffer (per_sink_buffer *base)
177 : {
178 2444428 : text_sink_buffer * const buffer
179 : = static_cast<text_sink_buffer *> (base);
180 :
181 2444428 : pretty_printer *const pp = get_printer ();
182 :
183 2444428 : if (!m_saved_output_buffer)
184 31291 : m_saved_output_buffer = pp_buffer (pp);
185 :
186 2444428 : if (buffer)
187 1222214 : pp_buffer (pp) = &buffer->m_output_buffer;
188 : else
189 : {
190 1222214 : gcc_assert (m_saved_output_buffer);
191 1222214 : pp_buffer (pp) = m_saved_output_buffer;
192 : }
193 2444428 : }
194 :
195 : std::unique_ptr<per_sink_buffer>
196 98391 : text_sink::make_per_sink_buffer ()
197 : {
198 98391 : return std::make_unique<text_sink_buffer> (*this);
199 : }
200 :
201 : /* Implementation of diagnostics::sink::on_report_diagnostic vfunc
202 : for GCC's standard textual output. */
203 :
204 : void
205 1586195 : text_sink::on_report_diagnostic (const diagnostic_info &diagnostic,
206 : enum kind orig_diag_kind)
207 : {
208 1586195 : auto logger = get_logger ();
209 1586195 : DIAGNOSTICS_LOG_SCOPE_PRINTF0
210 : (logger,
211 1586195 : "diagnostics::text_sink::on_report_diagnostic");
212 :
213 1586195 : pretty_printer *pp = get_printer ();
214 :
215 1586195 : (*text_starter (&m_context)) (*this, &diagnostic);
216 :
217 1586195 : pp_output_formatted_text (pp, m_context.get_urlifier ());
218 :
219 1586195 : if (m_context.m_show_cwe)
220 1584803 : print_any_cwe (diagnostic);
221 :
222 1586195 : if (m_context.m_show_rules)
223 1584803 : print_any_rules (diagnostic);
224 :
225 1586195 : if (m_context.m_show_option_requested)
226 1584803 : print_option_information (diagnostic, orig_diag_kind);
227 :
228 : /* If we're showing nested diagnostics, then print the location
229 : on a new line, indented. */
230 1586195 : if (m_show_nesting && m_show_locations_in_nesting)
231 : {
232 21737 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
233 21737 : if (nesting_level > 0)
234 : {
235 60 : location_t loc = diagnostic_location (&diagnostic);
236 60 : pp_set_prefix (pp, nullptr);
237 60 : char *indent_prefix = build_indent_prefix (false);
238 : /* Only print changes of location. */
239 60 : if (loc != get_context ().m_last_location
240 60 : && loc > BUILTINS_LOCATION)
241 : {
242 8 : const expanded_location s
243 8 : = diagnostic_expand_location (&diagnostic);
244 8 : label_text location_text = get_location_text (s);
245 8 : pp_newline (pp);
246 8 : pp_printf (pp, "%s%s", indent_prefix, location_text.get ());
247 8 : }
248 60 : pp_set_prefix (pp, indent_prefix);
249 : }
250 : }
251 :
252 1586195 : (*text_finalizer (&m_context)) (*this,
253 : &diagnostic,
254 : orig_diag_kind);
255 :
256 1586194 : if (m_show_nesting && m_show_locations_in_nesting)
257 21737 : get_context ().m_last_location = diagnostic_location (&diagnostic);
258 1586194 : }
259 :
260 : void
261 0 : text_sink::on_report_verbatim (text_info &text)
262 : {
263 0 : pp_format_verbatim (get_printer (), &text);
264 0 : pp_newline_and_flush (get_printer ());
265 0 : }
266 :
267 : void
268 80 : text_sink::on_diagram (const diagnostics::diagram &d)
269 : {
270 80 : pretty_printer *const pp = get_printer ();
271 :
272 80 : char *saved_prefix = pp_take_prefix (pp);
273 80 : pp_set_prefix (pp, nullptr);
274 : /* Use a newline before and after and a two-space indent
275 : to make the diagram stand out a little from the wall of text. */
276 80 : pp_newline (pp);
277 80 : d.get_canvas ().print_to_pp (pp, " ");
278 80 : pp_newline (pp);
279 80 : pp_set_prefix (pp, saved_prefix);
280 80 : pp_flush (pp);
281 80 : }
282 :
283 : void
284 364131 : text_sink::
285 : after_diagnostic (const diagnostic_info &diagnostic)
286 : {
287 364131 : if (const paths::path *path = diagnostic.m_richloc->get_path ())
288 9843 : print_path (*path);
289 364131 : }
290 :
291 : /* Return a malloc'd string describing a location and the severity of the
292 : diagnostic, e.g. "foo.c:42:10: error: ".
293 :
294 : If m_show_nesting, then the above will be preceded by indentation to show
295 : the level, and a bullet point.
296 :
297 : The caller is responsible for freeing the memory. */
298 : char *
299 363704 : text_sink::build_prefix (const diagnostic_info &diagnostic) const
300 : {
301 363704 : gcc_assert (diagnostic.m_kind < kind::last_diagnostic_kind);
302 :
303 363704 : const char *text = _(get_text_for_kind (diagnostic.m_kind));
304 363704 : const char *text_cs = "", *text_ce = "";
305 363704 : pretty_printer *pp = get_printer ();
306 :
307 363704 : if (const char *color_name = get_color_for_kind (diagnostic.m_kind))
308 : {
309 363704 : text_cs = colorize_start (pp_show_color (pp), color_name);
310 363704 : text_ce = colorize_stop (pp_show_color (pp));
311 : }
312 :
313 363704 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
314 363704 : if (m_show_nesting && nesting_level > 0)
315 : {
316 162 : char *indent_prefix = build_indent_prefix (true);
317 :
318 : /* Reduce verbosity of nested diagnostics by not printing "note: "
319 : all the time. */
320 162 : if (diagnostic.m_kind == kind::note)
321 : return indent_prefix;
322 :
323 6 : char *result = build_message_string ("%s%s%s%s", indent_prefix,
324 : text_cs, text, text_ce);
325 6 : free (indent_prefix);
326 6 : return result;
327 : }
328 : else
329 : {
330 363542 : const expanded_location s = diagnostic_expand_location (&diagnostic);
331 363542 : label_text location_text = get_location_text (s);
332 363542 : return build_message_string ("%s %s%s%s", location_text.get (),
333 : text_cs, text, text_ce);
334 363542 : }
335 : }
336 :
337 : /* Same as build_prefix, but only the source FILE is given. */
338 : char *
339 40662 : text_sink::file_name_as_prefix (const char *f) const
340 : {
341 40662 : pretty_printer *const pp = get_printer ();
342 40662 : const char *locus_cs
343 40662 : = colorize_start (pp_show_color (pp), "locus");
344 40662 : const char *locus_ce = colorize_stop (pp_show_color (pp));
345 40662 : return build_message_string ("%s%s:%s ", locus_cs, f, locus_ce);
346 : }
347 :
348 : /* Get the unicode code point for bullet points when showing
349 : nested diagnostics. */
350 :
351 : static unsigned
352 321 : get_bullet_point_unichar (bool unicode)
353 : {
354 321 : if (unicode)
355 : return 0x2022; /* U+2022: Bullet */
356 : else
357 285 : return '*';
358 : }
359 :
360 : /* Return true if DC's theme supports unicode characters. */
361 :
362 : static bool
363 321 : use_unicode_p (const context &dc)
364 : {
365 321 : if (text_art::theme *theme = dc.get_diagram_theme ())
366 36 : return theme->unicode_p ();
367 : else
368 : return false;
369 : }
370 :
371 : /* Get the unicode code point for bullet points when showing
372 : nested diagnostics. */
373 :
374 : static unsigned
375 321 : get_bullet_point_unichar (context &dc)
376 : {
377 321 : return get_bullet_point_unichar (use_unicode_p (dc));
378 : }
379 :
380 : /* Return a malloc'd string for use as a prefix to show indentation.
381 : If m_show_nesting is false, or we're at the top-level, then the
382 : result will be the empty string.
383 :
384 : If m_show_nesting, then the result will contain indentation to show
385 : the nesting level, then either a bullet point (if WITH_BULLET is true),
386 : or a space.
387 :
388 : The caller is responsible for freeing the memory. */
389 :
390 : char *
391 595398 : text_sink::build_indent_prefix (bool with_bullet) const
392 : {
393 595398 : if (!m_show_nesting)
394 589780 : return xstrdup ("");
395 :
396 5618 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
397 5618 : if (nesting_level == 0)
398 5075 : return xstrdup ("");
399 :
400 543 : pretty_printer pp;
401 2201 : for (int i = 0; i < nesting_level; i++)
402 1658 : pp_string (&pp, " ");
403 543 : if (with_bullet)
404 642 : pp_unicode_character (&pp, get_bullet_point_unichar (get_context ()));
405 : else
406 222 : pp_space (&pp);
407 543 : pp_space (&pp);
408 543 : if (m_show_nesting_levels)
409 36 : pp_printf (&pp, "(level %i):", nesting_level);
410 543 : return xstrdup (pp_formatted_text (&pp));
411 543 : }
412 :
413 : /* Add a purely textual note with text GMSGID and with LOCATION. */
414 :
415 : void
416 12669 : text_sink::append_note (location_t location,
417 : const char * gmsgid, ...)
418 : {
419 12669 : context *dc = &get_context ();
420 :
421 12669 : diagnostic_info diagnostic;
422 12669 : va_list ap;
423 12669 : rich_location richloc (line_table, location);
424 :
425 12669 : va_start (ap, gmsgid);
426 12669 : diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, kind::note);
427 12669 : if (dc->m_inhibit_notes_p)
428 : {
429 0 : va_end (ap);
430 0 : return;
431 : }
432 12669 : pretty_printer *pp = get_printer ();
433 12669 : char *saved_prefix = pp_take_prefix (pp);
434 12669 : pp_set_prefix (pp, build_prefix (diagnostic));
435 12669 : pp_format (pp, &diagnostic.m_message);
436 12669 : pp_output_formatted_text (pp);
437 12669 : pp_destroy_prefix (pp);
438 12669 : pp_set_prefix (pp, saved_prefix);
439 12669 : pp_newline (pp);
440 12669 : diagnostic_show_locus (dc, get_source_printing_options (),
441 : &richloc, kind::note, pp);
442 12669 : va_end (ap);
443 12669 : }
444 :
445 : bool
446 4530337 : text_sink::follows_reference_printer_p () const
447 : {
448 4530337 : return m_follows_reference_printer;
449 : }
450 :
451 : void
452 497943 : text_sink::update_printer ()
453 : {
454 497943 : pretty_printer *copy_from_pp
455 497943 : = (m_follows_reference_printer
456 497943 : ? get_context ().get_reference_printer ()
457 0 : : m_printer.get ());
458 497943 : const bool show_color = pp_show_color (copy_from_pp);
459 497943 : const diagnostic_url_format url_format = copy_from_pp->get_url_format ();
460 :
461 497943 : m_printer = get_context ().clone_printer ();
462 :
463 497943 : pp_show_color (m_printer.get ()) = show_color;
464 497943 : m_printer->set_url_format (url_format);
465 : // ...etc
466 :
467 497943 : m_source_printing = get_context ().m_source_printing;
468 497943 : }
469 :
470 : /* If DIAGNOSTIC has a CWE identifier, print it.
471 :
472 : For example, if the diagnostic metadata associates it with CWE-119,
473 : " [CWE-119]" will be printed, suitably colorized, and with a URL of a
474 : description of the security issue. */
475 :
476 : void
477 1584803 : text_sink::print_any_cwe (const diagnostic_info &diagnostic)
478 : {
479 1584803 : if (!diagnostic.m_metadata)
480 : return;
481 :
482 4543 : int cwe = diagnostic.m_metadata->get_cwe ();
483 4543 : if (cwe)
484 : {
485 3328 : pretty_printer * const pp = get_printer ();
486 3328 : char *saved_prefix = pp_take_prefix (pp);
487 3328 : pp_string (pp, " [");
488 3328 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
489 3328 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
490 3328 : if (pp->supports_urls_p ())
491 : {
492 0 : char *cwe_url = get_cwe_url (cwe);
493 0 : pp_begin_url (pp, cwe_url);
494 0 : free (cwe_url);
495 : }
496 3328 : pp_printf (pp, "CWE-%i", cwe);
497 3328 : pp_set_prefix (pp, saved_prefix);
498 3328 : if (pp->supports_urls_p ())
499 0 : pp_end_url (pp);
500 3328 : pp_string (pp, colorize_stop (pp_show_color (pp)));
501 3328 : pp_character (pp, ']');
502 : }
503 : }
504 :
505 : /* If DIAGNOSTIC has any rules associated with it, print them.
506 :
507 : For example, if the diagnostic metadata associates it with a rule
508 : named "STR34-C", then " [STR34-C]" will be printed, suitably colorized,
509 : with any URL provided by the rule. */
510 :
511 : void
512 1584803 : text_sink::print_any_rules (const diagnostic_info &diagnostic)
513 : {
514 1584803 : if (!diagnostic.m_metadata)
515 : return;
516 :
517 5026 : for (unsigned idx = 0; idx < diagnostic.m_metadata->get_num_rules (); idx++)
518 : {
519 483 : const diagnostics::metadata::rule &rule
520 483 : = diagnostic.m_metadata->get_rule (idx);
521 483 : if (char *desc = rule.make_description ())
522 : {
523 483 : pretty_printer * const pp = get_printer ();
524 483 : char *saved_prefix = pp_take_prefix (pp);
525 483 : pp_string (pp, " [");
526 483 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
527 483 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
528 483 : char *url = nullptr;
529 483 : if (pp->supports_urls_p ())
530 : {
531 0 : url = rule.make_url ();
532 0 : if (url)
533 0 : pp_begin_url (pp, url);
534 : }
535 483 : pp_string (pp, desc);
536 483 : pp_set_prefix (pp, saved_prefix);
537 483 : if (pp->supports_urls_p ())
538 0 : if (url)
539 0 : pp_end_url (pp);
540 483 : free (url);
541 483 : pp_string (pp, colorize_stop (pp_show_color (pp)));
542 483 : pp_character (pp, ']');
543 483 : free (desc);
544 : }
545 : }
546 : }
547 :
548 : /* Print any metadata about the option used to control DIAGNOSTIC to
549 : the context's printer, e.g. " [-Werror=uninitialized]". */
550 :
551 : void
552 1584803 : text_sink::print_option_information (const diagnostic_info &diagnostic,
553 : enum kind orig_diag_kind)
554 : {
555 1584803 : label_text option_text
556 1584803 : = m_context.get_option_name (diagnostic.m_option_id,
557 1584803 : orig_diag_kind, diagnostic.m_kind);
558 1584803 : if (option_text.get ())
559 : {
560 93904 : label_text option_url;
561 93904 : pretty_printer * const pp = get_printer ();
562 93904 : if (pp->supports_urls_p ())
563 0 : option_url = m_context.get_option_url (diagnostic.m_option_id);
564 93904 : pp_string (pp, " [");
565 93904 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
566 93904 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
567 93904 : if (option_url.get ())
568 0 : pp_begin_url (pp, option_url.get ());
569 93904 : pp_string (pp, option_text.get ());
570 93904 : if (option_url.get ())
571 0 : pp_end_url (pp);
572 93904 : pp_string (pp, colorize_stop (pp_show_color (pp)));
573 93904 : pp_character (pp, ']');
574 93904 : }
575 1584803 : }
576 :
577 : /* Only dump the "In file included from..." stack once for each file. */
578 :
579 : bool
580 70820 : text_sink::includes_seen_p (const line_map_ordinary *map)
581 : {
582 : /* No include path for main. */
583 70820 : if (MAIN_FILE_P (map))
584 : return true;
585 :
586 : /* Always identify C++ modules, at least for now. */
587 16479 : auto probe = map;
588 16479 : if (linemap_check_ordinary (map)->reason == LC_RENAME)
589 : /* The module source file shows up as LC_RENAME inside LC_MODULE. */
590 760 : probe = linemap_included_from_linemap (line_table, map);
591 16479 : if (MAP_MODULE_P (probe))
592 : return false;
593 :
594 15031 : if (!m_includes_seen)
595 1031 : m_includes_seen = new hash_set<location_t, false, location_hash>;
596 :
597 : /* Hash the location of the #include directive to better handle files
598 : that are included multiple times with different macros defined. */
599 15031 : return m_includes_seen->add (linemap_included_from (map));
600 : }
601 :
602 : label_text
603 363550 : text_sink::get_location_text (const expanded_location &s) const
604 : {
605 363550 : column_policy column_policy_ (get_context ());
606 363550 : return column_policy_.get_location_text (s,
607 363550 : show_column_p (),
608 363550 : pp_show_color (get_printer ()));
609 : }
610 :
611 : /* Helpers for writing lang-specific starters/finalizers for text output. */
612 :
613 : /* Return a formatted line and column ':%line:%column'. Elided if
614 : line == 0 or col < 0. (A column of 0 may be valid due to the
615 : -fdiagnostics-column-origin option.)
616 : The result is a statically allocated buffer. */
617 :
618 : const char *
619 370764 : text_sink::maybe_line_and_column (int line, int col)
620 : {
621 370764 : static char result[32];
622 :
623 370764 : if (line)
624 : {
625 365718 : size_t l
626 365718 : = snprintf (result, sizeof (result),
627 365718 : col >= 0 ? ":%d:%d" : ":%d", line, col);
628 365718 : gcc_checking_assert (l < sizeof (result));
629 : }
630 : else
631 5046 : result[0] = 0;
632 370764 : return result;
633 : }
634 :
635 : void
636 351035 : text_sink::report_current_module (location_t where)
637 : {
638 351035 : pretty_printer *pp = get_printer ();
639 351035 : const line_map_ordinary *map = nullptr;
640 :
641 351035 : if (pp_needs_newline (pp))
642 : {
643 0 : pp_newline (pp);
644 0 : pp_needs_newline (pp) = false;
645 : }
646 :
647 351035 : if (where <= BUILTINS_LOCATION)
648 3561 : return;
649 :
650 347474 : linemap_resolve_location (line_table, where,
651 : LRK_MACRO_DEFINITION_LOCATION,
652 : &map);
653 :
654 347474 : if (map && m_last_module != map)
655 : {
656 65447 : m_last_module = map;
657 65447 : if (!includes_seen_p (map))
658 : {
659 2417 : bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
660 2417 : expanded_location s = {};
661 5373 : do
662 : {
663 5373 : where = linemap_included_from (map);
664 5373 : map = linemap_included_from_linemap (line_table, map);
665 5373 : bool is_module = MAP_MODULE_P (map);
666 5373 : s.file = LINEMAP_FILE (map);
667 5373 : s.line = SOURCE_LINE (map, where);
668 5373 : int col = -1;
669 5373 : if (first && show_column_p ())
670 : {
671 1470 : s.column = SOURCE_COLUMN (map, where);
672 1470 : col = get_column_policy ().converted_column (s);
673 : }
674 5373 : const char *line_col = maybe_line_and_column (s.line, col);
675 5373 : static const char *const msgs[] =
676 : {
677 : nullptr,
678 : N_(" from"),
679 : N_("In file included from"), /* 2 */
680 : N_(" included from"),
681 : N_("In module"), /* 4 */
682 : N_("of module"),
683 : N_("In module imported at"), /* 6 */
684 : N_("imported at"),
685 : };
686 :
687 5373 : unsigned index = (was_module ? 6 : is_module ? 4
688 3925 : : need_inc ? 2 : 0) + !first;
689 :
690 7637 : pp_verbatim (pp, "%s%s %r%s%s%R",
691 : first ? "" : was_module ? ", " : ",\n",
692 5373 : _(msgs[index]),
693 : "locus", s.file, line_col);
694 5373 : first = false, need_inc = was_module, was_module = is_module;
695 : }
696 5373 : while (!includes_seen_p (map));
697 2417 : pp_verbatim (pp, ":");
698 2417 : pp_newline (pp);
699 : }
700 : }
701 : }
702 :
703 : void
704 1392 : default_text_starter (text_sink &text_output,
705 : const diagnostic_info *diagnostic)
706 : {
707 1392 : text_output.report_current_module (diagnostic_location (diagnostic));
708 1392 : pretty_printer *const pp = text_output.get_printer ();
709 1392 : pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
710 1392 : }
711 :
712 : void
713 17139 : default_text_finalizer (text_sink &text_output,
714 : const diagnostic_info *diagnostic,
715 : enum kind)
716 : {
717 17139 : pretty_printer *const pp = text_output.get_printer ();
718 17139 : char *saved_prefix = pp_take_prefix (pp);
719 17139 : pp_set_prefix (pp, nullptr);
720 17139 : pp_newline (pp);
721 17139 : diagnostic_show_locus (&text_output.get_context (),
722 17139 : text_output.get_source_printing_options (),
723 17139 : diagnostic->m_richloc, diagnostic->m_kind, pp);
724 17139 : pp_set_prefix (pp, saved_prefix);
725 17139 : pp_flush (pp);
726 17139 : }
727 :
728 : #if __GNUC__ >= 10
729 : # pragma GCC diagnostic pop
730 : #endif
731 :
732 : } // namespace diagnostics
|