public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] RFC: elide repeated source locations (PR other/84889)
@ 2018-11-12  1:56 David Malcolm
  2018-11-12 20:38 ` Martin Sebor
  0 siblings, 1 reply; 5+ messages in thread
From: David Malcolm @ 2018-11-12  1:56 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

We often emit more than one diagnostic at the same source location.
For example, the C++ frontend can emit many diagnostics at
the same source location when suggesting overload candidates.

For example:

../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In function 'int test_3(s, t)':
../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: error: no match for 'operator&&' (operand types are 's' and 't')
   38 |   return param_s && param_t;
      |          ~~~~~~~~^~~~~~~~~~
../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: note: candidate: 'operator&&(bool, bool)' <built-in>
../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: note:   no known conversion for argument 2 from 't' to 'bool'

This is overly verbose.  Note how the same location has been printed
three times, obscuring the pertinent messages.

This patch add a new "elide" value to -fdiagnostics-show-location=
and makes it the default (previously it was "once").  With elision
the above is printed as:

../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In function 'int test_3(s, t)':
../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: error: no match for 'operator&&' (operand types are 's' and 't')
   38 |   return param_s && param_t;
      |          ~~~~~~~~^~~~~~~~~~
      = note: candidate: 'operator&&(bool, bool)' <built-in>
      = note:   no known conversion for argument 2 from 't' to 'bool'

where the followup notes are printed with a '=' lined up with
the source code margin.

Thoughts?
Dave

TODO: the selftests currently assume LANG=C.  Clearly this would
need fixing before committing.

TODO: potentially integrate this with auto_diagnostic_group, so
we only elide within a logically-related diagnostic (and thus
make auto_diagnostic_group do something user-visible).

(FWIW, the output format is inspired by Rust)

gcc/ChangeLog:
	PR other/84889
	* common.opt (fdiagnostics-show-location=): Add "elide".
	(Enum(diagnostic_prefixing_rule)): Add "elide" value.
	* diagnostic-show-locus.c (layout::print_source_line): Set
	last_margin.
	(diagnostic_show_locus): Reset last_margin, saving it and
	restoring it if bailing out.
	(selftest::test_one_liner_elide_location): New test.
	FIXME: require LANG=C, or fix the test to work with i18n.
	(selftest::test_diagnostic_show_locus_one_liner): Call it.
	* diagnostic.c (diagnostic_initialize): Initialize "last_margin"
	and "override_file".
	(diagnostic_get_location_text): Use context->override_file
	if non-NULL.
	(diagnostic_build_prefix): Handle DIAGNOSTICS_SHOW_PREFIX_ELIDE.
	(selftest::assert_location_text): Set dc.override_file.
	* diagnostic.h (struct diagnostic_context): Add fields
	"last_margin" and "override_file".
	* doc/invoke.texi (-fdiagnostics-show-location=elide): Document.
	(-fdiagnostics-show-location=once): Remove "default behavior"
	text.
	* pretty-print.c (pp_set_real_maximum_length): Handle
	DIAGNOSTICS_SHOW_PREFIX_ELIDE.
	(pp_emit_prefix): Likewise.
	(pretty_printer::pretty_printer): Default to
	DIAGNOSTICS_SHOW_PREFIX_ELIDE.
	* pretty-print.h (enum diagnostic_prefixing_rule_t): Add
	DIAGNOSTICS_SHOW_PREFIX_ELIDE.  Document inline.
	* selftest-diagnostic.c
	(selftest::test_diagnostic_context::test_diagnostic_context):
	Set buffer's stream and flush_p.  Set override_file.
	(selftest::global_dc_test::global_dc_test): New ctor.
	(selftest::global_dc_test::~global_dc_test): New dtor.
	* selftest-diagnostic.h (class selftest::global_dc_test): New
	class.

gcc/testsuite/ChangeLog:
	PR other/84889
	* lib/prune.exp (TEST_ALWAYS_FLAGS): Add
	-fdiagnostics-show-location=once.
---
 gcc/common.opt              |   5 +-
 gcc/diagnostic-show-locus.c | 135 +++++++++++++++++++++++++++++++++++++++++++-
 gcc/diagnostic.c            |  70 ++++++++++++++++++++++-
 gcc/diagnostic.h            |   8 +++
 gcc/doc/invoke.texi         |  10 +++-
 gcc/pretty-print.c          |   7 ++-
 gcc/pretty-print.h          |  22 +++++---
 gcc/selftest-diagnostic.c   |  21 +++++++
 gcc/selftest-diagnostic.h   |  16 ++++++
 gcc/testsuite/lib/prune.exp |   1 +
 10 files changed, 279 insertions(+), 16 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 5a5d332..010ca0c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1222,7 +1222,7 @@ Try to convert virtual calls to direct ones.
 
 fdiagnostics-show-location=
 Common Joined RejectNegative Enum(diagnostic_prefixing_rule)
--fdiagnostics-show-location=[once|every-line]	How often to emit source location at the beginning of line-wrapped diagnostics.
+-fdiagnostics-show-location=[elide|once|every-line]	How often to emit source location at the beginning of diagnostics.
 
 ; Required for these enum values.
 SourceInclude
@@ -1237,6 +1237,9 @@ Enum(diagnostic_prefixing_rule) String(once) Value(DIAGNOSTICS_SHOW_PREFIX_ONCE)
 EnumValue
 Enum(diagnostic_prefixing_rule) String(every-line) Value(DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE)
 
+EnumValue
+Enum(diagnostic_prefixing_rule) String(elide) Value(DIAGNOSTICS_SHOW_PREFIX_ELIDE)
+
 fdiagnostics-show-caret
 Common Var(flag_diagnostics_show_caret) Init(1)
 Show the source line with a caret indicating the column.
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index a42ff81..2c8bb2b 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -1313,6 +1313,7 @@ layout::print_source_line (linenum_type row, const char *line, int line_width,
       for (int i = 0; i < m_linenum_width - width; i++)
 	pp_space (m_pp);
       pp_printf (m_pp, "%i | ", row);
+      m_context->last_margin = m_linenum_width + 1;
     }
   else
     pp_space (m_pp);
@@ -2309,6 +2310,11 @@ diagnostic_show_locus (diagnostic_context * context,
 {
   pp_newline (context->printer);
 
+  int saved_last_margin = context->last_margin;
+
+  /* Reset last_margin.  */
+  context->last_margin = -1;
+
   location_t loc = richloc->get_loc ();
   /* Do nothing if source-printing has been disabled.  */
   if (!context->show_caret)
@@ -2322,7 +2328,11 @@ diagnostic_show_locus (diagnostic_context * context,
      fix-it hints.  */
   if (loc == context->last_location
       && richloc->get_num_fixit_hints () == 0)
-    return;
+    {
+      /* Bail out, retaining the value of context->last_margin.  */
+      context->last_margin = saved_last_margin;
+      return;
+    }
 
   context->last_location = loc;
 
@@ -2841,6 +2851,128 @@ test_one_liner_labels ()
      gcc-rich-location.c due to Makefile.in issues).  */
 }
 
+/* Ensure that DIAGNOSTICS_SHOW_PREFIX_ELIDE works as expected.  */
+
+static void
+test_one_liner_elide_location ()
+{
+  location_t start = linemap_position_for_column (line_table, 11);
+  location_t finish = linemap_position_for_column (line_table, 15);
+  location_t field = make_location (start, start, finish);
+
+  /* Test the various combinations of
+     - with/without line numbers
+     - with/without elision.  */
+
+  /* With elision.  */
+  {
+    test_diagnostic_context dc;
+    global_dc_test gdt (&dc);
+    rich_location richloc (line_table, field);
+    richloc.add_fixit_replace ("m_field");
+    error_at (&richloc, "the error message");
+    inform (field, "the inform message");
+    ASSERT_STREQ ("FILENAME:1:11: error: the error message\n"
+		  " foo = bar.field;\n"
+		  "           ^~~~~\n"
+		  "           m_field\n"
+		  "   note: the inform message\n",
+		  pp_formatted_text (dc.printer));
+  }
+  {
+    test_diagnostic_context dc;
+    dc.show_line_numbers_p = true;
+    global_dc_test gdt (&dc);
+    rich_location richloc (line_table, field);
+    richloc.add_fixit_replace ("m_field");
+    error_at (&richloc, "the error message");
+    inform (field, "the 1st inform message");
+    inform (field, "the 2nd inform message");
+    ASSERT_STREQ ("FILENAME:1:11: error: the error message\n"
+		  "    1 | foo = bar.field;\n"
+		  "      |           ^~~~~\n"
+		  "      |           m_field\n"
+		  "      = note: the 1st inform message\n"
+		  "      = note: the 2nd inform message\n",
+		  pp_formatted_text (dc.printer));
+  }
+
+  {
+    /* Verify handling of UNKNOWN_LOCATION.  */
+    const char *old_progname = progname;
+    progname = "PROGNAME";
+    test_diagnostic_context dc;
+    dc.show_line_numbers_p = true;
+    global_dc_test gdt (&dc);
+    error_at (UNKNOWN_LOCATION, "the error message");
+    ASSERT_STREQ ("PROGNAME: error: the error message\n",
+		  pp_formatted_text (dc.printer));
+    progname = old_progname;
+  }
+  {
+    /* Verify handling of BUILTINS_LOCATION.  */
+    test_diagnostic_context dc;
+    dc.show_line_numbers_p = true;
+    global_dc_test gdt (&dc);
+    error_at (BUILTINS_LOCATION, "the error message");
+    inform (BUILTINS_LOCATION, "the inform message");
+    ASSERT_STREQ ("<built-in>: error: the error message\n"
+		  "<built-in>: note: the inform message\n",
+		  pp_formatted_text (dc.printer));
+  }
+  {
+    /* With a fix-it hint on the followup.  */
+    test_diagnostic_context dc;
+    dc.show_line_numbers_p = true;
+    global_dc_test gdt (&dc);
+    error_at (field, "the error message");
+    rich_location richloc (line_table, field);
+    richloc.add_fixit_replace ("m_field");
+    inform (&richloc, "the inform message");
+    ASSERT_STREQ ("FILENAME:1:11: error: the error message\n"
+		  "    1 | foo = bar.field;\n"
+		  "      |           ^~~~~\n"
+		  "      = note: the inform message\n"
+		  "    1 | foo = bar.field;\n"
+		  "      |           ^~~~~\n"
+		  "      |           m_field\n",
+		  pp_formatted_text (dc.printer));
+  }
+
+  /* Without elision.  */
+  {
+    test_diagnostic_context dc;
+    pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+    global_dc_test gdt (&dc);
+    rich_location richloc (line_table, field);
+    richloc.add_fixit_replace ("m_field");
+    error_at (&richloc, "the error message");
+    inform (field, "the inform message");
+    ASSERT_STREQ ("FILENAME:1:11: error: the error message\n"
+		  " foo = bar.field;\n"
+		  "           ^~~~~\n"
+		  "           m_field\n"
+		  "FILENAME:1:11: note: the inform message\n",
+		  pp_formatted_text (dc.printer));
+  }
+  {
+    test_diagnostic_context dc;
+    pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+    dc.show_line_numbers_p = true;
+    global_dc_test gdt (&dc);
+    rich_location richloc (line_table, field);
+    richloc.add_fixit_replace ("m_field");
+    error_at (&richloc, "the error message");
+    inform (field, "the inform message");
+    ASSERT_STREQ ("FILENAME:1:11: error: the error message\n"
+		  "    1 | foo = bar.field;\n"
+		  "      |           ^~~~~\n"
+		  "      |           m_field\n"
+		  "FILENAME:1:11: note: the inform message\n",
+		  pp_formatted_text (dc.printer));
+  }
+}
+
 /* Run the various one-liner tests.  */
 
 static void
@@ -2878,6 +3010,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
   test_one_liner_many_fixits_1 ();
   test_one_liner_many_fixits_2 ();
   test_one_liner_labels ();
+  test_one_liner_elide_location ();
 }
 
 /* Verify that gcc_rich_location::add_location_if_nearby works.  */
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index a572c08..72cbe9a 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -180,11 +180,13 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   context->min_margin_width = 0;
   context->show_ruler_p = false;
   context->parseable_fixits_p = false;
+  context->last_margin = -1;
   context->edit_context_ptr = NULL;
   context->diagnostic_group_nesting_depth = 0;
   context->diagnostic_group_emission_count = 0;
   context->begin_group_cb = NULL;
   context->end_group_cb = NULL;
+  context->override_file = NULL;
 }
 
 /* Maybe initialize the color support. We require clients to do this
@@ -327,8 +329,25 @@ diagnostic_get_location_text (diagnostic_context *context,
   pretty_printer *pp = context->printer;
   const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
   const char *locus_ce = colorize_stop (pp_show_color (pp));
-  const char *file = s.file ? s.file : progname;
-  int line = strcmp (file, N_("<built-in>")) ? s.line : 0;
+  const char *file;
+  int line;
+  if (s.file)
+    {
+      file = s.file;
+      if (strcmp (file, N_("<built-in>")))
+	{
+	  if (context->override_file)
+	    file = context->override_file;
+	  line = s.line;
+	}
+      else
+	line = 0;
+    }
+  else
+    {
+      file = progname;
+      line = s.line;
+    }
   int col = context->show_column ? s.column : 0;
 
   const char *line_col = maybe_line_and_column (line, col);
@@ -362,6 +381,52 @@ diagnostic_build_prefix (diagnostic_context *context,
       text_ce = colorize_stop (pp_show_color (pp));
     }
 
+  /* Don't bother printing the location in the prefix if we have a diagnostic
+     with the same location as the previous diagnostic.  This makes the
+     diagnostics less "dense" visually, so that e.g.:
+
+       PATH_WHICH_COULD_BE_VERY_LONG/SOME_FILENAME:LINE:COLUMN: error: MESSAGE_1
+        SOURCE VIEW
+       PATH_WHICH_COULD_BE_VERY_LONG/SOME_FILENAME:LINE:COLUMN: note: MESSAGE_2
+       PATH_WHICH_COULD_BE_VERY_LONG/SOME_FILENAME:LINE:COLUMN: note: MESSAGE_3
+
+     can be instead printed as:
+
+       PATH_WHICH_COULD_BE_VERY_LONG/SOME_FILENAME:LINE:COLUMN: error: MESSAGE_1
+        SOURCE VIEW
+          note: MESSAGE_2
+          note: MESSAGE_3
+
+     or, with line numbers:
+
+       PATH_WHICH_COULD_BE_VERY_LONG/SOME_FILENAME:LINE:COLUMN: error: MESSAGE_1
+       nn | SOURCE VIEW
+          = note: MESSAGE_2
+          = note: MESSAGE_3
+
+     This should also make it easier for the user to see the boundaries between
+     logically-related diagnostics.  */
+  if (pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ELIDE)
+    {
+      location_t loc = diagnostic->richloc->get_loc ();
+      // FIXME: but not if a builtin location?
+      if (loc == context->last_location
+	  && loc != UNKNOWN_LOCATION)
+	{
+	  /* last_margin is set when printing the left margin.  */
+	  if (context->last_margin >= 0)
+	    {
+	      pretty_printer pp;
+	      for (int i = 0; i < context->last_margin; i++)
+		pp_character (&pp, ' ');
+	      pp_printf (&pp, "= %s%s%s", text_cs, text, text_ce);
+	      return xstrdup (pp_formatted_text (&pp));
+	    }
+	  else
+	    return build_message_string ("   %s%s%s", text_cs, text, text_ce);
+	}
+    }
+
   expanded_location s = diagnostic_expand_location (diagnostic);
   char *location_text = diagnostic_get_location_text (context, s);
 
@@ -1740,6 +1805,7 @@ assert_location_text (const char *expected_loc_text,
 {
   test_diagnostic_context dc;
   dc.show_column = show_column;
+  dc.override_file = NULL;
 
   expanded_location xloc;
   xloc.file = filename;
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 3498a9b..28ac278 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -223,6 +223,10 @@ struct diagnostic_context
      rest of the diagnostic.  */
   bool parseable_fixits_p;
 
+  /* For use with DIAGNOSTICS_SHOW_PREFIX_ELIDE: the width of the last
+     margin, or -1 if there was no margin.  */
+  int last_margin;
+
   /* If non-NULL, an edit_context to which fix-it hints should be
      applied, for generating patches.  */
   edit_context *edit_context_ptr;
@@ -243,6 +247,10 @@ struct diagnostic_context
   /* If non-NULL, this will be called when a stack of groups is
      popped if any diagnostics were emitted within that group.  */
   void (*end_group_cb) (diagnostic_context * context);
+
+  /* For use in selftests: if non-NULL, then use this string when
+     printing filenames.  */
+  const char *override_file;
 };
 
 static inline void
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4ff3a150..49b7962 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3673,14 +3673,20 @@ Note - this option also affects the display of the @samp{#error} and
 function/type/variable attribute.  It does not however affect the
 @samp{pragma GCC warning} and @samp{pragma GCC error} pragmas.
 
+@item -fdiagnostics-show-location=elide
+@opindex fdiagnostics-show-location
+Instructs the diagnostic messages reporter to only emit source location
+information once within a given diagnostic, and to elide such locations
+for followup diagnostics that have the same location.
+This is the default behavior.
+
 @item -fdiagnostics-show-location=once
 @opindex fdiagnostics-show-location
 Only meaningful in line-wrapping mode.  Instructs the diagnostic messages
 reporter to emit source location information @emph{once}; that is, in
 case the message is too long to fit on a single physical line and has to
 be wrapped, the source location won't be emitted (as prefix) again,
-over and over, in subsequent continuation lines.  This is the default
-behavior.
+over and over, in subsequent continuation lines.
 
 @item -fdiagnostics-show-location=every-line
 Only meaningful in line-wrapping mode.  Instructs the diagnostic
diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index 691dbb6..a168207 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -783,6 +783,7 @@ pp_set_real_maximum_length (pretty_printer *pp)
      not to increase unnecessarily the line-length cut-off.  */
   if (!pp_is_wrapping_line (pp)
       || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
+      || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ELIDE
       || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
     pp->maximum_length = pp_line_cutoff (pp);
   else
@@ -1546,6 +1547,7 @@ pp_emit_prefix (pretty_printer *pp)
 	  break;
 
 	case DIAGNOSTICS_SHOW_PREFIX_ONCE:
+	case DIAGNOSTICS_SHOW_PREFIX_ELIDE:
 	  if (pp->emitted_prefix)
 	    {
 	      pp_indent (pp);
@@ -1582,8 +1584,9 @@ pretty_printer::pretty_printer (int maximum_length)
     show_color ()
 {
   pp_line_cutoff (this) = maximum_length;
-  /* By default, we emit prefixes once per message.  */
-  pp_prefixing_rule (this) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+  /* Emit only once within a given diagnostic, and elide locations
+     for followup diagnostics with equal location.  */
+  pp_prefixing_rule (this) = DIAGNOSTICS_SHOW_PREFIX_ELIDE;
   pp_set_prefix (this, NULL);
 }
 
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index a6e60f1..316c611 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -41,16 +41,22 @@ struct text_info
   location_t get_location (unsigned int index_of_location) const;
 };
 
-/* How often diagnostics are prefixed by their locations:
-   o DIAGNOSTICS_SHOW_PREFIX_NEVER: never - not yet supported;
-   o DIAGNOSTICS_SHOW_PREFIX_ONCE: emit only once;
-   o DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE: emit each time a physical
-   line is started.  */
+/* How often diagnostics are prefixed by their locations.  */
 enum diagnostic_prefixing_rule_t
 {
-  DIAGNOSTICS_SHOW_PREFIX_ONCE       = 0x0,
-  DIAGNOSTICS_SHOW_PREFIX_NEVER      = 0x1,
-  DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE = 0x2
+  /* Emit only once within a given diagnostic.  */
+  DIAGNOSTICS_SHOW_PREFIX_ONCE,
+
+  /* Emit only once within a given diagnostic, and elide locations
+     for followup diagnostics with equal location.  */
+  DIAGNOSTICS_SHOW_PREFIX_ELIDE,
+
+  /* Never - not yet supported.  */
+  DIAGNOSTICS_SHOW_PREFIX_NEVER,
+
+  /* Emit each time a physical line is started within a diagnostic
+     message.  */
+  DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE
 };
 
 /* The chunk_info data structure forms a stack of the results from the
diff --git a/gcc/selftest-diagnostic.c b/gcc/selftest-diagnostic.c
index 4a7f0de..4e6cfd4 100644
--- a/gcc/selftest-diagnostic.c
+++ b/gcc/selftest-diagnostic.c
@@ -36,11 +36,15 @@ namespace selftest {
 test_diagnostic_context::test_diagnostic_context ()
 {
   diagnostic_initialize (this, 0);
+  /* Don't print to stderr.  */
+  printer->buffer->stream = NULL;
+  printer->buffer->flush_p = false;
   show_caret = true;
   show_labels_p = true;
   show_column = true;
   start_span = start_span_cb;
   min_margin_width = 6;
+  override_file = "FILENAME";
 }
 
 test_diagnostic_context::~test_diagnostic_context ()
@@ -59,6 +63,23 @@ test_diagnostic_context::start_span_cb (diagnostic_context *context,
   default_diagnostic_start_span_fn (context, exploc);
 }
 
+/* Implementation of class selftest::global_dc_test.  */
+
+/* Constructor.  Override "global_dc" with DC.  */
+
+global_dc_test::global_dc_test (diagnostic_context *dc)
+: m_saved_global_dc (global_dc)
+{
+  global_dc = dc;
+}
+
+/* Destructor.  Restore the saved global_dc.  */
+
+global_dc_test::~global_dc_test ()
+{
+  global_dc = m_saved_global_dc;
+}
+
 } // namespace selftest
 
 #endif /* #if CHECKING_P */
diff --git a/gcc/selftest-diagnostic.h b/gcc/selftest-diagnostic.h
index b1d6ace..90ff2d1 100644
--- a/gcc/selftest-diagnostic.h
+++ b/gcc/selftest-diagnostic.h
@@ -42,6 +42,22 @@ class test_diagnostic_context : public diagnostic_context
   start_span_cb (diagnostic_context *context, expanded_location exploc);
 };
 
+/* A class for overriding the global "global_dc" within a selftest,
+   restoring its value afterwards.  */
+
+class global_dc_test
+{
+ public:
+  /* Constructor.  Override "global_dc" with DC.  */
+  global_dc_test (diagnostic_context *dc);
+
+  /* Destructor.  Restore the saved global_dc.  */
+  ~global_dc_test ();
+
+ private:
+  diagnostic_context *m_saved_global_dc;
+};
+
 } // namespace selftest
 
 #endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index df36c34..9e08545 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -22,6 +22,7 @@ if ![info exists TEST_ALWAYS_FLAGS] {
     set TEST_ALWAYS_FLAGS ""
 }
 set TEST_ALWAYS_FLAGS "-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never $TEST_ALWAYS_FLAGS"
+set TEST_ALWAYS_FLAGS "-fdiagnostics-show-location=once $TEST_ALWAYS_FLAGS"
 
 proc prune_gcc_output { text } {
     global srcdir
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RFC: elide repeated source locations (PR other/84889)
  2018-11-12  1:56 [PATCH] RFC: elide repeated source locations (PR other/84889) David Malcolm
@ 2018-11-12 20:38 ` Martin Sebor
  2018-11-14 21:13   ` David Malcolm
  0 siblings, 1 reply; 5+ messages in thread
From: Martin Sebor @ 2018-11-12 20:38 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 11/11/2018 07:43 PM, David Malcolm wrote:
> We often emit more than one diagnostic at the same source location.
> For example, the C++ frontend can emit many diagnostics at
> the same source location when suggesting overload candidates.
>
> For example:
>
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In function 'int test_3(s, t)':
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: error: no match for 'operator&&' (operand types are 's' and 't')
>    38 |   return param_s && param_t;
>       |          ~~~~~~~~^~~~~~~~~~
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: note: candidate: 'operator&&(bool, bool)' <built-in>
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: note:   no known conversion for argument 2 from 't' to 'bool'
>
> This is overly verbose.  Note how the same location has been printed
> three times, obscuring the pertinent messages.
>
> This patch add a new "elide" value to -fdiagnostics-show-location=
> and makes it the default (previously it was "once").  With elision
> the above is printed as:
>
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In function 'int test_3(s, t)':
> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18: error: no match for 'operator&&' (operand types are 's' and 't')
>    38 |   return param_s && param_t;
>       |          ~~~~~~~~^~~~~~~~~~
>       = note: candidate: 'operator&&(bool, bool)' <built-in>
>       = note:   no known conversion for argument 2 from 't' to 'bool'
>
> where the followup notes are printed with a '=' lined up with
> the source code margin.
>
> Thoughts?

I agree the long pathname in the notes is at first glance redundant
but I'm not sure about using '=' as a shorthand for it.  I have
written many scripts to parse GCC output to extract all diagnostics
(including notes) and publish those on a Web page somewhere, as I'm
sure must have others.  All those scripts would stop working with
this change and require changes to the build system to work again.
Making those changes can be a substantial undertaking in some
organizations.

Have you considered printing just the file name instead?  Or any
other alternatives?

Martin

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RFC: elide repeated source locations (PR other/84889)
  2018-11-12 20:38 ` Martin Sebor
