diff mbox

[committed] Remove arbitrary limits from rich_location

Message ID 1472605593-2038-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Aug. 31, 2016, 1:06 a.m. UTC
This patch eliminates the hard-coded limits within rich_location
(up to 3 ranges, up to 2 fixits).  The common case is still
handled by embedding the values inside rich_location - it only
uses dynamic allocation if these limits are exceeded, so
creation of rich_location instances on the stack should still
be fast.  This is implemented via a new container class,
semi_embedded_vec <T, N>.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
Successful stage 1 selftest on powerpc-ibm-aix7.1.3.0.

Committed to trunk as r239879.

gcc/ChangeLog:
	* diagnostic-show-locus.c (colorizer::begin_state): Support more
	than 3 ranges per diagnostic by alternating between color 1 and
	color 2.
	(layout::layout): Replace use of rich_location::MAX_RANGES
	with richloc->get_num_locations ().
	(layout::calculate_line_spans): Replace use of
	rich_location::MAX_RANGES with m_layout_ranges.length ().
	(layout::print_annotation_line): Handle arbitrary numbers of
	ranges in caret-printing by defaulting to '^'.
	(selftest::test_one_liner_many_fixits): New function.
	(test_diagnostic_show_locus_one_liner): Call it.
	* diagnostic.c (diagnostic_initialize): Update for renaming
	of rich_location::MAX_RANGES to
	rich_location::STATICALLY_ALLOCATED_RANGES.
	* diagnostic.h (struct diagnostic_context): Likewise.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/diagnostic-test-show-locus-bw.c
	(test_many_nested_locations): New function.
	* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
	(test_show_locus): Handle "test_many_nested_locations".

libcpp/ChangeLog:
	* include/line-map.h (class semi_embedded_vec): New class.
	(semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec): New ctor.
	(semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec): New
	dtor.
	(semi_embedded_vec<T, NUM_EMBEDDED>::operator[]): New methods.
	(semi_embedded_vec<T, NUM_EMBEDDED>::push): New method.
	(semi_embedded_vec<T, NUM_EMBEDDED>::truncate): New method.
	(rich_location::get_num_locations): Reimplement in terms of
	m_ranges.
	(rich_location::get_range): Make non-inline.
	(rich_location::get_num_fixit_hints): Reimplement in terms of
	m_fixit_hints.
	(rich_location::add_fixit): New function.
	(rich_location::MAX_RANGES): Rename to...
	(rich_location::STATICALLY_ALLOCATED_RANGES): ...this.
	(rich_location::MAX_FIXIT_HINTS): Rename to...
	(rich_location::STATICALLY_ALLOCATED_RANGES): ...this, and make
	private.
	(rich_location::m_num_ranges): Eliminate in favor of...
	(rich_location::m_ranges): ...this, converting from a fixed-size
	array to a semi_embedded_vec.
	(rich_location::m_num_fixit_hints): Eliminate in favor of...
	(rich_location::m_fixit_hints): ...this, converting from a
	fixed-size array to a semi_embedded_vec.
	* line-map.c (rich_location::rich_location): Update for above
	changes.
	(rich_location::~rich_location): Likewise.
	(rich_location::get_loc): Likewise.
	(rich_location::get_range): New methods.
	(rich_location::add_range): Update for above changes.
	(rich_location::set_range): Likewise.
	(rich_location::add_fixit_insert): Likewise.
	(rich_location::add_fixit_replace): Likewise.
	(rich_location::get_last_fixit_hint): Likewise.
	(rich_location::reject_impossible_fixit): Likewise.
	(rich_location::add_fixit): New method.
---
 gcc/diagnostic-show-locus.c                        |  64 ++++++++-
 gcc/diagnostic.c                                   |   2 +-
 gcc/diagnostic.h                                   |   2 +-
 .../gcc.dg/plugin/diagnostic-test-show-locus-bw.c  |  44 +++++++
 .../plugin/diagnostic_plugin_test_show_locus.c     |  53 ++++++++
 libcpp/include/line-map.h                          | 145 +++++++++++++++++++--
 libcpp/line-map.c                                  |  92 +++++++------
 7 files changed, 341 insertions(+), 61 deletions(-)
diff mbox

Patch

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 60f6820..a22a660 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -317,8 +317,12 @@  colorizer::begin_state (int state)
       break;
 
     default:
