From 7a90645fe6440d109f879249d4c075ca3024244d Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 8 Oct 2015 11:30:03 -0400
Subject: [PATCH 3/3] Eliminate special-casing for Fortran

gcc/ChangeLog:
	* diagnostic-show-locus.c (adjust_line): Delete.
	(layout::get_state_at_point): Update the suppression code for
	before leading/after trailing whitespace to only act on
	underlines, not on carets.
	(diagnostic_show_locus): Eliminate the
	"frontend_calls_diagnostic_print_caret_line_p" special-casing,
	and absorb the body of diagnostic_print_ranges.
	(diagnostic_print_caret_line): Delete.
	(diagnostic_print_ranges): Move body inside diagnostic_show_locus.
	* diagnostic.h (struct diagnostic_context): Delete field
	"frontend_calls_diagnostic_print_caret_line_p".
	(diagnostic_print_caret_line): Delete.

gcc/fortran/ChangeLog:
	* error.c (gfc_diagnostic_build_locus_prefix): Likewise.
	(gfc_diagnostic_starter): When handling a location that will
	involve a call to diagnostic_show_locus, only attempt to print the
	locus for the primary location, and don't call into
	diagnostic_print_caret_line.
	(gfc_diagnostics_init): Remove setting of field
	"frontend_calls_diagnostic_print_caret_line_p".

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/diagnostic-test-show-locus-bw.c
	(test_caret_on_leading_whitespace): New.
	* gcc.dg/plugin/diagnostic-test-show-locus-color.c
	(test_caret_on_leading_whitespace): New.
	* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
	(test_show_locus): Add test_caret_on_leading_whitespace.
---
 gcc/diagnostic-show-locus.c                        | 151 ++-------------------
 gcc/diagnostic.h                                   |  12 --
 gcc/fortran/error.c                                |  71 +---------
 .../gcc.dg/plugin/diagnostic-test-show-locus-bw.c  |  14 ++
 .../plugin/diagnostic-test-show-locus-color.c      |  15 ++
 .../plugin/diagnostic_plugin_test_show_locus.c     |  21 +++
 6 files changed, 65 insertions(+), 219 deletions(-)

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index c3a941d..f7b6d9a 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -39,34 +39,6 @@ along with GCC; see the file COPYING3.  If not see
 static void
 show_ruler (diagnostic_context *context, int max_width, int x_offset);
 
-static void
-diagnostic_print_ranges (diagnostic_context * context,
-			 const diagnostic_info *diagnostic);
-
-/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
-   MAX_WIDTH by some margin, then adjust the start of the line such
-   that the COLUMN is smaller than MAX_WIDTH minus the margin.  The
-   margin is either CARET_LINE_MARGIN characters or the difference
-   between the column and the length of the line, whatever is smaller.
-   The length of LINE is given by LINE_WIDTH.  */
-static const char *
-adjust_line (const char *line, int line_width,
-	     int max_width, int *column_p)
-{
-  int right_margin = CARET_LINE_MARGIN;
-  int column = *column_p;
-
-  gcc_checking_assert (line_width >= column);
-  right_margin = MIN (line_width - column, right_margin);
-  right_margin = max_width - right_margin;
-  if (line_width >= max_width && column > right_margin)
-    {
-      line += column - right_margin;
-      *column_p = right_margin;
-    }
-  return line;
-}
-
 /* Classes for rendering source code and diagnostics, within an
    anonymous namespace.
    The work is done by "class layout", which embeds and uses
@@ -603,11 +575,6 @@ layout::get_state_at_point (/* Inputs.  */
 			    /* Outputs.  */
 			    point_state *out_state)
 {
-  /* Within a multiline range, don't display any underline or caret
-     in any leading or trailing whitespace on a line.  */
-  if (column < first_non_ws || column > last_non_ws)
-    return false;
-
   layout_range *range;
   int i;
   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
@@ -633,6 +600,13 @@ layout::get_state_at_point (/* Inputs.  */
 	      && column == range->m_caret.m_column)
 	    out_state->draw_caret_p = range->m_show_caret_p;
 
+	  /* Within a multiline range, don't display any underline
+	     in any leading or trailing whitespace on a line.
+	     We do display carets, however.  */
+	  if (!out_state->draw_caret_p)
+	    if (column < first_non_ws || column > last_non_ws)
+	      return false;
+
 	  /* We are within a range.  */
 	  return true;
 	}
