This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] diagnostics: Add options to control the column units [PR49973] [PR86904]


Hello-

Here is the second patch that I mentioned when I submitted the other related
patch (which is awaiting review):
https://gcc.gnu.org/ml/gcc-patches/2020-01/msg01626.html. This second patch
is based on top of the first one and it closes out PR49973 and PR86904 by
adding the new option -fdiagnostics-column-unit=[display|byte]. This allows
to specify whether columns are output as simple byte counts (the current
behavior), or as display columns including handling multibyte characters and
tabs. The patch makes display columns the new default. Additionally, a
second new option -fdiagnostics-column-origin is added, which allows to make
the column 0-based (or N-based for any N) instead of 1-based. The default
remains at 1-based as it is now.

A number of testcases were explicitly testing for the old behavior, so I
have updated them to test for the new behavior instead, since the column
number adjusted for tabs is more natural to test for, and matches what
editors typically show (give or take 1 for the origin convention).

One other testcase (go.dg/arrayclear.go) was a bit of an oddity. It failed
after this patch, although it doesn't test for any column numbers. The
answer turned out to be, this test checks for identical error text on two
different lines. When the column units are changed to display columns, then
the column of the second error happens to match the line of the first
one. dejagnu then misinterprets the second error as if it matched the
location of the first one (it doesn't distinguish whether it checks for the
line number or the column number in the output). I added a comment to the
test explaining the situation; since adding the comment has the side effect
of making the first line number no longer match the second column number, it
also makes the test pass again.

It wasn't quite clear to me whether this change was appropriate for GCC 10
or not at this point. We discussed it a couple months ago here:
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02171.html. Either way, I hope
it isn't a problem that I submitted the patch for review now, whether it
will end up in 10 or 11. Please let me know what's normally expected?
Thanks!

Bootstrapped and regtested all languages on linux x86-64, results were the
same before and after:

FAIL 109 109
PASS 467378 467378
UNRESOLVED 1 1
UNSUPPORTED 11183 11183
UNTESTED 202 202
XFAIL 1756 1756
XPASS 36 36

Thanks for taking a look at it.

-Lewis
gcc/ChangeLog:

2020-01-31  Lewis Hyatt  <lhyatt@gmail.com>

	* common.opt: Added -fdiagnostics-column-unit= and
	-fdiagnostics-column-origin= options.  Fix typo in the description
	text for -fdiagnostics-output-format.
	* diagnostic-format-json.cc (json_from_expanded_location): Added
	diagnostic_context argument.  Use it to convert column numbers as per
	the new options.
	(json_from_location_range): Likewise.
	(json_from_fixit_hint): Likewise.
	(json_end_diagnostic): Pass the new context arguments to helper
	functions above.
	(test_unknown_location): Likewise.
	(test_bad_endpoints): Likewise.
	* diagnostic.c (diagnostic_initialize): Initialize new column_unit and
	column_adj members.
	(diagnostic_converted_column): New function.
	(maybe_line_and_column): Elide negative columns, rather than a zero
	column.
	(diagnostic_get_location_text): Convert column number as per the new
	options.
	(diagnostic_report_current_module): Likewise.
	(print_parseable_fixits): Change pretty_printer argument to a
	diagnostic_context. Use the context to convert column numbers.
	(diagnostic_report_diagnostic): Adapt to new arguments for
	print_parseable_fixits().
	(test_print_parseable_fixits_none): Likewise.
	(test_print_parseable_fixits_insert): Likewise.
	(test_print_parseable_fixits_remove): Likewise.
	(test_print_parseable_fixits_replace): Likewise.
	(assert_location_text): Added origin and column_unit arguments for
	testing the new functionality.
	(test_diagnostic_get_location_text): Added selftests for
	-fdiagnostics-column-unit= and -fdiagnostics-column-origin=.
	* diagnostic.h (enum diagnostics_column_unit): New enum.
	(struct diagnostic_context): Added new column_unit and column_adj
	members.
	(diagnostic_converted_column): Declare.
	(json_from_expanded_location): Added new context argument.
	* opts.c (common_handle_option): Handle the new options.
	* tree-diagnostic-path.cc (default_tree_make_json_for_path): Pass the
	new context argument to json_from_expanded_location().


gcc/testsuite/ChangeLog:

