From b957d3f30f609c563ceb5cfa0386c4dba3404951 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 18 Sep 2015 13:25:48 -0400
Subject: [PATCH 32/42] FIXME: semi-working attempt to suppress range-printing
 for macro expansion

This filters out "awkward" ranges in diagnostic_show_locus; doing
so involved reworking it only work on ranges within m_per_range_vec.

It does reject printing the caret though, since it rejects range 0.

Conflicts:
	gcc/diagnostic-show-locus.c
---
 gcc/diagnostic-show-locus.c                        | 277 +++++++++++++--------
 .../gcc.dg/plugin/diagnostic-test-expressions-1.c  |  60 +++++
 libcpp/include/line-map.h                          |   1 +
 libcpp/line-map.c                                  |   3 +
 4 files changed, 244 insertions(+), 97 deletions(-)

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 7dd0ff2..f60bae3 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -164,96 +164,6 @@ location_range::contains_point (int row, int column) const
   return column <= m_finish.column;
 }
 
-/* Return true if (ROW/COLUMN) is within a range of RICHLOC.
-   If it returns true, OUT_RANGE_IDX and OUT_DRAW_CARET_P are
-   written to, with the range index, and whether we should draw
-   the caret at (ROW/COLUMN) (as opposed to an underline).  */
-
-static bool
-get_state_at_point (/* Inputs.  */
-		    int row, int column, rich_location *richloc,
-		    int first_non_ws, int last_non_ws,
-		    /* Outputs.  */
-		    int *out_range_idx,
-		    bool *out_draw_caret_p)
-{
-  /* 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;
-
-  for (rich_location::range_iter iter = richloc->iter_ranges ();
-       !iter.at_end ();
-       iter.next())
-    {
-      const location_range *range = *iter;
-
-      if (0)
-	fprintf (stderr,
-		 "range ( (%i, %i), (%i, %i))->contains_point (%i, %i): %s\n",
-		 range->m_start.line,
-		 range->m_start.column,
-		 range->m_finish.line,
-		 range->m_finish.column,
-		 row,
-		 column,
-		 range->contains_point (row, column) ? "true" : "false");
-
-      if (range->contains_point (row, column))
-	{
-	  *out_range_idx = iter.index();
-
-	  /* Are we at the range's caret?  is it visible? */
-	  *out_draw_caret_p = false;
-	  if (row == range->m_caret.line
-	      && column == range->m_caret.column)
-	    *out_draw_caret_p = range->m_show_caret_p;
-
-	  /* We are within a range.  */
-	  return true;
-	}
-    }
-
-  return false;
-}
-
-/* Get the column beyond the rightmost one that could contain a caret or
-   range marker, given that we stop rendering at trailing whitespace.  */
-
-static int
-get_x_bound_for_row (int row, int caret_column,
-		     rich_location *richloc,
-		     int last_non_ws)
-{
-  int result = caret_column + 1;
-
-  for (rich_location::range_iter iter = richloc->iter_ranges ();
-       !iter.at_end ();
-       iter.next())
-    {
-      const location_range *range = *iter;
-      if (row >= range->m_start.line)
-	{
-	  if (range->m_finish.line == row)
-	    {
-	      /* On the final line within a range; ensure that
-		 we render up to the end of the range.  */
-	      if (result <= range->m_finish.column)
-		result = range->m_finish.column + 1;
-	    }
-	  else if (row < range->m_finish.line)
-	    {
-	      /* Within a multiline range; ensure that we render up to the
-		 last non-whitespace column.  */
-	      if (result <= last_non_ws)
-		result = last_non_ws + 1;
-	    }
-	}
-    }
-
-  return result;
-}
-
 /* Classes for rendering source code and diagnostics, within an
    anonymous namespace.
    The work is done by "class layout", which embeds and uses
@@ -303,6 +213,11 @@ class per_range_info
 
   int get_range_index () const { return m_range_idx; }
 
+  location_range *get_range (rich_location *richloc) const
+  {
+    return richloc->get_range (m_range_idx);
+  }
+
   void add_uniquely_captioned_row (int row);
 
   int get_first_unique_row () const;
@@ -337,6 +252,9 @@ class layout
   layout (diagnostic_context *context,
 	  const diagnostic_info *diagnostic);
 
+  int get_first_line () const;
+  int get_last_line () const;
+
   void print_line (int row);
 
  private:
@@ -346,6 +264,17 @@ class layout
   void
   move_to_column (int *column, int dest_column);
 
+  bool
+  get_state_at_point (/* Inputs.  */
+		      int row, int column,
+		      int first_non_ws, int last_non_ws,
+		      /* Outputs.  */
+		      int *out_range_idx,
+		      bool *out_draw_caret_p);
+
+  int
+  get_x_bound_for_row (int row, int caret_column, int last_non_ws);
+
  private:
   diagnostic_context *m_context;
   pretty_printer *m_pp;