@ 2018-11-14 21:13   ` David Malcolm
  2018-11-15 17:35     ` Martin Sebor
  0 siblings, 1 reply; 5+ messages in thread
From: David Malcolm @ 2018-11-14 21:13 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches

On Mon, 2018-11-12 at 13:37 -0700, Martin Sebor wrote:
> On 11/11/2018 07:43 PM, David Malcolm wrote:
> > We often emit more than one diagnostic at the same source location.
> > For example, the C++ frontend can emit many diagnostics at
> > the same source location when suggesting overload candidates.
> > 
> > For example:
> > 
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
> > function 'int test_3(s, t)':
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
> > error: no match for 'operator&&' (operand types are 's' and 't')
> >    38 |   return param_s && param_t;
> >       |          ~~~~~~~~^~~~~~~~~~
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
> > note: candidate: 'operator&&(bool, bool)' <built-in>
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
> > note:   no known conversion for argument 2 from 't' to 'bool'
> > 
> > This is overly verbose.  Note how the same location has been
> > printed
> > three times, obscuring the pertinent messages.
> > 
> > This patch add a new "elide" value to -fdiagnostics-show-location=
> > and makes it the default (previously it was "once").  With elision
> > the above is printed as:
> > 
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
> > function 'int test_3(s, t)':
> > ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
> > error: no match for 'operator&&' (operand types are 's' and 't')
> >    38 |   return param_s && param_t;
> >       |          ~~~~~~~~^~~~~~~~~~
> >       = note: candidate: 'operator&&(bool, bool)' <built-in>
> >       = note:   no known conversion for argument 2 from 't' to
> > 'bool'
> > 
> > where the followup notes are printed with a '=' lined up with
> > the source code margin.
> > 
> > Thoughts?
> 
> I agree the long pathname in the notes is at first glance redundant
> but I'm not sure about using '=' as a shorthand for it.  I have
> written many scripts to parse GCC output to extract all diagnostics
> (including notes) and publish those on a Web page somewhere, as I'm
> sure must have others.  All those scripts would stop working with
> this change and require changes to the build system to work again.
> Making those changes can be a substantial undertaking in some
> organizations.
> 
> Have you considered printing just the file name instead?  Or any
> other alternatives?