-      /* We don't expect more than 3 ranges per diagnostic.  */
-      gcc_unreachable ();
+      /* For ranges beyond 2, alternate between color 1 and color 2.  */
+      {
+	gcc_assert (state > 2);
+	pp_string (m_context->printer,
+		   state % 2 ? m_range1 : m_range2);
+      }
       break;
     }
 }
@@ -720,8 +724,8 @@  layout::layout (diagnostic_context * context,
   m_exploc (richloc->get_expanded_location (0)),
   m_colorizer (context, diagnostic_kind),
   m_colorize_source_p (context->colorize_source_p),
-  m_layout_ranges (rich_location::MAX_RANGES),
-  m_line_spans (1 + rich_location::MAX_RANGES),
+  m_layout_ranges (richloc->get_num_locations ()),
+  m_line_spans (1 + richloc->get_num_locations ()),
   m_x_offset (0)
 {
   source_location primary_loc = richloc->get_range (0)->m_loc;
@@ -904,7 +908,7 @@  layout::calculate_line_spans ()
 
   /* Populate tmp_spans with individual spans, for each of
      m_exploc, and for m_layout_ranges.  */
-  auto_vec<line_span> tmp_spans (1 + rich_location::MAX_RANGES);
+  auto_vec<line_span> tmp_spans (1 + m_layout_ranges.length ());
   tmp_spans.safe_push (line_span (m_exploc.line, m_exploc.line));
   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
     {
@@ -1050,8 +1054,15 @@  layout::print_annotation_line (int row, const line_bounds lbounds)
 	  /* Within a range.  Draw either the caret or an underline.  */
 	  m_colorizer.set_range (state.range_idx);
 	  if (state.draw_caret_p)
-	    /* Draw the caret.  */
-	    pp_character (m_pp, m_context->caret_chars[state.range_idx]);
+	    {
+	      /* Draw the caret.  */
+	      char caret_char;
+	      if (state.range_idx < rich_location::STATICALLY_ALLOCATED_RANGES)
+		caret_char = m_context->caret_chars[state.range_idx];
+	      else
+		caret_char = '^';
+	      pp_character (m_pp, caret_char);
+	    }
 	  else
 	    pp_character (m_pp, '~');
 	}
@@ -1654,6 +1665,44 @@  test_one_liner_fixit_validation_adhoc_locations ()
   }
 }
 
+/* Ensure that we can add an arbitrary number of fix-it hints to a
+   rich_location.  */
+
+static void
+test_one_liner_many_fixits ()
+{
+  test_diagnostic_context dc;
+  location_t equals = linemap_position_for_column (line_table, 5);
+  rich_location richloc (line_table, equals);
+  for (int i = 0; i < 19; i++)
+    richloc.add_fixit_insert ("a");
+  ASSERT_EQ (19, richloc.get_num_fixit_hints ());
+  diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+  ASSERT_STREQ ("\n"
+		" foo = bar.field;\n"
+		"     ^\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n"
+		"     a\n",
+		pp_formatted_text (dc.printer));
+}
+
 /* Run the various one-liner tests.  */
 
 static void
@@ -1687,6 +1736,7 @@  test_diagnostic_show_locus_one_liner (const line_table_case &case_)
   test_one_liner_fixit_replace_non_equal_range ();
   test_one_liner_fixit_replace_equal_secondary_range ();
   test_one_liner_fixit_validation_adhoc_locations ();
+  test_one_liner_many_fixits ();
 }
 
 /* Verify that fix-it hints are appropriately consolidated.
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index b47da38..47b4c79 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -147,7 +147,7 @@  diagnostic_initialize (diagnostic_context *context, int n_opts)
     context->classify_diagnostic[i] = DK_UNSPECIFIED;
   context->show_caret = false;
   diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
-  for (i = 0; i < rich_location::MAX_RANGES; i++)
+  for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
     context->caret_chars[i] = '^';
   context->show_option_requested = false;
   context->abort_on_error = false;
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 104e39c..0727644 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -109,7 +109,7 @@  struct diagnostic_context
   int caret_max_width;
 
   /* Character used for caret diagnostics.  */
-  char caret_chars[rich_location::MAX_RANGES];
+  char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
 
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
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 2748fa1..e8112bf 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
@@ -205,3 +205,47 @@  int test_percent_q_plus_d (void)
    { dg-end-multiline-output "" } */
   return local;
 }