@@ -571,10 +500,44 @@ layout::layout (diagnostic_context * context,
   m_per_range_vec (),
   m_x_offset (0)
 {
+  const line_map *loc_linemap = linemap_lookup (line_table,
+						m_richloc->get_loc ());
   for (rich_location::range_iter iter = m_richloc->iter_ranges ();
        !iter.at_end ();
        iter.next())
     {
+      /* This diagnostic printer can only cope with "sufficiently sane" ranges.
+	 Ignore any ranges that are awkward to handle.  */
+      location_range *loc_range = m_richloc->get_range (iter.index ());
+
+#if 0
+      /* If the primary location is within a macro expansion, reject all ranges
+	 for now.
+	 Doing so fixes some crazy output, but drops the caret from the output
+	 if the range is range 0.  */
+      if (linemap_location_from_macro_expansion_p (line_table,
+						   m_richloc->get_loc ()))
+	continue;
+
+      /* Ignore ranges that start/finish within a macro expansion.  */
+      if (linemap_location_from_macro_expansion_p (line_table,
+						   loc_range->m_src_range.m_start))
+	continue;
+      if (linemap_location_from_macro_expansion_p (line_table,
+						   loc_range->m_src_range.m_finish))
+	continue;
+#endif
+
+      /* If they're not all in the same line-map, ignore the range.  */
+      if (linemap_lookup (line_table, loc_range->m_src_range.m_start)
+	  != loc_linemap)
+	continue;
+      if (linemap_lookup (line_table, loc_range->m_src_range.m_finish)
+	  != loc_linemap)
+	continue;
+
+      /* Passed all the tests; add the range to m_per_range_vec.
+         The printer only considers the ranges in this vec.  */
       per_range_info ri (iter.index ());
       m_per_range_vec.safe_push (ri);
     }
@@ -643,7 +606,6 @@ layout::print_line (int row)
       int range_idx;
       bool draw_caret_p;
       in_range_p = get_state_at_point (row, column,
-				       m_richloc,
 				       0, INT_MAX,
 				       &range_idx, &draw_caret_p);
       if (in_range_p)
@@ -666,9 +628,7 @@ layout::print_line (int row)
 
   /* Step 2: print a line consisting of the caret/underlines for the
      given source line.  */
-  int x_bound = get_x_bound_for_row (row, m_exploc.column,
-				     m_richloc,
-				     last_non_ws);
+  int x_bound = get_x_bound_for_row (row, m_exploc.column, last_non_ws);
 
   pp_space (m_pp);
   for (int column = 1 + m_x_offset; column < x_bound; column++)
@@ -677,7 +637,6 @@ layout::print_line (int row)
       int range_idx;
       bool draw_caret_p;
       in_range_p = get_state_at_point (row, column,
-				       m_richloc,
 				       first_non_ws, last_non_ws,
 				       &range_idx, &draw_caret_p);
       if (in_range_p)
@@ -795,6 +754,42 @@ layout::get_any_range (int line)
   return NULL;
 }
 
+/* Get the first line of code to print, either that of
+   the primary location, or of one of the non-rejected ranges.  */
+
+int
+layout::get_first_line () const
+{
+  int result = m_richloc->lazily_expand_location ().line;
+  int i;
+  per_range_info *ri;
+  FOR_EACH_VEC_ELT (m_per_range_vec, i, ri)
+    {
+      location_range *range = ri->get_range (m_richloc);
+      if (result > range->m_start.line)
+	result = range->m_start.line;
+    }
+  return result;
+}
+
+/* Get the last line of the rich_location, either that of
+   the primary location, or of one of the non-rejected ranges.  */
+
+int
+layout::get_last_line () const
+{
+  int result = m_richloc->lazily_expand_location ().line;
+  int i;
+  per_range_info *ri;
+  FOR_EACH_VEC_ELT (m_per_range_vec, i, ri)
+    {
+      location_range *range = ri->get_range (m_richloc);
+      if (result < range->m_finish.line)
+	result = range->m_finish.line;
+    }
+  return result;
+}
+
 /* Given *COLUMN as an x-coordinate, print spaces to position
    successive output at DEST_COLUMN, printing a newline if necessary,
    and updating *COLUMN.  */
@@ -816,6 +811,94 @@ layout::move_to_column (int *column, int dest_column)
     }
 }
 
