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 98059 : text_sink_buffer::text_sink_buffer (sink &sink_)
72 98059 : : m_sink (sink_)
73 : {
74 98059 : m_output_buffer.m_flush_p = false;
75 98059 : }
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 8405876 : text_sink_buffer::empty_p () const
86 : {
87 8405876 : return output_buffer_last_position_in_text (&m_output_buffer) == nullptr;
88 : }
89 :
90 : void
91 23297 : text_sink_buffer::move_to (per_sink_buffer &base_dest)
92 : {
93 23297 : text_sink_buffer &dest
94 : = static_cast<text_sink_buffer &> (base_dest);
95 23297 : const char *str = output_buffer_formatted_text (&m_output_buffer);
96 23297 : output_buffer_append_r (&dest.m_output_buffer, str, strlen (str));
97 :
98 23297 : obstack_free (m_output_buffer.m_obstack,
99 : obstack_base (m_output_buffer.m_obstack));
100 23297 : m_output_buffer.m_line_length = 0;
101 23297 : }
102 :
103 : void
104 5141150 : text_sink_buffer::clear ()
105 : {
106 5141150 : pretty_printer *const pp = m_sink.get_printer ();
107 5141150 : output_buffer *const old_output_buffer = pp_buffer (pp);
108 :
109 5141150 : pp_buffer (pp) = &m_output_buffer;
110 :
111 5141150 : pp_clear_output_area (pp);
112 5141150 : gcc_assert (empty_p ());
113 :
114 5141150 : pp_buffer (pp) = old_output_buffer;
115 5141150 : }
116 :
117 : void
118 7283 : text_sink_buffer::flush ()
119 : {
120 7283 : pretty_printer *const pp = m_sink.get_printer ();
121 7283 : output_buffer *const old_output_buffer = pp_buffer (pp);
122 :
123 7283 : pp_buffer (pp) = &m_output_buffer;
124 :
125 7283 : pp_really_flush (pp);
126 7283 : gcc_assert (empty_p ());
127 :
128 7283 : pp_buffer (pp) = old_output_buffer;
129 7283 : }
130 :
131 : /* class diagnostics::text_sink : public diagnostics::sink. */
132 :
133 612985 : text_sink::~text_sink ()
134 : {
135 : /* Some of the errors may actually have been warnings. */
136 307868 : 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 307868 : if (m_includes_seen)
153 : {
154 1008 : delete m_includes_seen;
155 1008 : m_includes_seen = nullptr;
156 : }
157 612985 : }
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 2432388 : text_sink::set_buffer (per_sink_buffer *base)
177 : {
178 2432388 : text_sink_buffer * const buffer
179 : = static_cast<text_sink_buffer *> (base);
180 :
181 2432388 : pretty_printer *const pp = get_printer ();
182 :
183 2432388 : if (!m_saved_output_buffer)
184 31139 : m_saved_output_buffer = pp_buffer (pp);
185 :
186 2432388 : if (buffer)
187 1216194 : pp_buffer (pp) = &buffer->m_output_buffer;
188 : else
189 : {
190 1216194 : gcc_assert (m_saved_output_buffer);
191 1216194 : pp_buffer (pp) = m_saved_output_buffer;
192 : }
193 2432388 : }
194 :
195 : std::unique_ptr<per_sink_buffer>
196 98059 : text_sink::make_per_sink_buffer ()
197 : {
198 98059 : 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 1560514 : text_sink::on_report_diagnostic (const diagnostic_info &diagnostic,
206 : enum kind orig_diag_kind)
207 : {
208 1560514 : auto logger = get_logger ();
209 1560514 : DIAGNOSTICS_LOG_SCOPE_PRINTF0
210 : (logger,
211 1560514 : "diagnostics::text_sink::on_report_diagnostic");
212 :
213 1560514 : pretty_printer *pp = get_printer ();
214 :
215 1560514 : (*text_starter (&m_context)) (*this, &diagnostic);
216 :
217 1560514 : pp_output_formatted_text (pp, m_context.get_urlifier ());
218 :
219 1560514 : if (m_context.m_show_cwe)
220 1559147 : print_any_cwe (diagnostic);
221 :
222 1560514 : if (m_context.m_show_rules)
223 1559147 : print_any_rules (diagnostic);
224 :
225 1560514 : if (m_context.m_show_option_requested)
226 1559147 : 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 1560514 : if (m_show_nesting && m_show_locations_in_nesting)
231 : {
232 21741 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
233 21741 : 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 1560514 : (*text_finalizer (&m_context)) (*this,
253 : &diagnostic,
254 : orig_diag_kind);
255 :
256 1560513 : if (m_show_nesting && m_show_locations_in_nesting)
257 21741 : get_context ().m_last_location = diagnostic_location (&diagnostic);
258 1560513 : }
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 344473 : text_sink::
285 : after_diagnostic (const diagnostic_info &diagnostic)
286 : {
287 344473 : if (const paths::path *path = diagnostic.m_richloc->get_path ())
288 9671 : print_path (*path);
289 344473 : }
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 344033 : text_sink::build_prefix (const diagnostic_info &diagnostic) const
300 : {
301 344033 : gcc_assert (diagnostic.m_kind < kind::last_diagnostic_kind);
302 :
303 344033 : const char *text = _(get_text_for_kind (diagnostic.m_kind));
304 344033 : const char *text_cs = "", *text_ce = "";
305 344033 : pretty_printer *pp = get_printer ();
306 :
307 344033 : if (const char *color_name = get_color_for_kind (diagnostic.m_kind))
308 : {
309 344033 : text_cs = colorize_start (pp_show_color (pp), color_name);
310 344033 : text_ce = colorize_stop (pp_show_color (pp));
311 : }
312 :
313 344033 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
314 344033 : 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 343871 : const expanded_location s = diagnostic_expand_location (&diagnostic);
331 343871 : label_text location_text = get_location_text (s);
332 343871 : return build_message_string ("%s %s%s%s", location_text.get (),
333 : text_cs, text, text_ce);
334 343871 : }
335 : }
336 :
337 : /* Same as build_prefix, but only the source FILE is given. */
338 : char *
339 40347 : text_sink::file_name_as_prefix (const char *f) const
340 : {
341 40347 : pretty_printer *const pp = get_printer ();
342 40347 : const char *locus_cs
343 40347 : = colorize_start (pp_show_color (pp), "locus");
344 40347 : const char *locus_ce = colorize_stop (pp_show_color (pp));
345 40347 : 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 556744 : text_sink::build_indent_prefix (bool with_bullet) const
392 : {
393 556744 : if (!m_show_nesting)
394 551122 : return xstrdup ("");
395 :
396 5622 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
397 5622 : if (nesting_level == 0)
398 5079 : 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 12644 : text_sink::append_note (location_t location,
417 : const char * gmsgid, ...)
418 : {
419 12644 : context *dc = &get_context ();
420 :
421 12644 : diagnostic_info diagnostic;
422 12644 : va_list ap;
423 12644 : rich_location richloc (line_table, location);
424 :
425 12644 : va_start (ap, gmsgid);
426 12644 : diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, kind::note);
427 12644 : if (dc->m_inhibit_notes_p)
428 : {
429 0 : va_end (ap);
430 0 : return;
431 : }
432 12644 : pretty_printer *pp = get_printer ();
433 12644 : char *saved_prefix = pp_take_prefix (pp);
434 12644 : pp_set_prefix (pp, build_prefix (diagnostic));
435 12644 : pp_format (pp, &diagnostic.m_message);
436 12644 : pp_output_formatted_text (pp);
437 12644 : pp_destroy_prefix (pp);
438 12644 : pp_set_prefix (pp, saved_prefix);
439 12644 : pp_newline (pp);
440 12644 : diagnostic_show_locus (dc, get_source_printing_options (),
441 : &richloc, kind::note, pp);
442 12644 : va_end (ap);
443 12644 : }
444 :
445 : bool
446 4487240 : text_sink::follows_reference_printer_p () const
447 : {
448 4487240 : return m_follows_reference_printer;
449 : }
450 :
451 : void
452 494180 : text_sink::update_printer ()
453 : {
454 494180 : pretty_printer *copy_from_pp
455 494180 : = (m_follows_reference_printer
456 494180 : ? get_context ().get_reference_printer ()
457 0 : : m_printer.get ());
458 494180 : const bool show_color = pp_show_color (copy_from_pp);
459 494180 : const diagnostic_url_format url_format = copy_from_pp->get_url_format ();
460 :
461 494180 : m_printer = get_context ().clone_printer ();
462 :
463 494180 : pp_show_color (m_printer.get ()) = show_color;
464 494180 : m_printer->set_url_format (url_format);
465 : // ...etc
466 :
467 494180 : m_source_printing = get_context ().m_source_printing;
468 494180 : }
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 1559147 : text_sink::print_any_cwe (const diagnostic_info &diagnostic)
478 : {
479 1559147 : if (!diagnostic.m_metadata)
480 : return;
481 :
482 4362 : int cwe = diagnostic.m_metadata->get_cwe ();
483 4362 : if (cwe)
484 : {
485 3266 : pretty_printer * const pp = get_printer ();
486 3266 : char *saved_prefix = pp_take_prefix (pp);
487 3266 : pp_string (pp, " [");
488 3266 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
489 3266 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
490 3266 : 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 3266 : pp_printf (pp, "CWE-%i", cwe);
497 3266 : pp_set_prefix (pp, saved_prefix);
498 3266 : if (pp->supports_urls_p ())
499 0 : pp_end_url (pp);
500 3266 : pp_string (pp, colorize_stop (pp_show_color (pp)));
501 3266 : 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 1559147 : text_sink::print_any_rules (const diagnostic_info &diagnostic)
513 : {
514 1559147 : if (!diagnostic.m_metadata)
515 : return;
516 :
517 4813 : for (unsigned idx = 0; idx < diagnostic.m_metadata->get_num_rules (); idx++)
518 : {
519 451 : const diagnostics::metadata::rule &rule
520 451 : = diagnostic.m_metadata->get_rule (idx);
521 451 : if (char *desc = rule.make_description ())
522 : {
523 451 : pretty_printer * const pp = get_printer ();
524 451 : char *saved_prefix = pp_take_prefix (pp);
525 451 : pp_string (pp, " [");
526 451 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
527 451 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
528 451 : char *url = nullptr;
529 451 : 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 451 : pp_string (pp, desc);
536 451 : pp_set_prefix (pp, saved_prefix);
537 451 : if (pp->supports_urls_p ())
538 0 : if (url)
539 0 : pp_end_url (pp);
540 451 : free (url);
541 451 : pp_string (pp, colorize_stop (pp_show_color (pp)));
542 451 : pp_character (pp, ']');
543 451 : 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 1559147 : text_sink::print_option_information (const diagnostic_info &diagnostic,
553 : enum kind orig_diag_kind)
554 : {
555 3118294 : if (char *option_text
556 1559147 : = m_context.make_option_name (diagnostic.m_option_id,
557 1559147 : orig_diag_kind, diagnostic.m_kind))
558 : {
559 93486 : char *option_url = nullptr;
560 93486 : pretty_printer * const pp = get_printer ();
561 93486 : if (pp->supports_urls_p ())
562 0 : option_url = m_context.make_option_url (diagnostic.m_option_id);
563 93486 : pp_string (pp, " [");
564 93486 : const char *kind_color = get_color_for_kind (diagnostic.m_kind);
565 93486 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
566 93486 : if (option_url)
567 0 : pp_begin_url (pp, option_url);
568 93486 : pp_string (pp, option_text);
569 93486 : if (option_url)
570 : {
571 0 : pp_end_url (pp);
572 0 : free (option_url);
573 : }
574 93486 : pp_string (pp, colorize_stop (pp_show_color (pp)));
575 93486 : pp_character (pp, ']');
576 93486 : free (option_text);
577 : }
578 1559147 : }
579 :
580 : /* Only dump the "In file included from..." stack once for each file. */
581 :
582 : bool
583 62011 : text_sink::includes_seen_p (const line_map_ordinary *map)
584 : {
585 : /* No include path for main. */
586 62011 : if (MAIN_FILE_P (map))
587 : return true;
588 :
589 : /* Always identify C++ modules, at least for now. */
590 8358 : auto probe = map;
591 8358 : if (linemap_check_ordinary (map)->reason == LC_RENAME)
592 : /* The module source file shows up as LC_RENAME inside LC_MODULE. */
593 621 : probe = linemap_included_from_linemap (line_table, map);
594 8358 : if (MAP_MODULE_P (probe))
595 : return false;
596 :
597 7174 : if (!m_includes_seen)
598 1008 : m_includes_seen = new hash_set<location_t, false, location_hash>;
599 :
600 : /* Hash the location of the #include directive to better handle files
601 : that are included multiple times with different macros defined. */
602 7174 : return m_includes_seen->add (linemap_included_from (map));
603 : }
604 :
605 : label_text
606 343879 : text_sink::get_location_text (const expanded_location &s) const
607 : {
608 343879 : column_policy column_policy_ (get_context ());
609 343879 : return column_policy_.get_location_text (s,
610 343879 : show_column_p (),
611 343879 : pp_show_color (get_printer ()));
612 : }
613 :
614 : /* Helpers for writing lang-specific starters/finalizers for text output. */
615 :
616 : /* Return a formatted line and column ':%line:%column'. Elided if
617 : line == 0 or col < 0. (A column of 0 may be valid due to the
618 : -fdiagnostics-column-origin option.)
619 : The result is a statically allocated buffer. */
620 :
621 : const char *
622 350211 : text_sink::maybe_line_and_column (int line, int col)
623 : {
624 350211 : static char result[32];
625 :
626 350211 : if (line)
627 : {
628 345357 : size_t l
629 345357 : = snprintf (result, sizeof (result),
630 345357 : col >= 0 ? ":%d:%d" : ":%d", line, col);
631 345357 : gcc_checking_assert (l < sizeof (result));
632 : }
633 : else
634 4854 : result[0] = 0;
635 350211 : return result;
636 : }
637 :
638 : void
639 331389 : text_sink::report_current_module (location_t where)
640 : {
641 331389 : pretty_printer *pp = get_printer ();
642 331389 : const line_map_ordinary *map = nullptr;
643 :
644 331389 : if (pp_needs_newline (pp))
645 : {
646 0 : pp_newline (pp);
647 0 : pp_needs_newline (pp) = false;
648 : }
649 :
650 331389 : if (where <= BUILTINS_LOCATION)
651 3507 : return;
652 :
653 327882 : linemap_resolve_location (line_table, where,
654 : LRK_MACRO_DEFINITION_LOCATION,
655 : &map);
656 :
657 327882 : if (map && m_last_module != map)
658 : {
659 57520 : m_last_module = map;
660 57520 : if (!includes_seen_p (map))
661 : {
662 2011 : bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
663 2011 : expanded_location s = {};
664 4491 : do
665 : {
666 4491 : where = linemap_included_from (map);
667 4491 : map = linemap_included_from_linemap (line_table, map);
668 4491 : bool is_module = MAP_MODULE_P (map);
669 4491 : s.file = LINEMAP_FILE (map);
670 4491 : s.line = SOURCE_LINE (map, where);
671 4491 : int col = -1;
672 4491 : if (first && show_column_p ())
673 : {
674 1075 : s.column = SOURCE_COLUMN (map, where);
675 1075 : col = get_column_policy ().converted_column (s);
676 : }
677 4491 : const char *line_col = maybe_line_and_column (s.line, col);
678 4491 : static const char *const msgs[] =
679 : {
680 : nullptr,
681 : N_(" from"),
682 : N_("In file included from"), /* 2 */
683 : N_(" included from"),
684 : N_("In module"), /* 4 */
685 : N_("of module"),
686 : N_("In module imported at"), /* 6 */
687 : N_("imported at"),
688 : };
689 :
690 4491 : unsigned index = (was_module ? 6 : is_module ? 4
691 3307 : : need_inc ? 2 : 0) + !first;
692 :
693 6411 : pp_verbatim (pp, "%s%s %r%s%s%R",
694 : first ? "" : was_module ? ", " : ",\n",
695 4491 : _(msgs[index]),
696 : "locus", s.file, line_col);
697 4491 : first = false, need_inc = was_module, was_module = is_module;
698 : }
699 4491 : while (!includes_seen_p (map));
700 2011 : pp_verbatim (pp, ":");
701 2011 : pp_newline (pp);
702 : }
703 : }
704 : }
705 :
706 : void
707 1367 : default_text_starter (text_sink &text_output,
708 : const diagnostic_info *diagnostic)
709 : {
710 1367 : text_output.report_current_module (diagnostic_location (diagnostic));
711 1367 : pretty_printer *const pp = text_output.get_printer ();
712 1367 : pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
713 1367 : }
714 :
715 : void
716 17052 : default_text_finalizer (text_sink &text_output,
717 : const diagnostic_info *diagnostic,
718 : enum kind)
719 : {
720 17052 : pretty_printer *const pp = text_output.get_printer ();
721 17052 : char *saved_prefix = pp_take_prefix (pp);
722 17052 : pp_set_prefix (pp, nullptr);
723 17052 : pp_newline (pp);
724 17052 : diagnostic_show_locus (&text_output.get_context (),
725 17052 : text_output.get_source_printing_options (),
726 17052 : diagnostic->m_richloc, diagnostic->m_kind, pp);
727 17052 : pp_set_prefix (pp, saved_prefix);
728 17052 : pp_flush (pp);
729 17052 : }
730 :
731 : #if __GNUC__ >= 10
732 : # pragma GCC diagnostic pop
733 : #endif
734 :
735 : } // namespace diagnostics
|