@@ -719,10 +693,7 @@ show_ruler (diagnostic_context *context, int max_width, int x_offset)
 }
 
 /* Print the physical source code corresponding to the location of
-   this diagnostic, with additional annotations.
-   If CONTEXT has set frontend_calls_diagnostic_print_caret_line_p,
-   the code is printed using diagnostic_print_caret_line; otherwise
-   it is printed using diagnostic_print_ranges.  */
+   this diagnostic, with additional annotations.  */
 
 void
 diagnostic_show_locus (diagnostic_context * context,
@@ -735,112 +706,6 @@ diagnostic_show_locus (diagnostic_context * context,
 
   context->last_location = diagnostic_location (diagnostic, 0);
 
-  if (context->frontend_calls_diagnostic_print_caret_line_p)
-    {
-      /* The GCC < 6 routine. */
-      expanded_location s0 = diagnostic_expand_location (diagnostic, 0);
-      expanded_location s1 = { };
-      /* Zero-initialized. This is checked later by
-	 diagnostic_print_caret_line.  */
-
-      if (diagnostic_num_locations (diagnostic) >= 2)
-	s1 = diagnostic->message.m_richloc->get_range (1)->m_start;
-
-      diagnostic_print_caret_line (context, s0, s1,
-				   context->caret_chars[0],
-				   context->caret_chars[1]);
-    }
-  else
-    /* The GCC >= 6 routine.  */
-    diagnostic_print_ranges (context, diagnostic);
-}
-
-/* Print (part) of the source line given by xloc1 with caret1 pointing
-   at the column.  If xloc2.column != 0 and it fits within the same
-   line as xloc1 according to diagnostic_same_line (), then caret2 is
-   printed at xloc2.colum.  Otherwise, the caller has to set up things
-   to print a second caret line for xloc2.  */
-void
-diagnostic_print_caret_line (diagnostic_context * context,
-			     expanded_location xloc1,
-			     expanded_location xloc2,
-			     char caret1, char caret2)
-{
-  if (!diagnostic_same_line (context, xloc1, xloc2))
-    /* This will mean ignore xloc2.  */
-    xloc2.column = 0;
-  else if (xloc1.column == xloc2.column)
-    xloc2.column++;
-
-  int cmax = MAX (xloc1.column, xloc2.column);
-  int line_width;
-  const char *line = location_get_source_line (xloc1.file, xloc1.line,
-					       &line_width);
-  if (line == NULL || cmax > line_width)
-    return;
-
-  /* Center the interesting part of the source line to fit in
-     max_width, and adjust all columns accordingly.  */
-  int max_width = context->caret_max_width;
-  int offset = (int) cmax;
-  line = adjust_line (line, line_width, max_width, &offset);
-  offset -= cmax;
-  cmax += offset;
-  xloc1.column += offset;
-  if (xloc2.column)
-    xloc2.column += offset;
-
-  /* Print the source line.  */
-  pp_newline (context->printer);
-  const char *saved_prefix = pp_get_prefix (context->printer);
-  pp_set_prefix (context->printer, NULL);
-  pp_space (context->printer);
-  while (max_width > 0 && line_width > 0)
-    {
-      char c = *line == '\t' ? ' ' : *line;
-      if (c == '\0')
-	c = ' ';
-      pp_character (context->printer, c);
-      max_width--;
-      line_width--;
-      line++;
-    }
-  pp_newline (context->printer);
-
-  /* Print the caret under the line.  */
-  const char *caret_cs, *caret_ce;
-  caret_cs = colorize_start (pp_show_color (context->printer), "caret");
-  caret_ce = colorize_stop (pp_show_color (context->printer));
-  int cmin = xloc2.column
-    ? MIN (xloc1.column, xloc2.column) : xloc1.column;
-  int caret_min = cmin == xloc1.column ? caret1 : caret2;
-  int caret_max = cmin == xloc1.column ? caret2 : caret1;
-
-  /* cmin is >= 1, but we indent with an extra space at the start like
-     we did above.  */
-  int i;
-  for (i = 0; i < cmin; i++)
-    pp_space (context->printer);
-  pp_printf (context->printer, "%s%c%s", caret_cs, caret_min, caret_ce);
-
-  if (xloc2.column)
-    {
-      for (i++; i < cmax; i++)
-	pp_space (context->printer);
-      pp_printf (context->printer, "%s%c%s", caret_cs, caret_max, caret_ce);
-    }
-  pp_set_prefix (context->printer, saved_prefix);
-  pp_needs_newline (context->printer) = true;
-}
-
-/* Print all source lines covered by the locations and any ranges
-   within DIAGNOSTIC, displaying one or more carets and zero or more
-   underlines as appropriate.  */
-
-static void
-diagnostic_print_ranges (diagnostic_context * context,
-			 const diagnostic_info *diagnostic)
-{
   pp_newline (context->printer);
 
   const char *saved_prefix = pp_get_prefix (context->printer);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 66a867c..d4ebf86 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -183,11 +183,6 @@ struct diagnostic_context
   int lock;
 
   bool inhibit_notes_p;
-
-  /* Does the frontend make calls to diagnostic_print_caret_line?
-     If so, we fall back to the old implementation of
-     diagnostic_show_locus.  */
-  bool frontend_calls_diagnostic_print_caret_line_p;
 };
 
 static inline void
@@ -348,13 +343,6 @@ diagnostic_same_line (const diagnostic_context *context,
     && context->caret_max_width - CARET_LINE_MARGIN > abs (s1.column - s2.column);
 }
 
-void
-diagnostic_print_caret_line (diagnostic_context * context,
-			     expanded_location xloc1,
-			     expanded_location xloc2,
-			     char caret1, char caret2);
-
-
 extern const char *
 diagnostic_get_color_for_kind (diagnostic_t kind);
 
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index 3d9deb0..4b3d31c 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -1027,48 +1027,21 @@ gfc_diagnostic_build_locus_prefix (diagnostic_context *context,
 }
 
 /* This function prints the locus (file:line:column), the diagnostic kind
-   (Error, Warning) and (optionally) the caret line (a source line
-   with '1' and/or '2' below it).
+   (Error, Warning) and (optionally) the relevant lines of code with
+   annotation lines with '1' and/or '2' below them.
 
-   With -fdiagnostic-show-caret (the default) and for valid locations,
-   it prints for one location:
+   With -fdiagnostic-show-caret (the default) it prints:
 
-       [locus]:
+       [locus of primary range]:
        
           some code
                  1
        Error: Some error at (1)
         
-   for two locations that fit in the same locus line:
+  With -fno-diagnostic-show-caret or if the primary range is not
+  valid, it prints:
 
-       [locus]:
-       
-         some code and some more code
-                1       2
-       Error: Some error at (1) and (2)
-
-   and for two locations that do not fit in the same locus line:
-
-       [locus]:
-       
-         some code
-                1
-       [locus2]:
-       
-         some other code
-           2
-       Error: Some error at (1) and (2)
-       
-  With -fno-diagnostic-show-caret or if one of the locations is not
-  valid, it prints for one location (or for two locations that fit in
-  the same locus line):
-
-       [locus]: Error: Some error at (1) and (2)
-
-   and for two locations that do not fit in the same locus line:
-
-       [name]:[locus]: Error: (1)
-       [name]:[locus2]: Error: Some error at (1) and (2)
+       [locus of primary range]: Error: Some error at (1) and (2)
 */
 static void 
 gfc_diagnostic_starter (diagnostic_context *context,
@@ -1128,35 +1101,6 @@ gfc_diagnostic_starter (diagnostic_context *context,
       /* If the caret line was shown, the prefix does not contain the
 	 locus.  */
       pp_set_prefix (context->printer, kind_prefix);
-
-      if (one_locus || same_locus)
-	  return;
-
-      locus_prefix = gfc_diagnostic_build_locus_prefix (context, s2);
-      if (diagnostic_location (diagnostic, 1) <= BUILTINS_LOCATION)
-	{
-	  /* No caret line for the second location. Override the previous
-	     prefix with [locus2]:[prefix].  */
-	  pp_set_prefix (context->printer,
-			 concat (locus_prefix, " ", kind_prefix, NULL));
-	  free (kind_prefix);
-	  free (locus_prefix);
-	}
-      else
-	{
-	  /* We print the caret for the second location.  */
-	  pp_verbatim (context->printer, locus_prefix);
-	  free (locus_prefix);
-	  /* Fortran uses an empty line between locus and caret line.  */
-	  pp_newline (context->printer);
-	  s1.column = 0; /* Print only a caret line for s2.  */
-	  diagnostic_print_caret_line (context, s2, s1,
-				       context->caret_chars[1], '\0');
-	  pp_newline (context->printer);
-	  /* If the caret line was shown, the prefix does not contain the
-	     locus.  */
-	  pp_set_prefix (context->printer, kind_prefix);
-	}
     }
 }
 
@@ -1481,7 +1425,6 @@ gfc_diagnostics_init (void)
   diagnostic_format_decoder (global_dc) = gfc_format_decoder;
   global_dc->caret_chars[0] = '1';
   global_dc->caret_chars[1] = '2';
-  global_dc->frontend_calls_diagnostic_print_caret_line_p = true;
   pp_warning_buffer = new (XNEW (output_buffer)) output_buffer ();
   pp_warning_buffer->flush_p = false;
   /* pp_error_buffer is statically allocated.  This simplifies memory
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
index ab74a11..a4b16da 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
@@ -133,3 +133,17 @@ void test_multiple_carets (void)
    { dg-end-multiline-output "" } */
 #endif
 }