+
+/* Test of many nested locations and fixits.  */
+
+void test_many_nested_locations (void)
+{
+  /* { dg-warning "test of 70 locations" }
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+    sed do eiusmod tempor incididunt ut labore et dolore magna
+    aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+    ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+    aute irure dolor in reprehenderit in voluptate velit esse cillum
+    dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+    cupidatat non proident, sunt in culpa qui officia deserunt
+    mollit anim id est laborum.
+  */
+/* { dg-begin-multiline-output "" }
+   /*
+   ^
+     Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+     ^~~~~ ^~~~~ ^~~~~ ^~~ ^~~~  ^~~~~~~~~~~ ^~~~~~~~~~ ^~~~
+     LOREM IPSUM DOLOR SIT AMET  CONSECTETUR ADIPISCING ELIT
+     sed do eiusmod tempor incididunt ut labore et dolore magna
+     ^~~ ^~ ^~~~~~~ ^~~~~~ ^~~~~~~~~~ ^~ ^~~~~~ ^~ ^~~~~~ ^~~~~
+     SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE ET DOLORE MAGNA
+     aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+     ^~~~~~  ^~ ^~~~ ^~ ^~~~~ ^~~~~~  ^~~~ ^~~~~~~ ^~~~~~~~~~~~
+     ALIQUA  UT ENIM AD MINIM VENIAM  QUIS NOSTRUD EXERCITATION
+     ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+     ^~~~~~~ ^~~~~~~ ^~~~ ^~ ^~~~~~~ ^~ ^~ ^~~~~~~ ^~~~~~~~~  ^~~~
+     ULLAMCO LABORIS NISI UT ALIQUIP EX EA COMMODO CONSEQUAT  DUIS
+     aute irure dolor in reprehenderit in voluptate velit esse cillum
+     ^~~~ ^~~~~ ^~~~~ ^~ ^~~~~~~~~~~~~ ^~ ^~~~~~~~~ ^~~~~ ^~~~ ^~~~~~
+     AUTE IRURE DOLOR IN REPREHENDERIT IN VOLUPTATE VELIT ESSE CILLUM
+     dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+     ^~~~~~ ^~ ^~~~~~ ^~~~~ ^~~~~~~~  ^~~~~~~~~ ^~~~ ^~~~~~~~
+     DOLORE EU FUGIAT NULLA PARIATUR  EXCEPTEUR SINT OCCAECAT
+     cupidatat non proident, sunt in culpa qui officia deserunt
+     ^~~~~~~~~ ^~~ ^~~~~~~~  ^~~~ ^~ ^~~~~ ^~~ ^~~~~~~ ^~~~~~~~
+     CUPIDATAT NON PROIDENT  SUNT IN CULPA QUI OFFICIA DESERUNT
+     mollit anim id est laborum.
+     ^~~~~~ ^~~~ ^~ ^~~ ^~~~~~~
+     MOLLIT ANIM ID EST LABORUM
+   { dg-end-multiline-output "" } */
+}
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 d57400d..ea28f04 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
@@ -325,6 +325,59 @@  test_show_locus (function *fun)
       warning_at (input_location, 0,
 		  "example of plus in format code for %q+D", local);
     }