+/* Return true if (ROW/COLUMN) is within a range of RICHLOC.
+   If it returns true, OUT_RANGE_IDX and OUT_DRAW_CARET_P are
+   written to, with the range index, and whether we should draw
+   the caret at (ROW/COLUMN) (as opposed to an underline).  */
+
+bool
+layout::get_state_at_point (/* Inputs.  */
+			    int row, int column,
+			    int first_non_ws, int last_non_ws,
+			    /* Outputs.  */
+			    int *out_range_idx,
+			    bool *out_draw_caret_p)
+{
+  /* 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;
+
+  per_range_info *ri;
+  int i;
+  FOR_EACH_VEC_ELT (m_per_range_vec, i, ri)
+    {
+      const location_range *range = m_richloc->get_range (i);
+
+      if (0)
+	fprintf (stderr,
+		 "range ( (%i, %i), (%i, %i))->contains_point (%i, %i): %s\n",
+		 range->m_start.line,
+		 range->m_start.column,
+		 range->m_finish.line,
+		 range->m_finish.column,
+		 row,
+		 column,
+		 range->contains_point (row, column) ? "true" : "false");
+
+      if (range->contains_point (row, column))
+	{
+	  *out_range_idx = ri->get_range_index ();
+
+	  /* Are we at the range's caret?  is it visible? */
+	  *out_draw_caret_p = false;
+	  if (row == range->m_start.line
+	      && column == range->m_start.column)
+	    *out_draw_caret_p = range->m_show_caret_p;
+
+	  /* We are within a range.  */
+	  return true;
+	}
+    }
+
+  return false;
+}
+
+/* Get the column beyond the rightmost one that could contain a caret or
+   range marker, given that we stop rendering at trailing whitespace.  */
+
+int
+layout::get_x_bound_for_row (int row, int caret_column, int last_non_ws)
+{
+  int result = caret_column + 1;
+
+  per_range_info *ri;
+  int i;
+  FOR_EACH_VEC_ELT (m_per_range_vec, i, ri)
+    {
+      const location_range *range = m_richloc->get_range (i);
+      if (row >= range->m_start.line)
+	{
+	  if (range->m_finish.line == row)
+	    {
+	      /* On the final line within a range; ensure that
+		 we render up to the end of the range.  */
+	      if (result <= range->m_finish.column)
+		result = range->m_finish.column + 1;
+	    }
+	  else if (row < range->m_finish.line)
+	    {
+	      /* Within a multiline range; ensure that we render up to the
+		 last non-whitespace column.  */
+	      if (result <= last_non_ws)
+		result = last_non_ws + 1;
+	    }
+	}
+    }
+
+  return result;
+}
+
 } /* End of anonymous namespace.  */
 
 /* For debugging layout issues in diagnostic_show_locus and friends,
@@ -982,8 +1065,8 @@ diagnostic_print_ranges (diagnostic_context * context,
 
   {
     layout layout (context, diagnostic);
-    int last_line = diagnostic->richloc->get_last_line ();
-    for (int row = diagnostic->richloc->get_first_line ();
+    int last_line = layout.get_last_line ();
+    for (int row = layout.get_first_line ();
 	 row <= last_line;
 	 row++)
       layout.print_line (row);
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
index 5485aaf..794c823 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
@@ -420,3 +420,63 @@ void test_quadratic (double a, double b, double c)
    { dg-end-multiline-output "" } */
 
 }