+
+void test_caret_on_leading_whitespace (void)
+{
+#if 0
+    ASSOCIATE (y => x)
+      y = 5 /* { dg-warning "6: test" } */
+/* { dg-begin-multiline-output "" }
+     ASSOCIATE (y => x)
+                    2
+       y = 5
+      1
+   { dg-end-multiline-output "" } */
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
index 6789a47..47639b2 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
@@ -141,3 +141,18 @@ void test_multiple_carets (void)
    { dg-end-multiline-output "" } */
 #endif
 }
+
+void test_caret_on_leading_whitespace (void)
+{
+#if 0
+    ASSOCIATE (y => x)
+      y = 5 /* { dg-warning "6: test" } */
+/* { dg-begin-multiline-output "" }
+     ASSOCIATE (y =>[32m[K [m[Kx)
+                    [32m[K2
+[m[K      [01;35m[K [m[Ky = 5
+      [01;35m[K1
+[m[K
+   { dg-end-multiline-output "" } */
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
index 4917fad..e49cf46 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
@@ -256,6 +256,27 @@ test_show_locus (function *fun)
       global_dc->caret_chars[0] = '^';
       global_dc->caret_chars[1] = '^';
     }
+
+  /* Example of two carets where both carets appear to have an off-by-one
+     error appearing one column early.
+     Seen with gfortran.dg/associate_5.f03.
+     In an earlier version of the printer, the printing of caret 0 aka
+     "1" was suppressed due to it appearing within the leading whitespace
+     before the text in its line.  Ensure that we at least faithfully
+     print both carets, at the given (erroneous) locations.  */
+  if (0 == strcmp (fnname, "test_caret_on_leading_whitespace"))
+    {
+      const int line = fnstart_line + 3;
+      location_t caret_a = get_loc (line, 5);
+      location_t caret_b = get_loc (line - 1, 19);
+      rich_location richloc (caret_a);
+      richloc.add_range (caret_b, caret_b, true);
+      global_dc->caret_chars[0] = '1';
+      global_dc->caret_chars[1] = '2';
+      warning_at_rich_loc (&richloc, 0, "test");
+      global_dc->caret_chars[0] = '^';
+      global_dc->caret_chars[1] = '^';
+    }
 }
 
 unsigned int
-- 
1.8.5.3