+
+  /* Example of many locations and many fixits.
+     Underline (separately) every word in a comment, and convert them
+     to upper case.  */
+  if (0 == strcmp (fnname, "test_many_nested_locations"))
+    {
+      const char *file = LOCATION_FILE (fnstart);
+      const int start_line = fnstart_line + 2;
+      const int finish_line = start_line + 7;
+      location_t loc = get_loc (start_line - 1, 2);
+      rich_location richloc (line_table, loc);
+      for (int line = start_line; line <= finish_line; line++)
+	{
+	  int line_size;
+	  const char *content = location_get_source_line (file, line,
+							  &line_size);
+	  gcc_assert (content);
+	  /* Split line up into words.  */
+	  for (int idx = 0; idx < line_size; idx++)
+	    {
+	      if (ISALPHA (content[idx]))
+		{
+		  int start_idx = idx;
+		  while (idx < line_size && ISALPHA (content[idx]))
+		    idx++;
+		  if (idx == line_size || !ISALPHA (content[idx]))
+		    {
+		      location_t start_of_word = get_loc (line, start_idx);
+		      location_t end_of_word = get_loc (line, idx - 1);
+		      location_t word
+			= make_location (start_of_word, start_of_word,
+					 end_of_word);
+		      richloc.add_range (word, true);
+
+		      /* Add a fixit, converting to upper case.  */
+		      char *copy = xstrndup (content + start_idx,
+					     idx - start_idx);
+		      for (char *ch = copy; *ch; ch++)
+			*ch = TOUPPER (*ch);
+		      richloc.add_fixit_replace (word, copy);
+		      free (copy);
+		    }
+		}
+	    }
+	}
+      /* Verify that we added enough locations to fully exercise
+	 rich_location.  We want to exceed both the
+	 statically-allocated buffer in class rich_location,
+	 and then trigger a reallocation of the dynamic buffer.  */
+      gcc_assert (richloc.get_num_locations () > 3 + (2 * 16));
+      warning_at_rich_loc (&richloc, 0, "test of %i locations",
+			   richloc.get_num_locations ());
+    }
 }
 
 unsigned int
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 122e474..0c95b29 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1288,6 +1288,128 @@  struct location_range
   bool m_show_caret_p;
 };
 
+/* A partially-embedded vec for use within rich_location for storing
+   ranges and fix-it hints.
+
+   Elements [0..NUM_EMBEDDED) are allocated within m_embed, after
+   that they are within the dynamically-allocated m_extra.
+
+   This allows for static allocation in the common case, whilst
+   supporting the rarer case of an arbitrary number of elements.
+
+   Dynamic allocation is not performed unless it's needed.  */
+
+template <typename T, int NUM_EMBEDDED>
+class semi_embedded_vec
+{
+ public:
+  semi_embedded_vec ();
+  ~semi_embedded_vec ();
+
+  unsigned int count () const { return m_num; }
+  T& operator[] (int idx);
+  const T& operator[] (int idx) const;
+
+  void push (const T&);
+  void truncate (int len);
+
+ private:
+  int m_num;
+  T m_embedded[NUM_EMBEDDED];
+  int m_alloc;
+  T *m_extra;
+};
+
+/* Constructor for semi_embedded_vec.  In particular, no dynamic allocation
+   is done.  */
+
+template <typename T, int NUM_EMBEDDED>
+semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec ()
+: m_num (0), m_alloc (0), m_extra (NULL)
+{
+}
+
+/* semi_embedded_vec's dtor.  Release any dynamically-allocated memory.  */
+
+template <typename T, int NUM_EMBEDDED>
+semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec ()
+{
+  XDELETEVEC (m_extra);
+}
+
+/* Look up element IDX, mutably.  */
+
+template <typename T, int NUM_EMBEDDED>
+T&
+semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx)
+{
+  linemap_assert (idx < m_num);
+  if (idx < NUM_EMBEDDED)
+    return m_embedded[idx];
+  else
+    {
+      linemap_assert (m_extra != NULL);
+      return m_extra[idx - NUM_EMBEDDED];
+    }
+}
+
+/* Look up element IDX (const).  */
+
+template <typename T, int NUM_EMBEDDED>
+const T&
+semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx) const
+{
+  linemap_assert (idx < m_num);
+  if (idx < NUM_EMBEDDED)
+    return m_embedded[idx];
+  else
+    {
+      linemap_assert (m_extra != NULL);
+      return m_extra[idx - NUM_EMBEDDED];
+    }
+}
+
+/* Append VALUE to the end of the semi_embedded_vec.  */
+
+template <typename T, int NUM_EMBEDDED>
+void
+semi_embedded_vec<T, NUM_EMBEDDED>::push (const T& value)
+{
+  int idx = m_num++;
+  if (idx < NUM_EMBEDDED)
+    m_embedded[idx] = value;
+  else
+    {
+      /* Offset "idx" to be an index within m_extra.  */
+      idx -= NUM_EMBEDDED;
+      if (NULL == m_extra)
+	{
+	  linemap_assert (m_alloc == 0);
+	  m_alloc = 16;
+	  m_extra = XNEWVEC (T, m_alloc);
+	}
+      else if (idx >= m_alloc)
+	{
+	  linemap_assert (m_alloc > 0);
+	  m_alloc *= 2;
+	  m_extra = XRESIZEVEC (T, m_extra, m_alloc);
+	}
+      linemap_assert (m_extra);
+      linemap_assert (idx < m_alloc);
+      m_extra[idx] = value;
+    }
+}
+
+/* Truncate to length LEN.  No deallocation is performed.  */
+
+template <typename T, int NUM_EMBEDDED>
+void
+semi_embedded_vec<T, NUM_EMBEDDED>::truncate (int len)
+{
+  linemap_assert (len <= m_num);
+  m_num = len;
+}
+
 class fixit_hint;
   class fixit_insert;
   class fixit_remove;