2020-01-31  Lewis Hyatt  <lhyatt@gmail.com>

	* c-c++-common/Wmisleading-indentation-3.c: Adjust expected output
	for new default display column units.
	* c-c++-common/Wmisleading-indentation.c: Likewise.
	* g++.dg/parse/error4.C: Likewise.
	* g++.old-deja/g++.brendan/crash11.C: Likewise.
	* g++.old-deja/g++.pt/overload2.C: Likewise.
	* g++.old-deja/g++.robertl/eb109.C: Likewise.
	* gcc.dg/format/branch-1.c: Likewise.
	* gcc.dg/format/pr79210.c: Likewise.
	* gcc.dg/redecl-4.c: Likewise.
	* go.dg/arrayclear.go: Add a comment explaining why adding a
	comment to the test is necessary to prevent it breaking due to a
	dejagnu bug revealed by the new default column units.
commit 02d02a7bbbd4824c230079c38e134843ac442ef5
Author: Lewis Hyatt <lhyatt@gmail.com>
Date:   Fri Jan 24 17:17:40 2020 -0500

    diagnostics: Add options to control the column units [PR49973] [PR86904]

diff --git a/gcc/common.opt b/gcc/common.opt
index 630c380bd6a..657985450c2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1309,6 +1309,14 @@ Enum(diagnostic_url_rule) String(always) Value(DIAGNOSTICS_URL_YES)
 EnumValue
 Enum(diagnostic_url_rule) String(auto) Value(DIAGNOSTICS_URL_AUTO)
 
+fdiagnostics-column-unit=
+Common Joined RejectNegative Enum(diagnostics_column_unit)
+-fdiagnostics-column-unit=[display|byte]	Select units for column numbers.
+
+fdiagnostics-column-origin=
+Common Joined RejectNegative UInteger
+-fdiagnostics-column-origin=<number>	Set the number of the first column.  Default 1-based.
+
 fdiagnostics-format=
 Common Joined RejectNegative Enum(diagnostics_output_format)
 -fdiagnostics-format=[text|json] Select output format.
@@ -1317,6 +1325,15 @@ Common Joined RejectNegative Enum(diagnostics_output_format)
 SourceInclude
 diagnostic.h
 
+Enum
+Name(diagnostics_column_unit) Type(int)
+
+EnumValue
+Enum(diagnostics_column_unit) String(display) Value(DIAGNOSTICS_COLUMN_UNIT_DISPLAY)
+
+EnumValue
+Enum(diagnostics_column_unit) String(byte) Value(DIAGNOSTICS_COLUMN_UNIT_BYTE)
+
 Enum
 Name(diagnostics_output_format) Type(int)
 
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 7bda5c4ba83..3b970b51d0c 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "diagnostic.h"
+#include "selftest-diagnostic.h"
 #include "diagnostic-metadata.h"
 #include "json.h"
 #include "selftest.h"
@@ -43,21 +44,23 @@ static json::array *cur_children_array;
 /* Generate a JSON object for LOC.  */
 
 json::value *
-json_from_expanded_location (location_t loc)
+json_from_expanded_location (diagnostic_context *context, location_t loc)
 {
   expanded_location exploc = expand_location (loc);
   json::object *result = new json::object ();
   if (exploc.file)
     result->set ("file", new json::string (exploc.file));
   result->set ("line", new json::integer_number (exploc.line));
-  result->set ("column", new json::integer_number (exploc.column));
+  const int col = diagnostic_converted_column (context, exploc);
+  result->set ("column", new json::integer_number (col));
   return result;
 }
 
 /* Generate a JSON object for LOC_RANGE.  */
 
 static json::object *
