diagnostics/sarif-sink.o \
diagnostics/text-sink.o \
diagnostics/lazy-paths.o \
+ diagnostics/logging.o \
diagnostics/macro-unwinding.o \
diagnostics/option-classifier.o \
diagnostics/paths.o \
#include "analyzer/common.h"
#include "diagnostics/event-id.h"
+#include "diagnostics/logging.h"
#include "cpplib.h"
#include "digraph.h"
#include "ordered-hash-map.h"
bool
diagnostic_emission_context::warn (const char *gmsgid, ...)
{
+ auto dc_logger = global_dc->get_logger ();
+ diagnostics::logging::log_function_params
+ (dc_logger, "ana::diagnostic_emission_context::warn")
+ .log_param_string ("gmsgid", gmsgid);
+ diagnostics::logging::auto_inc_depth depth_sentinel (dc_logger);
+
const pending_diagnostic &pd = get_pending_diagnostic ();
auto_diagnostic_group d;
va_list ap;
pd.get_controlling_option (),
gmsgid, &ap);
va_end (ap);
+
+ if (dc_logger)
+ dc_logger->log_bool_return ("ana::diagnostic_emission_context::warn",
+ result);
+
return result;
}
void
diagnostic_emission_context::inform (const char *gmsgid, ...)
{
+ auto dc_logger = global_dc->get_logger ();
+ diagnostics::logging::log_function_params
+ (dc_logger, "ana::diagnostic_emission_context::inform")
+ .log_param_string ("gmsgid", gmsgid);
+ diagnostics::logging::auto_inc_depth depth_sentinel (dc_logger);
+
const pending_diagnostic &pd = get_pending_diagnostic ();
auto_diagnostic_group d;
va_list ap;
#include "intl.h"
#include "diagnostic.h"
#include "diagnostics/sink.h"
+#include "diagnostics/logging.h"
/* A diagnostics::context surrogate for stderr. */
static diagnostics::context global_diagnostic_context;
diagnostics::context *global_dc = &global_diagnostic_context;
+using log_function_params = diagnostics::logging::log_function_params;
+using auto_inc_log_depth = diagnostics::logging::auto_inc_depth;
+
/* Standard error reporting routines in increasing order of severity. */
/* Text to be emitted verbatim to the error message stream; this
void
verbatim (const char *gmsgid, ...)
{
- va_list ap;
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+ va_list ap;
va_start (ap, gmsgid);
text_info text (_(gmsgid), &ap, errno);
global_dc->report_verbatim (text);
diagnostics::option_id option_id,
const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
gmsgid, &ap, kind);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("emit_diagnostic", ret);
+
return ret;
}
diagnostics::option_id option_id,
const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, option_id,
gmsgid, &ap, kind);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("emit_diagnostic", ret);
+
return ret;
}
diagnostics::option_id option_id,
const char *gmsgid, va_list *ap)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
rich_location richloc (line_table, location);
- return global_dc->diagnostic_impl (&richloc, nullptr, option_id,
- gmsgid, ap, kind);
+ bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
+ gmsgid, ap, kind);
+
+ if (logger)
+ logger->log_bool_return ("emit_diagnostic_valist", ret);
+
+ return ret;
}
/* As above, but with rich_location and metadata. */
diagnostics::option_id option_id,
const char *gmsgid, va_list *ap)
{
- return global_dc->diagnostic_impl (richloc, metadata, option_id,
- gmsgid, ap, kind);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
+ bool ret = global_dc->diagnostic_impl (richloc, metadata, option_id,
+ gmsgid, ap, kind);
+
+ if (logger)
+ logger->log_bool_return ("emit_diagnostic_valist_meta", ret);
+
+ return ret;
}
/* An informative note at LOCATION. Use this for additional details on an error
void
inform (location_t location, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
inform_n (location_t location, unsigned HOST_WIDE_INT n,
const char *singular_gmsgid, const char *plural_gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
va_list ap;
va_start (ap, plural_gmsgid);
auto_diagnostic_group d;
bool
warning (diagnostics::option_id option_id, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning", ret);
+
return ret;
}
diagnostics::option_id option_id,
const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning_at", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning_at", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning_meta", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, plural_gmsgid);
singular_gmsgid, plural_gmsgid,
&ap, diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning_n", ret);
+
return ret;
}
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid, const char *plural_gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, plural_gmsgid);
singular_gmsgid, plural_gmsgid,
&ap, diagnostics::kind::warning);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("warning_n", ret);
+
return ret;
}
diagnostics::option_id option_id,
const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::pedwarn);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("pedwarn", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::pedwarn);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("pedwarn", ret);
+
return ret;
}
bool
permerror (location_t location, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
diagnostics::kind::permerror);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("permerror", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap,
diagnostics::kind::permerror);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("permerror", ret);
+
return ret;
}
diagnostics::option_id option_id,
const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::permerror);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("permerror_opt", ret);
+
return ret;
}
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_option_id ("option_id", option_id)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
gmsgid, &ap,
diagnostics::kind::permerror);
va_end (ap);
+
+ if (logger)
+ logger->log_bool_return ("permerror_opt", ret);
+
return ret;
}
void
error (const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
error_n (location_t location, unsigned HOST_WIDE_INT n,
const char *singular_gmsgid, const char *plural_gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("location", location)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, plural_gmsgid);
void
error_at (location_t loc, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("loc", loc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
{
gcc_assert (richloc);
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_rich_location ("richloc", richloc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
void
sorry (const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
void
sorry_at (location_t loc, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("loc", loc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
void
fatal_error (location_t loc, const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_location_t ("loc", loc)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
void
internal_error (const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
void
internal_error_no_backtrace (const char *gmsgid, ...)
{
+ auto logger = global_dc->get_logger ();
+ log_function_params (logger, __func__)
+ .log_param_string ("gmsgid", gmsgid);
+ auto_inc_log_depth depth_sentinel (logger);
+
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
#include "diagnostics/buffering.h"
#include "diagnostics/file-cache.h"
#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
m_diagrams.m_theme = nullptr;
m_original_argv = nullptr;
m_diagnostic_buffer = nullptr;
+ m_logger = nullptr;
enum diagnostic_text_art_charset text_art_charset
= DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI;
text_art_charset = DIAGNOSTICS_TEXT_ART_CHARSET_ASCII;
}
set_text_art_charset (text_art_charset);
+
+ if (const char *name = getenv ("GCC_DIAGNOSTICS_LOG"))
+ {
+ if (name[0] != '\0')
+ {
+ /* Try to write a log to the named path. */
+ if (FILE *outfile = fopen (name, "w"))
+ m_logger = new logging::logger
+ (output_file (outfile, true,
+ label_text::take (xstrdup (name))));
+ }
+ else
+ /* Write a log to stderr. */
+ m_logger = new logging::logger
+ (output_file
+ (stderr, false,
+ label_text::borrow ("stderr")));
+ }
+
+ if (m_logger)
+ m_logger->log_printf ("diagnostics::context::initialize");
}
/* Maybe initialize the color support. We require clients to do this
void
context::finish ()
{
+ if (m_logger)
+ {
+ m_logger->log_printf ("diagnostics::context::finish");
+ /* We're cleaning up the logger before this function exits,
+ so we can't use auto_inc_depth here. */
+ m_logger->inc_depth ();
+ dump (m_logger->get_stream (), m_logger->get_indent ());
+ }
+
/* We might be handling a fatal error.
Close any active diagnostic groups, which may trigger flushing
sinks. */
freeargv (m_original_argv);
m_original_argv = nullptr;
+
+ delete m_logger;
+ m_logger = nullptr;
}
/* Dump state of this diagnostics::context to OUT, for debugging. */
void
-context::dump (FILE *outfile) const
+context::dump (FILE *outfile, int indent) const
{
- dumping::emit_heading (outfile, 0, "diagnostics::context");
- m_diagnostic_counters.dump (outfile, 2);
- dumping::emit_heading (outfile, 2, "reference printer");
+ dumping::emit_heading (outfile, indent, "diagnostics::context");
+ m_diagnostic_counters.dump (outfile, indent + 2);
+ dumping::emit_heading (outfile, indent + 2, "reference printer");
if (m_reference_printer)
- m_reference_printer->dump (outfile, 4);
+ m_reference_printer->dump (outfile, indent + 4);
else
- dumping::emit_none (outfile, 4);
- dumping::emit_heading (outfile, 2, "output sinks");
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "output sinks");
if (m_sinks.length () > 0)
{
for (unsigned i = 0; i < m_sinks.length (); ++i)
{
- dumping::emit_indent (outfile, 4);
+ dumping::emit_indent (outfile, indent + 4);
const sink *s = m_sinks[i];
fprintf (outfile, "sink %i (", i);
s->dump_kind (outfile);
fprintf (outfile, "):\n");
- s->dump (outfile, 6);
+ s->dump (outfile, indent + 6);
}
}
else
- dumping::emit_none (outfile, 4);
- dumping::emit_heading (outfile, 2, "diagnostic buffer");
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "diagnostic buffer");
if (m_diagnostic_buffer)
- m_diagnostic_buffer->dump (outfile, 4);
+ m_diagnostic_buffer->dump (outfile, indent + 4);
else
- dumping::emit_none (outfile, 4);
- dumping::emit_heading (outfile, 2, "file cache");
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "file cache");
if (m_file_cache)
- m_file_cache->dump (outfile, 4);
+ m_file_cache->dump (outfile, indent + 4);
else
- dumping::emit_none (outfile, 4);
+ dumping::emit_none (outfile, indent + 4);
}
/* Return true if sufficiently severe diagnostics have been seen that
void
context::set_sink (std::unique_ptr<sink> sink_)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_logger, "diagnostics::context::set_sink");
+ if (m_logger)
+ sink_->dump (m_logger->get_stream (), m_logger->get_indent ());
remove_all_output_sinks ();
m_sinks.safe_push (sink_.release ());
}
void
context::add_sink (std::unique_ptr<sink> sink_)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_logger, "diagnostics::context::add_sink");
+ if (m_logger)
+ sink_->dump (m_logger->get_stream (), m_logger->get_indent ());
m_sinks.safe_push (sink_.release ());
}
return diagnostic_kind_text[static_cast<int> (kind)];
}
+static const char *const diagnostic_kind_debug_text[] = {
+#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (#K),
+#include "diagnostics/kinds.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+ "must-not-happen"
+};
+
+const char *
+get_debug_string_for_kind (enum kind kind)
+{
+ return diagnostic_kind_debug_text[static_cast<int> (kind)];
+}
+
static const char *const diagnostic_kind_color[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
#include "diagnostics/kinds.def"
bool
context::report_diagnostic (diagnostic_info *diagnostic)
{
+ auto logger = get_logger ();
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (logger, "diagnostics::context::report_diagnostic");
+
enum kind orig_diag_kind = diagnostic->m_kind;
/* Every call to report_diagnostic should be within a
if (was_warning && m_inhibit_warnings)
{
inhibit_notes_in_group ();
+ if (m_logger)
+ m_logger->log_printf ("rejecting: inhibiting warnings");
return false;
}
}
if (diagnostic->m_kind == kind::note && m_inhibit_notes_p)
- return false;
+ {
+ if (m_logger)
+ m_logger->log_printf ("rejecting: inhibiting notes");
+ return false;
+ }
/* If the user requested that warnings be treated as errors, so be
it. Note that we do this before the next block so that
stack. . */
if (!diagnostic_enabled (diagnostic))
{
+ if (m_logger)
+ m_logger->log_printf ("rejecting: diagnostic not enabled");
inhibit_notes_in_group ();
return false;
}
&& ((!m_warn_system_headers
&& diagnostic->m_iinfo.m_allsyslocs)
|| m_inhibit_warnings))
- /* Bail if the warning is not to be reported because all locations in the
- inlining stack (if there is one) are in system headers. */
- return false;
+ {
+ /* Bail if the warning is not to be reported because all locations in the
+ inlining stack (if there is one) are in system headers. */
+ if (m_logger)
+ m_logger->log_printf ("rejecting: warning in system header");
+ return false;
+ }
if (diagnostic->m_kind == kind::note && notes_inhibited_in_group ())
- /* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
- return false;
+ {
+ /* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
+ if (m_logger)
+ m_logger->log_printf ("rejecting: notes inhibited within group");
+ return false;
+ }
if (diagnostic->m_kind != kind::note && diagnostic->m_kind != kind::ice)
check_max_errors (false);
/* Is this the initial diagnostic within the stack of groups? */
if (m_diagnostic_groups.m_emission_count == 0)
- for (auto sink_ : m_sinks)
- sink_->on_begin_group ();
+ {
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::context: beginning group");
+ for (auto sink_ : m_sinks)
+ sink_->on_begin_group ();
+ }
m_diagnostic_groups.m_emission_count++;
va_list *orig_args = diagnostic->m_message.m_args_ptr;
const char *gmsgid,
va_list *ap, enum kind kind)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::diagnostic_impl")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("kind", kind)
+ .log_param_string ("gmsgid", gmsgid);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
diagnostic_info diagnostic;
if (kind == diagnostics::kind::permerror)
{
diagnostic.m_option_id = opt_id;
}
diagnostic.m_metadata = metadata;
- return report_diagnostic (&diagnostic);
+
+ bool ret = report_diagnostic (&diagnostic);
+ if (m_logger)
+ m_logger->log_bool_return ("diagnostics::context::diagnostic_impl", ret);
+ return ret;
}
/* Implement inform_n, warning_n, and error_n, as documented and
const char *plural_gmsgid,
va_list *ap, enum kind kind)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::diagnostic_n_impl")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("kind", kind)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
diagnostic_info diagnostic;
unsigned long gtn;
if (kind == diagnostics::kind::warning)
diagnostic.m_option_id = opt_id;
diagnostic.m_metadata = metadata;
- return report_diagnostic (&diagnostic);
+
+ bool ret = report_diagnostic (&diagnostic);
+ if (m_logger)
+ m_logger->log_bool_return ("diagnostics::context::diagnostic_n_impl", ret);
+ return ret;
}
If any diagnostics were emitted, give the context a chance
to do something. */
if (m_diagnostic_groups.m_emission_count > 0)
- for (auto sink_ : m_sinks)
- sink_->on_end_group ();
+ {
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::context::end_group: ending group");
+ for (auto sink_ : m_sinks)
+ sink_->on_end_group ();
+ }
m_diagnostic_groups.m_emission_count = 0;
}
/* We're popping one level, so might need to stop inhibiting notes. */
#include "diagnostics/source-printing-options.h"
#include "diagnostics/column-options.h"
#include "diagnostics/counters.h"
+#include "diagnostics/logging.h"
namespace diagnostics {
void finish ();
- void dump (FILE *out) const;
- void DEBUG_FUNCTION dump () const { dump (stderr); }
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+
+ logging::logger *get_logger () { return m_logger; }
bool execution_failed_p () const;
enum kind new_kind,
location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::classify_diagnostics")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("new_kind", new_kind)
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
return m_option_classifier.classify_diagnostic (this,
opt_id,
new_kind,
where);
}
- void push_diagnostics (location_t where ATTRIBUTE_UNUSED)
+ void push_diagnostics (location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::push_diagnostics")
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
m_option_classifier.push ();
}
void pop_diagnostics (location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::pop_diagnostics")
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
m_option_classifier.pop (where);
}
later (if the buffer is flushed), moved to other buffers, or
discarded (if the buffer is cleared). */
buffer *m_diagnostic_buffer;
+
+ /* Owned by the context.
+ Debugging option: if non-NULL, report information to the logger
+ on what the context is doing. */
+ logging::logger *m_logger;
};
/* Client supplied function to announce a diagnostic
#include "diagnostics/buffering.h"
#include "diagnostics/paths.h"
#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "diagnostics/client-data-hooks.h"
#include "selftest.h"
#include "diagnostics/selftest-context.h"
void
html_builder::flush_to_file (FILE *outf)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::html_builder::flush_to_file");
if (m_html_gen_opts.m_javascript)
{
gcc_assert (m_head_element);
on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind) final override
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::html_sink::on_report_diagnostic");
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
void on_diagram (const diagram &d) final override
};
extern const char *get_text_for_kind (enum diagnostics::kind);
+extern const char *get_debug_string_for_kind (enum diagnostics::kind);
extern const char *get_color_for_kind (enum diagnostics::kind);
} // namespace diagnostics
--- /dev/null
+/* Utilities for implementing "dump" functions for the diagnostics subsystem.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostics/logging.h"
+
+namespace diagnostics {
+namespace logging {
+
+logger::logger (output_file outfile)
+: m_outfile (std::move (outfile)),
+ m_log_depth (0)
+{
+}
+
+void
+logger::log_printf (const char *fmt, ...)
+{
+ emit_indent ();
+
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (get_stream (), fmt, ap);
+ va_end (ap);
+
+ emit_newline ();
+}
+
+void
+logger::log_bool_return (const char *function_name, bool retval)
+{
+ log_printf ("%s <- %s",
+ retval ? "true" : "false",
+ function_name);
+}
+
+/* Emit indentation to OUTFILE for the start of a log line. */
+
+void
+logger::emit_indent () const
+{
+ fprintf (get_stream (), "%*s", get_indent (), "");
+}
+
+void
+logger::emit_newline () const
+{
+ fputc ('\n', get_stream ());
+}
+
+} // namespace logging {
+} // namespace diagnostics
--- /dev/null
+/* Debugging code for logging what the diagnostics subsystem is doing.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_LOGGING_H
+#define GCC_DIAGNOSTICS_LOGGING_H
+
+#include "diagnostics/output-file.h"
+#include "diagnostics/option-id.h"
+#include "diagnostics/kinds.h"
+
+namespace diagnostics {
+
+namespace logging {
+
+/* A class for emitting a temporal log of what the diagnostics subsystem
+ is doing, for debugging.
+ We can't use pretty_printer here as we could potentially be debugging
+ pretty-printing itself. */
+
+class logger
+{
+public:
+ logger (output_file outfile);
+
+ /* High-level functions that emit a line of text. */
+ void log_printf (const char *fmt, ...)
+ __attribute__ ((__format__ (printf, 2, 3)));
+ void log_bool_return (const char *function_name, bool retval);
+
+ /* Lower-level functions for building up a line of text. */
+ void emit_indent () const;
+ void emit_newline () const;
+
+ FILE *get_stream () const
+ {
+ return m_outfile.get_open_file ();
+ }
+
+ int get_indent () const { return m_log_depth * 2; }
+
+ void inc_depth () { m_log_depth++; }
+ void dec_depth () { m_log_depth--; }
+
+private:
+ output_file m_outfile;
+ int m_log_depth;
+};
+
+/* RAII class for pushing/popping depth within a logger. */
+
+class auto_inc_depth
+{
+public:
+ auto_inc_depth (logger *log)
+ : m_logger (log)
+ {
+ if (m_logger)
+ m_logger->inc_depth ();
+ }
+ ~auto_inc_depth ()
+ {
+ if (m_logger)
+ m_logger->dec_depth ();
+ }
+
+private:
+ logger *m_logger;
+};
+
+/* Class for debugging function call parameters. */
+
+class log_function_params
+{
+public:
+ log_function_params (logger *logger_, const char *name)
+ : m_logger (logger_),
+ m_first_param (true)
+ {
+ if (m_logger)
+ {
+ m_logger->emit_indent ();
+ fprintf (m_logger->get_stream (), "%s (", name);
+ }
+ }
+ ~log_function_params ()
+ {
+ if (m_logger)
+ {
+ fprintf (m_logger->get_stream (), ")");
+ m_logger->emit_newline ();
+ }
+ }
+
+ log_function_params &
+ log_param_string (const char *name, const char *value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: \"%s\"", name, value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_location_t (const char *name, location_t value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: " HOST_SIZE_T_PRINT_HEX,
+ name, (size_t)value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_rich_location (const char *name, const rich_location *richloc)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: %p",
+ name, const_cast<void *> ((const void *)richloc));
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_option_id (const char *name, diagnostics::option_id value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: %i", name, value.m_idx);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_kind (const char *name, enum diagnostics::kind value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: %s",
+ name, get_debug_string_for_kind (value));
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_uhwi (const char *name, unsigned HOST_WIDE_INT value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: " HOST_WIDE_INT_PRINT_DEC,
+ name, value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_params_n_gmsgids (unsigned HOST_WIDE_INT n,
+ const char *singular_gmsgid,
+ const char *plural_gmsgid)
+ {
+ return log_param_uhwi ("n", n)
+ .log_param_string ("singular_gmsgid", singular_gmsgid)
+ .log_param_string ("plural_gmsgid", plural_gmsgid);
+ }
+
+private:
+ void
+ add_any_comma ()
+ {
+ gcc_assert (m_logger);
+ if (m_first_param)
+ m_first_param = false;
+ else
+ fprintf (m_logger->get_stream (), ", ");
+ }
+
+ logger *m_logger;
+ bool m_first_param;
+};
+
+} // namespace logging
+} // namespace diagnostics
+
+/* Various macros for logging a formatted line, and indenting
+ further log messages within a scope. */
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF0(LOGGER, FMT) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF1(LOGGER, FMT, ARG0) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT), (ARG0)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF2(LOGGER, FMT, ARG0, ARG1) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT), (ARG0), (ARG1)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#endif /* ! GCC_DIAGNOSTICS_LOGGING_H */
#ifndef GCC_DIAGNOSTICS_OUTPUT_FILE_H
#define GCC_DIAGNOSTICS_OUTPUT_FILE_H
+#include "label-text.h"
+
namespace diagnostics {
/* RAII class for wrapping a FILE * that could be borrowed or owned,
#include "diagnostics/sink.h"
#include "diagnostics/buffering.h"
#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "json.h"
#include "cpplib.h"
#include "diagnostics/logical-locations.h"
std::unique_ptr<sarif_log>
sarif_builder::flush_to_object ()
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::sarif_builder::flush_to_object");
m_invocation_obj->prepare_to_flush (*this);
std::unique_ptr<sarif_log> top
= make_top_level_object (std::move (m_invocation_obj),
void
sarif_builder::flush_to_file (FILE *outf)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::sarif_builder::flush_to_file");
std::unique_ptr<sarif_log> top = flush_to_object ();
m_serialization_format->write_to_file (outf, *top);
}
on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind) final override
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::sarif_sink::on_report_diagnostic");
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
void on_diagram (const diagram &d) final override
void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+ logging::logger *get_logger () { return m_context.get_logger (); }
+
protected:
sink (context &dc)
: m_context (dc),
#include "diagnostics/text-sink.h"
#include "diagnostics/buffering.h"
#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "text-art/theme.h"
/* Disable warnings about quoting issues in the pp_xxx calls below
text_sink::on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind)
{
+ auto logger = get_logger ();
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (logger,
+ "diagnostics::text_sink::on_report_diagnostic");
+
pretty_printer *pp = get_printer ();
(*text_starter (&m_context)) (*this, &diagnostic);
the output of the preprocessor, which is the input to the compiler
proper.
+@vindex GCC_DIAGNOSTICS_LOG
+@item GCC_DIAGNOSTICS_LOG
+If @env{GCC_DIAGNOSTICS_LOG} is set, then additional information
+about the diagnostics subsystem will be emitted. If it is set to an empty
+value, then the information will be written to stderr; otherwise, GCC will
+attempt to open that file and write the information there.
+
+The precise content and format of the information is subject to change;
+it is intended for use by GCC developers, rather than end-users.
+
@vindex GCC_COMPARE_DEBUG
@item GCC_COMPARE_DEBUG
Setting @env{GCC_COMPARE_DEBUG} is nearly equivalent to passing
#include "intl.h"
#include "diagnostic.h"
#include "diagnostics/output-spec.h"
+#include "diagnostics/logging.h"
#include "opts.h"
#include "options.h"
gcc_assert (line_table);
const char *const option_name = "-fdiagnostics-add-output=";
+ DIAGNOSTICS_LOG_SCOPE_PRINTF2 (dc.get_logger (),
+ "handling: %s%s", option_name, arg);
opt_spec_context ctxt (opts, dc, line_table, loc, option_name);
auto sink = ctxt.parse_and_make_sink (arg, dc);
if (!sink)
gcc_assert (line_table);
const char *const option_name = "-fdiagnostics-set-output=";
+ DIAGNOSTICS_LOG_SCOPE_PRINTF2 (dc.get_logger (),
+ "handling: %s%s", option_name, arg);
opt_spec_context ctxt (opts, dc, line_table, loc, option_name);
auto sink = ctxt.parse_and_make_sink (arg, dc);
if (!sink)