@@ -1387,13 +1509,10 @@  class rich_location
   set_range (line_maps *set, unsigned int idx, source_location loc,
 	     bool show_caret_p);
 
-  unsigned int get_num_locations () const { return m_num_ranges; }
+  unsigned int get_num_locations () const { return m_ranges.count (); }
 
-  location_range *get_range (unsigned int idx)
-  {
-    linemap_assert (idx < m_num_ranges);
-    return &m_ranges[idx];
-  }
+  const location_range *get_range (unsigned int idx) const;
+  location_range *get_range (unsigned int idx);
 
   expanded_location get_expanded_location (unsigned int idx);
 
@@ -1446,29 +1565,29 @@  class rich_location
   add_fixit_replace (source_range src_range,
 		     const char *new_content);
 
-  unsigned int get_num_fixit_hints () const { return m_num_fixit_hints; }
+  unsigned int get_num_fixit_hints () const { return m_fixit_hints.count (); }
   fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
   fixit_hint *get_last_fixit_hint () const;
 
 private:
   bool reject_impossible_fixit (source_location where);
+  void add_fixit (fixit_hint *hint);
 
 public:
-  static const int MAX_RANGES = 3;
-  static const int MAX_FIXIT_HINTS = 2;
+  static const int STATICALLY_ALLOCATED_RANGES = 3;
 
 protected:
   line_maps *m_line_table;
-  unsigned int m_num_ranges;
-  location_range m_ranges[MAX_RANGES];
+  semi_embedded_vec <location_range, STATICALLY_ALLOCATED_RANGES> m_ranges;
 
   int m_column_override;
 
   bool m_have_expanded_location;
   expanded_location m_expanded_location;
 
-  unsigned int m_num_fixit_hints;
-  fixit_hint *m_fixit_hints[MAX_FIXIT_HINTS];
+  static const int MAX_STATIC_FIXIT_HINTS = 2;
+  semi_embedded_vec <fixit_hint *, MAX_STATIC_FIXIT_HINTS> m_fixit_hints;
+
   bool m_seen_impossible_fixit;
 };
 
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 3189326..72549ba 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1983,10 +1983,10 @@  source_range::intersects_line_p (const char *file, int line) const
 
 rich_location::rich_location (line_maps *set, source_location loc) :
   m_line_table (set),
-  m_num_ranges (0),
+  m_ranges (),
   m_column_override (0),
   m_have_expanded_location (false),