-json_from_location_range (const location_range *loc_range, unsigned range_idx)
+json_from_location_range (diagnostic_context *context,
+			  const location_range *loc_range, unsigned range_idx)
 {
   location_t caret_loc = get_pure_location (loc_range->m_loc);
 
@@ -68,13 +71,13 @@ json_from_location_range (const location_range *loc_range, unsigned range_idx)
   location_t finish_loc = get_finish (loc_range->m_loc);
 
   json::object *result = new json::object ();
-  result->set ("caret", json_from_expanded_location (caret_loc));
+  result->set ("caret", json_from_expanded_location (context, caret_loc));
   if (start_loc != caret_loc
       && start_loc != UNKNOWN_LOCATION)
-    result->set ("start", json_from_expanded_location (start_loc));
+    result->set ("start", json_from_expanded_location (context, start_loc));
   if (finish_loc != caret_loc
       && finish_loc != UNKNOWN_LOCATION)
-    result->set ("finish", json_from_expanded_location (finish_loc));
+    result->set ("finish", json_from_expanded_location (context, finish_loc));
 
   if (loc_range->m_label)
     {
@@ -91,14 +94,14 @@ json_from_location_range (const location_range *loc_range, unsigned range_idx)
 /* Generate a JSON object for HINT.  */
 
 static json::object *
-json_from_fixit_hint (const fixit_hint *hint)
+json_from_fixit_hint (diagnostic_context *context, const fixit_hint *hint)
 {
   json::object *fixit_obj = new json::object ();
 
   location_t start_loc = hint->get_start_loc ();
-  fixit_obj->set ("start", json_from_expanded_location (start_loc));
+  fixit_obj->set ("start", json_from_expanded_location (context, start_loc));
   location_t next_loc = hint->get_next_loc ();
-  fixit_obj->set ("next", json_from_expanded_location (next_loc));
+  fixit_obj->set ("next", json_from_expanded_location (context, next_loc));
   fixit_obj->set ("string", new json::string (hint->get_string ()));
 
   return fixit_obj;
@@ -205,7 +208,7 @@ json_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
   for (unsigned int i = 0; i < richloc->get_num_locations (); i++)
     {
       const location_range *loc_range = richloc->get_range (i);
-      json::object *loc_obj = json_from_location_range (loc_range, i);
+      json::object *loc_obj = json_from_location_range (context, loc_range, i);
       if (loc_obj)
 	loc_array->append (loc_obj);
     }
@@ -217,7 +220,7 @@ json_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
       for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
 	{
 	  const fixit_hint *hint = richloc->get_fixit_hint (i);
-	  json::object *fixit_obj = json_from_fixit_hint (hint);
+	  json::object *fixit_obj = json_from_fixit_hint (context, hint);
 	  fixit_array->append (fixit_obj);
 	}
     }
@@ -320,7 +323,8 @@ namespace selftest {
 static void
 test_unknown_location ()
 {
-  delete json_from_expanded_location (UNKNOWN_LOCATION);
+  test_diagnostic_context dc;
+  delete json_from_expanded_location (&dc, UNKNOWN_LOCATION);
 }
 
 /* Verify that we gracefully handle attempts to serialize bad
@@ -338,7 +342,8 @@ test_bad_endpoints ()
   loc_range.m_range_display_kind = SHOW_RANGE_WITH_CARET;
   loc_range.m_label = NULL;
 
-  json::object *obj = json_from_location_range (&loc_range, 0);
+  test_diagnostic_context dc;
+  json::object *obj = json_from_location_range (&dc, &loc_range, 0);
   /* We should have a "caret" value, but no "start" or "finish" values.  */
   ASSERT_TRUE (obj != NULL);
   ASSERT_TRUE (obj->get ("caret") != NULL);
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 3386f070256..d9421c8bdf2 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "selftest.h"
 #include "selftest-diagnostic.h"
 #include "opts.h"
+#include "cpplib.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -219,6 +220,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   context->min_margin_width = 0;
   context->show_ruler_p = false;
   context->parseable_fixits_p = false;
+  context->column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
+  context->column_adj = 0;
   context->edit_context_ptr = NULL;
   context->diagnostic_group_nesting_depth = 0;
   context->diagnostic_group_emission_count = 0;
@@ -338,8 +341,37 @@ diagnostic_get_color_for_kind (diagnostic_t kind)
   return diagnostic_kind_color[kind];
 }
 
+/* Given an expanded_location, convert the column (which is in 1-based bytes)
+   to the requested units and origin.  Return -1 if the column is
+   invalid (<= 0).  */
+int
+diagnostic_converted_column (diagnostic_context *context, expanded_location s)
+{
+  if (s.column <= 0)
+    return -1;
+
+  int col;
+  switch (context->column_unit)
+    {
+    case DIAGNOSTICS_COLUMN_UNIT_DISPLAY:
+      col = location_compute_display_column (s);
+      break;
+
+    case DIAGNOSTICS_COLUMN_UNIT_BYTE:
+      col = s.column;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return col + context->column_adj;
+}
+
 /* Return a formatted line and column ':%line:%column'.  Elided if
-   zero.  The result is a statically allocated buffer.  */
+   line == 0 or col < 0.  (A column of 0 may be valid due to the
+   -fdiagnostics-column-origin option.)
+   The result is a statically allocated buffer.  */
 
 static const char *
 maybe_line_and_column (int line, int col)
@@ -348,8 +380,9 @@ maybe_line_and_column (int line, int col)
 
   if (line)
     {
-      size_t l = snprintf (result, sizeof (result),
-			   col ? ":%d:%d" : ":%d", line, col);
+      size_t l
+	= snprintf (result, sizeof (result),
+		    col >= 0 ? ":%d:%d" : ":%d", line, col);
       gcc_checking_assert (l < sizeof (result));
     }
   else
@@ -368,8 +401,14 @@ diagnostic_get_location_text (diagnostic_context *context,
   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;
-  int col = context->show_column ? s.column : 0;
+  int line = 0;
+  int col = -1;
+  if (strcmp (file, N_("<built-in>")))
+    {
+      line = s.line;
+      if (context->show_column)
+	col = diagnostic_converted_column (context, s);
+    }
 
   const char *line_col = maybe_line_and_column (line, col);
   return build_message_string ("%s%s%s:%s", locus_cs, file,
@@ -635,14 +674,20 @@ diagnostic_report_current_module (diagnostic_context *context, location_t where)
       if (! MAIN_FILE_P (map))
 	{
 	  bool first = true;
+	  expanded_location s = {};
 	  do
 	    {
 	      where = linemap_included_from (map);
 	      map = linemap_included_from_linemap (line_table, map);
-	      const char *line_col
-		= maybe_line_and_column (SOURCE_LINE (map, where),
-					 first && context->show_column
-					 ? SOURCE_COLUMN (map, where) : 0);
+	      s.file = LINEMAP_FILE (map);
+	      s.line = SOURCE_LINE (map, where);
+	      int col = -1;
+	      if (first && context->show_column)
+		{
+		  s.column = SOURCE_COLUMN (map, where);
+		  col = diagnostic_converted_column (context, s);
+		}
+	      const char *line_col = maybe_line_and_column (s.line, col);
 	      static const char *const msgs[] =
 		{
 		 N_("In file included from"),
@@ -651,7 +696,7 @@ diagnostic_report_current_module (diagnostic_context *context, location_t where)
 	      unsigned index = !first;
 	      pp_verbatim (context->printer, "%s%s %r%s%s%R",
 			   first ? "" : ",\n", _(msgs[index]),
-			   "locus", LINEMAP_FILE (map), line_col);
+			   "locus", s.file, line_col);
 	      first = false;
 	    }
 	  while (! MAIN_FILE_P (map));
@@ -863,11 +908,14 @@ print_escaped_string (pretty_printer *pp, const char *text)
    machine-parseable version of all fixits in RICHLOC to PP.  */
 
 static void
-print_parseable_fixits (pretty_printer *pp, rich_location *richloc)
+print_parseable_fixits (diagnostic_context *context, rich_location *richloc)
 {
-  gcc_assert (pp);
+  gcc_assert (context);
   gcc_assert (richloc);
 
+  pretty_printer *const pp = context->printer;
+  gcc_assert (pp);
+
   char *saved_prefix = pp_take_prefix (pp);
   pp_set_prefix (pp, NULL);
 
@@ -882,8 +930,10 @@ print_parseable_fixits (pretty_printer *pp, rich_location *richloc)
       location_t next_loc = hint->get_next_loc ();
       expanded_location next_exploc = expand_location (next_loc);
       pp_printf (pp, ":{%i:%i-%i:%i}:",
-		 start_exploc.line, start_exploc.column,
-		 next_exploc.line, next_exploc.column);
+		 start_exploc.line,
+		 diagnostic_converted_column (context, start_exploc),
+		 next_exploc.line,
+		 diagnostic_converted_column (context, next_exploc));
       print_escaped_string (pp, hint->get_string ());
       pp_newline (pp);
     }
@@ -1146,7 +1196,7 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   (*diagnostic_finalizer (context)) (context, diagnostic, orig_diag_kind);
   if (context->parseable_fixits_p)
     {
-      print_parseable_fixits (context->printer, diagnostic->richloc);
+      print_parseable_fixits (context, diagnostic->richloc);
       pp_flush (context->printer);
     }
   diagnostic_action_after_output (context, diagnostic->kind);
@@ -1943,11 +1993,11 @@ test_print_escaped_string ()
 static void
 test_print_parseable_fixits_none ()
 {
-  pretty_printer pp;
+  test_diagnostic_context dc;
   rich_location richloc (line_table, UNKNOWN_LOCATION);
 
-  print_parseable_fixits (&pp, &richloc);
-  ASSERT_STREQ ("", pp_formatted_text (&pp));
+  print_parseable_fixits (&dc, &richloc);
+  ASSERT_STREQ ("", pp_formatted_text (dc.printer));
 }
 
 /* Verify that print_parseable_fixits does the right thing if there
@@ -1956,7 +2006,7 @@ test_print_parseable_fixits_none ()
 static void
 test_print_parseable_fixits_insert ()
 {
-  pretty_printer pp;
+  test_diagnostic_context dc;
   rich_location richloc (line_table, UNKNOWN_LOCATION);
 
   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
@@ -1965,9 +2015,9 @@ test_print_parseable_fixits_insert ()
   location_t where = linemap_position_for_column (line_table, 10);
   richloc.add_fixit_insert_before (where, "added content");
 
-  print_parseable_fixits (&pp, &richloc);
+  print_parseable_fixits (&dc, &richloc);
   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n",
-		pp_formatted_text (&pp));
+		pp_formatted_text (dc.printer));
 }
 
 /* Verify that print_parseable_fixits does the right thing if there
@@ -1976,7 +2026,7 @@ test_print_parseable_fixits_insert ()
 static void
 test_print_parseable_fixits_remove ()
 {
-  pretty_printer pp;
+  test_diagnostic_context dc;
   rich_location richloc (line_table, UNKNOWN_LOCATION);
 
   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
@@ -1987,9 +2037,9 @@ test_print_parseable_fixits_remove ()
   where.m_finish = linemap_position_for_column (line_table, 20);
   richloc.add_fixit_remove (where);
 
-  print_parseable_fixits (&pp, &richloc);
+  print_parseable_fixits (&dc, &richloc);
   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"\"\n",
-		pp_formatted_text (&pp));
+		pp_formatted_text (dc.printer));
 }
 
 /* Verify that print_parseable_fixits does the right thing if there
@@ -1998,7 +2048,7 @@ test_print_parseable_fixits_remove ()
 static void
 test_print_parseable_fixits_replace ()
 {
-  pretty_printer pp;
+  test_diagnostic_context dc;
   rich_location richloc (line_table, UNKNOWN_LOCATION);
 
   linemap_add (line_table, LC_ENTER, false, "test.c", 0);
@@ -2009,9 +2059,9 @@ test_print_parseable_fixits_replace ()
   where.m_finish = linemap_position_for_column (line_table, 20);
   richloc.add_fixit_replace (where, "replacement");
 
-  print_parseable_fixits (&pp, &richloc);
+  print_parseable_fixits (&dc, &richloc);
   ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"replacement\"\n",
-		pp_formatted_text (&pp));
+		pp_formatted_text (dc.printer));
 }
 
 /* Verify that
@@ -2022,10 +2072,15 @@ test_print_parseable_fixits_replace ()
 static void
 assert_location_text (const char *expected_loc_text,
 		      const char *filename, int line, int column,
-		      bool show_column)
+		      bool show_column,
+		      int origin = 1,
+		      enum diagnostics_column_unit column_unit
+			= DIAGNOSTICS_COLUMN_UNIT_BYTE)
 {
   test_diagnostic_context dc;
   dc.show_column = show_column;
+  dc.column_unit = column_unit;
+  dc.column_adj = origin - 1;
 
   expanded_location xloc;
   xloc.file = filename;
@@ -2049,7 +2104,10 @@ test_diagnostic_get_location_text ()
   assert_location_text ("PROGNAME:", NULL, 0, 0, true);
   assert_location_text ("<built-in>:", "<built-in>", 42, 10, true);
   assert_location_text ("foo.c:42:10:", "foo.c", 42, 10, true);
-  assert_location_text ("foo.c:42:", "foo.c", 42, 0, true);
+  assert_location_text ("foo.c:42:9:", "foo.c", 42, 10, true, 0);
+  assert_location_text ("foo.c:42:1010:", "foo.c", 42, 10, true, 1001);
+  for (int origin = 0; origin != 2; ++origin)
+    assert_location_text ("foo.c:42:", "foo.c", 42, 0, true, origin);
   assert_location_text ("foo.c:", "foo.c", 0, 10, true);
   assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
   assert_location_text ("foo.c:", "foo.c", 0, 10, false);
@@ -2057,6 +2115,39 @@ test_diagnostic_get_location_text ()
   maybe_line_and_column (INT_MAX, INT_MAX);
   maybe_line_and_column (INT_MIN, INT_MIN);
 
+  {
+    /* In order to test display columns vs byte columns, we need to create a
+       file for location_get_source_line() to read.  */
+
+    const char *const content = "smile \xf0\x9f\x98\x82\n";
+    const int line_bytes = strlen (content) - 1;
+    const int display_width = cpp_display_width (content, line_bytes);
+    ASSERT_EQ (line_bytes - 2, display_width);
+    temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
+    const char *const fname = tmp.get_filename ();
+    const int buf_len = strlen (fname) + 16;
+    char *const expected = XNEWVEC (char, buf_len);
+
+    snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes);
+    assert_location_text (expected, fname, 1, line_bytes, true,
+			  1, DIAGNOSTICS_COLUMN_UNIT_BYTE);
+
+    snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes - 1);
+    assert_location_text (expected, fname, 1, line_bytes, true,
+			  0, DIAGNOSTICS_COLUMN_UNIT_BYTE);
+
+    snprintf (expected, buf_len, "%s:1:%d:", fname, display_width);
+    assert_location_text (expected, fname, 1, line_bytes, true,
+			  1, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
+
+    snprintf (expected, buf_len, "%s:1:%d:", fname, display_width - 1);
+    assert_location_text (expected, fname, 1, line_bytes, true,
+			  0, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
+
+    XDELETEVEC (expected);
+  }
+
+
   progname = old_progname;
 }
 
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 307dbcfb34a..5da6528222d 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -24,6 +24,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "pretty-print.h"
 #include "diagnostic-core.h"
 
+/* An enum for controlling what units to use for the column number
+   when diagnostics are output, used by the -fdiagnostics-column-unit option.
+   Tabs will be expanded or not according to the value of -ftabstop.  The origin
+   (default 1) is controlled by -fdiagnostics-column-origin.  */
+
+enum diagnostics_column_unit
+{
+  /* The new default: display columns.  */
+  DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
+
+  /* The historical behavior: simple bytes.  */
+  DIAGNOSTICS_COLUMN_UNIT_BYTE
+};
+
 /* Enum for overriding the standard output format.  */
 
 enum diagnostics_output_format
@@ -280,6 +294,13 @@ struct diagnostic_context
      rest of the diagnostic.  */
   bool parseable_fixits_p;
 
+  /* What units to use when outputting the column number.  */
+  enum diagnostics_column_unit column_unit;
+
+  /* Offset by which to adjust the 1-based column to respect
+     -fdiagnostics-column-origin.  */
+  int column_adj;
+
   /* If non-NULL, an edit_context to which fix-it hints should be
      applied, for generating patches.  */
   edit_context *edit_context_ptr;
@@ -458,6 +479,8 @@ diagnostic_same_line (const diagnostic_context *context,
 }
 
 extern const char *diagnostic_get_color_for_kind (diagnostic_t kind);
+extern int diagnostic_converted_column (diagnostic_context *context,
+					expanded_location s);
 
 /* Pure text formatting support functions.  */
 extern char *file_name_as_prefix (diagnostic_context *, const char *);
@@ -470,6 +493,7 @@ extern void diagnostic_output_format_init (diagnostic_context *,
 /* Compute the number of digits in the decimal representation of an integer.  */
 extern int num_digits (int);
 
-extern json::value *json_from_expanded_location (location_t loc);
+extern json::value *json_from_expanded_location (diagnostic_context *context,
+						 location_t loc);
 
 #endif /* ! GCC_DIAGNOSTIC_H */
diff --git a/gcc/opts.c b/gcc/opts.c
index d55adf912b1..2373eefd78a 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2423,6 +2423,14 @@ common_handle_option (struct gcc_options *opts,
       dc->parseable_fixits_p = value;
       break;
 
+    case OPT_fdiagnostics_column_unit_:
+      dc->column_unit = (enum diagnostics_column_unit)value;
+      break;
+
+    case OPT_fdiagnostics_column_origin_:
+      dc->column_adj = value - 1;
+      break;
+
     case OPT_fdiagnostics_show_cwe:
       dc->show_cwe = value;
       break;
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
index 7df431fdaef..2314ad42402 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
@@ -36,9 +36,9 @@ int fn_6 (int a, int b, int c)
 	/* ... */
 	if ((err = foo (a)) != 0)
 		goto fail;
-	if ((err = foo (b)) != 0) /* { dg-message "2: this 'if' clause does not guard..." } */
+	if ((err = foo (b)) != 0) /* { dg-message "9: this 'if' clause does not guard..." } */
 		goto fail;
-		goto fail; /* { dg-message "3: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
+		goto fail; /* { dg-message "17: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
 	if ((err = foo (c)) != 0)
 		goto fail;
 	/* ... */
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
index 5cdeba1cbba..202c6bc7fdf 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
@@ -65,9 +65,9 @@ int fn_6 (int a, int b, int c)
 	/* ... */
 	if ((err = foo (a)) != 0)
 		goto fail;
-	if ((err = foo (b)) != 0) /* { dg-message "2: this 'if' clause does not guard..." } */
+	if ((err = foo (b)) != 0) /* { dg-message "9: this 'if' clause does not guard..." } */
 		goto fail;
-		goto fail; /* { dg-message "3: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
+		goto fail; /* { dg-message "17: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
 	if ((err = foo (c)) != 0)
 		goto fail;
 	/* ... */
@@ -178,7 +178,7 @@ void fn_16_tabs (void)
     while (flagA)
       if (flagB) /* { dg-message "7: this 'if' clause does not guard..." } */
 	foo (0);
-	foo (1);/* { dg-message "2: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
+	foo (1);/* { dg-message "9: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
 }
 
 void fn_17_spaces (void)
diff --git a/gcc/testsuite/g++.dg/parse/error4.C b/gcc/testsuite/g++.dg/parse/error4.C
index 792bf4dc063..fe8de73790d 100644
--- a/gcc/testsuite/g++.dg/parse/error4.C
+++ b/gcc/testsuite/g++.dg/parse/error4.C
@@ -7,4 +7,4 @@ struct X {
 		 int);
 };
 
-// { dg-error "4:'itn' has not been declared" "" { target *-*-* } 6 }
+// { dg-error "18:'itn' has not been declared" "" { target *-*-* } 6 }
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C
index 96ebb71645c..d2b37a5122d 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C
@@ -9,13 +9,13 @@ class A {
 	int	h;
 	A() { i=10; j=20; }
 	virtual void f1() { printf("i=%d j=%d\n",i,j); }
-	friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "9:virtual functions cannot be friends" }
+	friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "16:virtual functions cannot be friends" }
 };
 
 class B : public A {
     public:
 	virtual void f1() { printf("i=%d j=%d\n",i,j); }// { dg-error "" }  member.*// ERROR -  member.*
-	friend virtual void f2() { printf("i=%d j=%d\n",i,j); }  // { dg-error "9:virtual functions cannot be friends" }
+	friend virtual void f2() { printf("i=%d j=%d\n",i,j); }  // { dg-error "16:virtual functions cannot be friends" }
 // { dg-error "private" "" { target *-*-* } .-1 }
 };
 
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/overload2.C b/gcc/testsuite/g++.old-deja/g++.pt/overload2.C
index b438543d445..bbc9e51aff6 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/overload2.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/overload2.C
@@ -12,5 +12,5 @@ int
 main()
 {
 	C<char*>	c;
-	char*		p = Z(c.O); //{ dg-error "13:'Z' was not declared" } ambiguous c.O
+	char*		p = Z(c.O); //{ dg-error "29:'Z' was not declared" } ambiguous c.O
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C
index 6dc2c55be58..b98e8da6b1e 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C
@@ -48,8 +48,8 @@ ostream& operator<<(ostream& os, Graph<VertexType,EdgeType>& G)
 
         // The compiler does not like this line!!!!!!
         typename Graph<VertexType, EdgeType>::Successor::iterator
-	  startN = G[i].second.begin(), // { dg-error "14:no match" } no index operator
-	  endN   = G[i].second.end();  // { dg-error "14:no match" } no index operator
+	  startN = G[i].second.begin(), // { dg-error "21:no match" } no index operator
+	  endN   = G[i].second.end();  // { dg-error "21:no match" } no index operator
 
         while(startN != endN)
         {
diff --git a/gcc/testsuite/gcc.dg/format/branch-1.c b/gcc/testsuite/gcc.dg/format/branch-1.c
index 1782064645e..4ea39b52b2e 100644
--- a/gcc/testsuite/gcc.dg/format/branch-1.c
+++ b/gcc/testsuite/gcc.dg/format/branch-1.c
@@ -10,7 +10,7 @@ foo (long l, int nfoo)
 {
   printf ((nfoo > 1) ? "%d foos" : "%d foo", nfoo);
   printf ((l > 1) ? "%d foos" /* { dg-warning "23:int" "wrong type in conditional expr" } */
-	          : "%d foo", l); /* { dg-warning "16:int" "wrong type in conditional expr" } */
+	          : "%d foo", l); /* { dg-warning "23:int" "wrong type in conditional expr" } */
   printf ((l > 1) ? "%ld foos" : "%d foo", l); /* { dg-warning "36:int" "wrong type in conditional expr" } */
   printf ((l > 1) ? "%d foos" : "%ld foo", l); /* { dg-warning "23:int" "wrong type in conditional expr" } */
   /* Should allow one case to have extra arguments.  */
diff --git a/gcc/testsuite/gcc.dg/format/pr79210.c b/gcc/testsuite/gcc.dg/format/pr79210.c
index 71f5dd6e082..6bdabdf21ec 100644
--- a/gcc/testsuite/gcc.dg/format/pr79210.c
+++ b/gcc/testsuite/gcc.dg/format/pr79210.c
@@ -20,4 +20,4 @@ LPFC_VPORT_ATTR_R(peer_port_login,
 		  "Allow peer ports on the same physical port to login to each "
 		  "other.");
 
-/* { dg-warning "6: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */
+/* { dg-warning "20: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */
diff --git a/gcc/testsuite/gcc.dg/redecl-4.c b/gcc/testsuite/gcc.dg/redecl-4.c
index 8f124886da8..2c214bb02c7 100644
--- a/gcc/testsuite/gcc.dg/redecl-4.c
+++ b/gcc/testsuite/gcc.dg/redecl-4.c
@@ -15,7 +15,7 @@ f (void)
     /* Should get format warnings even though the built-in declaration
        isn't "visible".  */
     printf (
-	    "%s", 1); /* { dg-warning "8:format" } */
+	    "%s", 1); /* { dg-warning "15:format" } */
     /* The type of strcmp here should have no prototype.  */
     if (0)
       strcmp (1);
diff --git a/gcc/testsuite/go.dg/arrayclear.go b/gcc/testsuite/go.dg/arrayclear.go
index 6daebc0b8f5..aa5ba0761d7 100644
--- a/gcc/testsuite/go.dg/arrayclear.go
+++ b/gcc/testsuite/go.dg/arrayclear.go
@@ -1,5 +1,8 @@
 // { dg-do compile }
 // { dg-options "-fgo-debug-optimization" }
+// This comment is necessary to work around a dejagnu bug. Otherwise, the
+// column of the second error message would equal the row of the first one, and
+// since the errors are also identical, dejagnu is not able to distinguish them.
 
 package p
 
diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc
index 381a49cb0b4..82b3c2d6b6a 100644
--- a/gcc/tree-diagnostic-path.cc
+++ b/gcc/tree-diagnostic-path.cc
@@ -493,7 +493,7 @@ default_tree_diagnostic_path_printer (diagnostic_context *context,
    doesn't have access to trees (for m_fndecl).  */
 
 json::value *
-default_tree_make_json_for_path (diagnostic_context *,
+default_tree_make_json_for_path (diagnostic_context *context,
 				 const diagnostic_path *path)
 {
   json::array *path_array = new json::array ();
@@ -504,7 +504,8 @@ default_tree_make_json_for_path (diagnostic_context *,
       json::object *event_obj = new json::object ();
       if (event.get_location ())
 	event_obj->set ("location",
-			json_from_expanded_location (event.get_location ()));
+			json_from_expanded_location (context,
+						     event.get_location ()));
       label_text event_text (event.get_desc (false));
       event_obj->set ("description", new json::string (event_text.m_buffer));
       event_text.maybe_free ();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]