+
+/* Examples of macros.  *******************************************/
+
+#if 1
+#define EXPECT(EXPR, RES) __builtin_expect ((expr), res)
+
+void test_expect (int expr, int res)
+{
+  __emit_expression_range (0, EXPECT (expr, res)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ #define EXPECT(EXPR, RES) __builtin_expect ((expr), res)
+                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, EXPECT (expr, res));
+                               ^
+   { dg-end-multiline-output "" } */
+
+}
+#endif
+
+
+#if  __GNUC__ >= 3
+# define _IO_BE(expr, res) __builtin_expect ((expr), res)
+#else
+# define _IO_BE(expr, res) (expr)
+#endif
+
+typedef struct _FILE
+{
+  unsigned char *_IO_write_ptr;
+  unsigned char *_IO_write_end;
+} FILE;
+
+extern unsigned char __overflow (FILE *__fp, unsigned char ch);
+
+#define _IO_putc_unlocked(_ch, _fp) \
+  ( _IO_BE ((_fp)->_IO_write_ptr >= (_fp)->_IO_write_end, 0) \
+    ? __overflow (_fp, (unsigned char) (_ch)) \
+    : (unsigned char) (*(_fp)->_IO_write_ptr++ = (_ch)))
+
+void
+fputc_unlocked (int __c, FILE *__stream)
+{
+  __emit_expression_range (0, _IO_putc_unlocked (__c, __stream)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, (_IO_putc_unlocked (__c, __stream) + 1)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, _IO_putc_unlocked (__c, __stream));
+                               ^
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (_IO_putc_unlocked (__c, __stream) + 1));
+                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
+   { dg-end-multiline-output "" } */
+
+}
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 19f1b32..f160dce 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1079,6 +1079,7 @@ typedef struct
    m_finish is the last location within the range.  */
 struct location_range
 {
+  source_range m_src_range;
   expanded_location m_start;
   expanded_location m_finish;
 
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 97a71e5..d8e0a84 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1893,6 +1893,8 @@ rich_location::add_range (source_location start, source_location finish,
   linemap_assert (m_num_ranges < MAX_RANGES);
 
   location_range *range = &m_ranges[m_num_ranges++];
+  range->m_src_range.m_start = start;
+  range->m_src_range.m_finish = finish;
   range->m_start = linemap_client_expand_location_to_spelling_point (start);
   range->m_finish = linemap_client_expand_location_to_spelling_point (finish);
   range->m_caret = range->m_start;
@@ -1942,6 +1944,7 @@ rich_location::set_range (unsigned int idx, source_range src_range,
   linemap_assert (idx <= m_num_ranges);
 
   location_range *locrange = &m_ranges[idx];
+  locrange->m_src_range = src_range;
   locrange->m_start
     = linemap_client_expand_location_to_spelling_point (src_range.m_start);
   locrange->m_finish
-- 
1.8.5.3