-  m_num_fixit_hints (0),
+  m_fixit_hints (),
   m_seen_impossible_fixit (false)
 {
   add_range (loc, true);
@@ -1996,8 +1996,8 @@  rich_location::rich_location (line_maps *set, source_location loc) :
 
 rich_location::~rich_location ()
 {
-  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
-    delete m_fixit_hints[i];
+  for (unsigned int i = 0; i < m_fixit_hints.count (); i++)
+    delete get_fixit_hint (i);
 }
 
 /* Get location IDX within this rich_location.  */
@@ -2005,8 +2005,24 @@  rich_location::~rich_location ()
 source_location
 rich_location::get_loc (unsigned int idx) const
 {
-  linemap_assert (idx < m_num_ranges);
-  return m_ranges[idx].m_loc;
+  const location_range *locrange = get_range (idx);
+  return locrange->m_loc;
+}
+
+/* Get range IDX within this rich_location.  */
+
+const location_range *
+rich_location::get_range (unsigned int idx) const
+{
+  return &m_ranges[idx];
+}
+
+/* Mutable access to range IDX within this rich_location.  */
+
+location_range *
+rich_location::get_range (unsigned int idx)
+{
+  return &m_ranges[idx];
 }
 
 /* Expand location IDX within this rich_location.  */
@@ -2049,11 +2065,10 @@  rich_location::override_column (int column)
 void
 rich_location::add_range (source_location loc, bool show_caret_p)
 {
-  linemap_assert (m_num_ranges < MAX_RANGES);
-
-  location_range *range = &m_ranges[m_num_ranges++];
-  range->m_loc = loc;
-  range->m_show_caret_p = show_caret_p;
+  location_range range;
+  range.m_loc = loc;
+  range.m_show_caret_p = show_caret_p;
+  m_ranges.push (range);
 }
 
 /* Add or overwrite the location given by IDX, setting its location to LOC,
@@ -2073,19 +2088,18 @@  void
 rich_location::set_range (line_maps * /*set*/, unsigned int idx,
 			  source_location loc, bool show_caret_p)
 {
-  linemap_assert (idx < MAX_RANGES);
-
   /* We can either overwrite an existing range, or add one exactly
      on the end of the array.  */
-  linemap_assert (idx <= m_num_ranges);
-
-  location_range *locrange = &m_ranges[idx];
-  locrange->m_loc = loc;
-  locrange->m_show_caret_p = show_caret_p;
+  linemap_assert (idx <= m_ranges.count ());
 
-  /* Are we adding a range onto the end?  */
-  if (idx == m_num_ranges)
-    m_num_ranges = idx + 1;
+  if (idx == m_ranges.count ())
+    add_range (loc,  show_caret_p);
+  else
+    {
+      location_range *locrange = get_range (idx);
+      locrange->m_loc = loc;
+      locrange->m_show_caret_p = show_caret_p;
+    }
 
   if (idx == 0)
     /* Mark any cached value here as dirty.  */
@@ -2114,10 +2128,7 @@  rich_location::add_fixit_insert (source_location where,
 
   if (reject_impossible_fixit (where))
     return;
-
-  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
-  m_fixit_hints[m_num_fixit_hints++]
-    = new fixit_insert (where, new_content);
+  add_fixit (new fixit_insert (where, new_content));
 }
 
 /* Methods for adding removal fix-it hints.  */
@@ -2217,8 +2228,6 @@  void
 rich_location::add_fixit_replace (source_range src_range,
 				  const char *new_content)
 {
-  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
-
   src_range.m_start = get_pure_location (m_line_table, src_range.m_start);
   src_range.m_finish = get_pure_location (m_line_table, src_range.m_finish);
 
@@ -2229,14 +2238,11 @@  rich_location::add_fixit_replace (source_range src_range,
 
   /* Consolidate neighboring fixits.  */
   fixit_hint *prev = get_last_fixit_hint ();
-  if (m_num_fixit_hints > 0)
-    {
-      if (prev->maybe_append_replace (m_line_table, src_range, new_content))
-	return;
-    }
+  if (prev)
+    if (prev->maybe_append_replace (m_line_table, src_range, new_content))
+      return;
 
-  m_fixit_hints[m_num_fixit_hints++]
-    = new fixit_replace (src_range, new_content);
+  add_fixit (new fixit_replace (src_range, new_content));
 }
 
 /* Get the last fix-it hint within this rich_location, or NULL if none.  */
@@ -2244,8 +2250,8 @@  rich_location::add_fixit_replace (source_range src_range,
 fixit_hint *
 rich_location::get_last_fixit_hint () const
 {
-  if (m_num_fixit_hints > 0)
-    return m_fixit_hints[m_num_fixit_hints - 1];
+  if (m_fixit_hints.count () > 0)
+    return get_fixit_hint (m_fixit_hints.count () - 1);
   else
     return NULL;
 }
@@ -2275,13 +2281,21 @@  rich_location::reject_impossible_fixit (source_location where)
   m_seen_impossible_fixit = true;
 
   /* Purge the rich_location of any fix-its that were already added. */
-  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
-    delete m_fixit_hints[i];
-  m_num_fixit_hints = 0;
+  for (unsigned int i = 0; i < m_fixit_hints.count (); i++)
+    delete get_fixit_hint (i);
+  m_fixit_hints.truncate (0);
 
   return true;
 }
 
+/* Add HINT to the fix-it hints in this rich_location.  */
+
+void
+rich_location::add_fixit (fixit_hint *hint)
+{
+  m_fixit_hints.push (hint);
+}
+
 /* class fixit_insert.  */
 
 fixit_insert::fixit_insert (source_location where,