"-fdiagnostics-show-location=once" will restore the old behavior.
Alternatively, if you want to parse GCC output, I'm adding a JSON
output format; see:
  https://gcc.gnu.org/ml/gcc-patches/2018-11/msg01038.html
(I'm testing an updated version of that patch)

Dave

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RFC: elide repeated source locations (PR other/84889)
  2018-11-14 21:13   ` David Malcolm
@ 2018-11-15 17:35     ` Martin Sebor
  2018-11-15 19:31       ` Eric Gallager
  0 siblings, 1 reply; 5+ messages in thread
From: Martin Sebor @ 2018-11-15 17:35 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 11/14/2018 02:12 PM, David Malcolm wrote:
> On Mon, 2018-11-12 at 13:37 -0700, Martin Sebor wrote:
>> On 11/11/2018 07:43 PM, David Malcolm wrote:
>>> We often emit more than one diagnostic at the same source location.
>>> For example, the C++ frontend can emit many diagnostics at
>>> the same source location when suggesting overload candidates.
>>>
>>> For example:
>>>
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
>>> function 'int test_3(s, t)':
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>> error: no match for 'operator&&' (operand types are 's' and 't')
>>>    38 |   return param_s && param_t;
>>>       |          ~~~~~~~~^~~~~~~~~~
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>> note: candidate: 'operator&&(bool, bool)' <built-in>
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>> note:   no known conversion for argument 2 from 't' to 'bool'
>>>
>>> This is overly verbose.  Note how the same location has been
>>> printed
>>> three times, obscuring the pertinent messages.
>>>
>>> This patch add a new "elide" value to -fdiagnostics-show-location=
>>> and makes it the default (previously it was "once").  With elision
>>> the above is printed as:
>>>
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
>>> function 'int test_3(s, t)':
>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>> error: no match for 'operator&&' (operand types are 's' and 't')
>>>    38 |   return param_s && param_t;
>>>       |          ~~~~~~~~^~~~~~~~~~
>>>       = note: candidate: 'operator&&(bool, bool)' <built-in>
>>>       = note:   no known conversion for argument 2 from 't' to
>>> 'bool'
>>>
>>> where the followup notes are printed with a '=' lined up with
>>> the source code margin.
>>>
>>> Thoughts?
>>
>> I agree the long pathname in the notes is at first glance redundant
>> but I'm not sure about using '=' as a shorthand for it.  I have
>> written many scripts to parse GCC output to extract all diagnostics
>> (including notes) and publish those on a Web page somewhere, as I'm
>> sure must have others.  All those scripts would stop working with
>> this change and require changes to the build system to work again.
>> Making those changes can be a substantial undertaking in some
>> organizations.
>>
>> Have you considered printing just the file name instead?  Or any
>> other alternatives?
>
> "-fdiagnostics-show-location=once" will restore the old behavior.
> Alternatively, if you want to parse GCC output, I'm adding a JSON
> output format; see:
>   https://gcc.gnu.org/ml/gcc-patches/2018-11/msg01038.html
> (I'm testing an updated version of that patch)

I understand the change can be disabled by an option.  I also
like making the repetitive pathnames shorter, but the concern
I have is that the change to use the '=' notation by default,
besides being rather unusual and not necessarily intuitive, will
break scripts that search for the pattern:

   "[^:]*:[1-9][0-9]*:[1-9][0-9]*: (error|note|warning): "

and adding a new option to a large build system can be quite
difficult.  I suspect it would also make the notes difficult
or even impossible to associate with the corresponding errors
or warnings in parallel builds (where they may be interleaved
with diagnostics from different compilations).

I think it's possible to make the output shorter/less repetitive
without these side-effects by keeping the current format and
instead abbreviating the pathname, e.g. by printing just the file
name (or ".../filename.c:" with the ellipsis standing in for the
long pathname, though the ellipsis would require adjusting
the scripts that sort diagnostics by the pathname).

Martin

PS As an aside, if we wanted to shorten all pathnames this same
idea could be extended to errors and warnings as well by printing
the pathname in the first one and just the filename in subsequent
ones in the same file.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RFC: elide repeated source locations (PR other/84889)
  2018-11-15 17:35     ` Martin Sebor
@ 2018-11-15 19:31       ` Eric Gallager
  0 siblings, 0 replies; 5+ messages in thread
From: Eric Gallager @ 2018-11-15 19:31 UTC (permalink / raw)
  To: Martin Sebor; +Cc: David Malcolm, gcc-patches

On 11/15/18, Martin Sebor <msebor@gmail.com> wrote:
> On 11/14/2018 02:12 PM, David Malcolm wrote:
>> On Mon, 2018-11-12 at 13:37 -0700, Martin Sebor wrote:
>>> On 11/11/2018 07:43 PM, David Malcolm wrote:
>>>> We often emit more than one diagnostic at the same source location.
>>>> For example, the C++ frontend can emit many diagnostics at
>>>> the same source location when suggesting overload candidates.
>>>>
>>>> For example:
>>>>
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
>>>> function 'int test_3(s, t)':
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>>> error: no match for 'operator&&' (operand types are 's' and 't')
>>>>    38 |   return param_s && param_t;
>>>>       |          ~~~~~~~~^~~~~~~~~~
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>>> note: candidate: 'operator&&(bool, bool)' <built-in>
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>>> note:   no known conversion for argument 2 from 't' to 'bool'
>>>>
>>>> This is overly verbose.  Note how the same location has been
>>>> printed
>>>> three times, obscuring the pertinent messages.
>>>>
>>>> This patch add a new "elide" value to -fdiagnostics-show-location=
>>>> and makes it the default (previously it was "once").  With elision
>>>> the above is printed as:
>>>>
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C: In
>>>> function 'int test_3(s, t)':
>>>> ../../src/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C:38:18:
>>>> error: no match for 'operator&&' (operand types are 's' and 't')
>>>>    38 |   return param_s && param_t;
>>>>       |          ~~~~~~~~^~~~~~~~~~
>>>>       = note: candidate: 'operator&&(bool, bool)' <built-in>
>>>>       = note:   no known conversion for argument 2 from 't' to
>>>> 'bool'
>>>>
>>>> where the followup notes are printed with a '=' lined up with
>>>> the source code margin.
>>>>
>>>> Thoughts?
>>>
>>> I agree the long pathname in the notes is at first glance redundant
>>> but I'm not sure about using '=' as a shorthand for it.

I like the -fdiagnostics-show-location=elide option but I also agree
about the '=' looking weird. However, I don't think the '=' is that
big a problem that needs to provoke huge rethinking, just some minor
bikeshedding about which symbol to use instead. How about '+'?

>>> I have
>>> written many scripts to parse GCC output to extract all diagnostics
>>> (including notes) and publish those on a Web page somewhere, as I'm
>>> sure must have others.  All those scripts would stop working with
>>> this change and require changes to the build system to work again.
>>> Making those changes can be a substantial undertaking in some
>>> organizations.
>>>
>>> Have you considered printing just the file name instead?  Or any
>>> other alternatives?
>>
>> "-fdiagnostics-show-location=once" will restore the old behavior.
>> Alternatively, if you want to parse GCC output, I'm adding a JSON
>> output format; see:
>>   https://gcc.gnu.org/ml/gcc-patches/2018-11/msg01038.html
>> (I'm testing an updated version of that patch)
>
> I understand the change can be disabled by an option.  I also
> like making the repetitive pathnames shorter, but the concern
> I have is that the change to use the '=' notation by default,
> besides being rather unusual and not necessarily intuitive, will
> break scripts that search for the pattern:
>
>    "[^:]*:[1-9][0-9]*:[1-9][0-9]*: (error|note|warning): "
>
> and adding a new option to a large build system can be quite
> difficult.  I suspect it would also make the notes difficult
> or even impossible to associate with the corresponding errors
> or warnings in parallel builds (where they may be interleaved
> with diagnostics from different compilations).
>
> I think it's possible to make the output shorter/less repetitive
> without these side-effects by keeping the current format and
> instead abbreviating the pathname, e.g. by printing just the file
> name (or ".../filename.c:" with the ellipsis standing in for the
> long pathname, though the ellipsis would require adjusting
> the scripts that sort diagnostics by the pathname).
>
> Martin
>
> PS As an aside, if we wanted to shorten all pathnames this same
> idea could be extended to errors and warnings as well by printing
> the pathname in the first one and just the filename in subsequent
> ones in the same file.
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-11-15 19:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-12  1:56 [PATCH] RFC: elide repeated source locations (PR other/84889) David Malcolm
2018-11-12 20:38 ` Martin Sebor
2018-11-14 21:13   ` David Malcolm
2018-11-15 17:35     ` Martin Sebor
2018-11-15 19:31       ` Eric Gallager

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).