re PR c/61861 (Incorrect column number for -Wdiscarded-qualifiers)
[gcc.git] / libcpp / line-map.c
index 23a0347cb5fb2f9d07ff6dfc26717c55a9668815..a4055c29c740c8ac7bc7b42cca8338bc29d2f94b 100644 (file)
@@ -1,6 +1,5 @@
 /* Map logical line numbers to (source file, line number) pairs.
-   Copyright (C) 2001, 2003, 2004, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2001-2014 Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -25,6 +24,7 @@ along with this program; see the file COPYING3.  If not see
 #include "line-map.h"
 #include "cpplib.h"
 #include "internal.h"
+#include "hashtab.h"
 
 static void trace_include (const struct line_maps *, const struct line_map *);
 static const struct line_map * linemap_ordinary_map_lookup (struct line_maps *,
@@ -50,14 +50,140 @@ static source_location linemap_macro_loc_to_exp_point (struct line_maps *,
 extern unsigned num_expanded_macros_counter;
 extern unsigned num_macro_tokens_counter;
 
+/* Hash function for location_adhoc_data hashtable.  */
+
+static hashval_t
+location_adhoc_data_hash (const void *l)
+{
+  const struct location_adhoc_data *lb =
+      (const struct location_adhoc_data *) l;
+  return (hashval_t) lb->locus + (size_t) lb->data;
+}
+
+/* Compare function for location_adhoc_data hashtable.  */
+
+static int
+location_adhoc_data_eq (const void *l1, const void *l2)
+{
+  const struct location_adhoc_data *lb1 =
+      (const struct location_adhoc_data *) l1;
+  const struct location_adhoc_data *lb2 =
+      (const struct location_adhoc_data *) l2;
+  return lb1->locus == lb2->locus && lb1->data == lb2->data;
+}
+
+/* Update the hashtable when location_adhoc_data is reallocated.  */
+
+static int
+location_adhoc_data_update (void **slot, void *data)
+{
+  *((char **) slot) += *((long long *) data);
+  return 1;
+}
+
+/* Rebuild the hash table from the location adhoc data.  */
+
+void
+rebuild_location_adhoc_htab (struct line_maps *set)
+{
+  unsigned i;
+  set->location_adhoc_data_map.htab =
+      htab_create (100, location_adhoc_data_hash, location_adhoc_data_eq, NULL);
+  for (i = 0; i < set->location_adhoc_data_map.curr_loc; i++)
+    htab_find_slot (set->location_adhoc_data_map.htab,
+                   set->location_adhoc_data_map.data + i, INSERT);
+}
+
+/* Combine LOCUS and DATA to a combined adhoc loc.  */
+
+source_location
+get_combined_adhoc_loc (struct line_maps *set,
+                       source_location locus, void *data)
+{
+  struct location_adhoc_data lb;
+  struct location_adhoc_data **slot;
+
+  linemap_assert (data);
+
+  if (IS_ADHOC_LOC (locus))
+    locus
+      = set->location_adhoc_data_map.data[locus & MAX_SOURCE_LOCATION].locus;
+  if (locus == 0 && data == NULL)
+    return 0;
+  lb.locus = locus;
+  lb.data = data;
+  slot = (struct location_adhoc_data **)
+      htab_find_slot (set->location_adhoc_data_map.htab, &lb, INSERT);
+  if (*slot == NULL)
+    {
+      if (set->location_adhoc_data_map.curr_loc >=
+         set->location_adhoc_data_map.allocated)
+       {
+         char *orig_data = (char *) set->location_adhoc_data_map.data;
+         long long offset;
+         /* Cast away extern "C" from the type of xrealloc.  */
+         line_map_realloc reallocator = (set->reallocator
+                                         ? set->reallocator
+                                         : (line_map_realloc) xrealloc);
+
+         if (set->location_adhoc_data_map.allocated == 0)
+           set->location_adhoc_data_map.allocated = 128;
+         else
+           set->location_adhoc_data_map.allocated *= 2;
+         set->location_adhoc_data_map.data = (struct location_adhoc_data *)
+             reallocator (set->location_adhoc_data_map.data,
+                          set->location_adhoc_data_map.allocated
+                          * sizeof (struct location_adhoc_data));
+         offset = (char *) (set->location_adhoc_data_map.data) - orig_data;
+         if (set->location_adhoc_data_map.allocated > 128)
+           htab_traverse (set->location_adhoc_data_map.htab,
+                          location_adhoc_data_update, &offset);
+       }
+      *slot = set->location_adhoc_data_map.data
+             + set->location_adhoc_data_map.curr_loc;
+      set->location_adhoc_data_map.data[set->location_adhoc_data_map.curr_loc++]
+       = lb;
+    }
+  return ((*slot) - set->location_adhoc_data_map.data) | 0x80000000;
+}
+
+/* Return the data for the adhoc loc.  */
+
+void *
+get_data_from_adhoc_loc (struct line_maps *set, source_location loc)
+{
+  linemap_assert (IS_ADHOC_LOC (loc));
+  return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].data;
+}
+
+/* Return the location for the adhoc loc.  */
+
+source_location
+get_location_from_adhoc_loc (struct line_maps *set, source_location loc)
+{
+  linemap_assert (IS_ADHOC_LOC (loc));
+  return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+}
+
+/* Finalize the location_adhoc_data structure.  */
+void
+location_adhoc_data_fini (struct line_maps *set)
+{
+  htab_delete (set->location_adhoc_data_map.htab);
+}
+
 /* Initialize a line map set.  */
 
 void
-linemap_init (struct line_maps *set)
+linemap_init (struct line_maps *set,
+             source_location builtin_location)
 {
   memset (set, 0, sizeof (struct line_maps));
   set->highest_location = RESERVED_LOCATION_COUNT - 1;
   set->highest_line = RESERVED_LOCATION_COUNT - 1;
+  set->location_adhoc_data_map.htab =
+      htab_create (100, location_adhoc_data_hash, location_adhoc_data_eq, NULL);
+  set->builtin_location = builtin_location;
 }
 
 /* Check for and warn about line_maps entered but not exited.  */
@@ -94,8 +220,10 @@ new_linemap (struct line_maps *set,
       /* We ran out of allocated line maps. Let's allocate more.  */
       unsigned alloc_size;
 
-      line_map_realloc reallocator
-       = set->reallocator ? set->reallocator : xrealloc;
+      /* Cast away extern "C" from the type of xrealloc.  */
+      line_map_realloc reallocator = (set->reallocator
+                                     ? set->reallocator
+                                     : (line_map_realloc) xrealloc);
       line_map_round_alloc_size_func round_alloc_size =
        set->round_alloc_size;
 
@@ -269,7 +397,7 @@ linemap_add (struct line_maps *set, enum lc_reason reason,
   return map;
 }
 
-/* Returns TRUE if the line table set tracks token locations accross
+/* Returns TRUE if the line table set tracks token locations across
    macro expansion, FALSE otherwise.  */
 
 bool
@@ -307,8 +435,10 @@ linemap_enter_macro (struct line_maps *set, struct cpp_hashnode *macro_node,
 {
   struct line_map *map;
   source_location start_location;
-  line_map_realloc reallocator
-    = set->reallocator ? set->reallocator : xrealloc;
+  /* Cast away extern "C" from the type of xrealloc.  */
+  line_map_realloc reallocator = (set->reallocator
+                                 ? set->reallocator
+                                 : (line_map_realloc) xrealloc);
 
   start_location = LINEMAPS_MACRO_LOWEST_LOCATION (set) - num_tokens;
 
@@ -331,7 +461,6 @@ linemap_enter_macro (struct line_maps *set, struct cpp_hashnode *macro_node,
          num_tokens * sizeof (source_location));
 
   LINEMAPS_MACRO_CACHE (set) = LINEMAPS_MACRO_USED (set) - 1;
-  set->max_column_hint = 0;
 
   return map;
 }
@@ -409,12 +538,12 @@ linemap_line_start (struct line_maps *set, linenum_type to_line,
   if (add_map)
     {
       int column_bits;
-      if (max_column_hint > 100000 || highest > 0xC0000000)
+      if (max_column_hint > 100000 || highest > 0x60000000)
        {
          /* If the column number is ridiculous or we've allocated a huge
             number of source_locations, give up on column numbers. */
          max_column_hint = 0;
-         if (highest >0xF0000000)
+         if (highest >0x70000000)
            return 0;
          column_bits = 0;
        }
@@ -510,6 +639,8 @@ linemap_position_for_line_and_column (struct line_map *map,
 const struct line_map*
 linemap_lookup (struct line_maps *set, source_location line)
 {
+  if (IS_ADHOC_LOC (line))
+    line = set->location_adhoc_data_map.data[line & MAX_SOURCE_LOCATION].locus;
   if (linemap_location_from_macro_expansion_p (set, line))
     return linemap_macro_map_lookup (set, line);
   return linemap_ordinary_map_lookup (set, line);
@@ -526,6 +657,9 @@ linemap_ordinary_map_lookup (struct line_maps *set, source_location line)
   unsigned int md, mn, mx;
   const struct line_map *cached, *result;
 
+  if (IS_ADHOC_LOC (line))
+    line = set->location_adhoc_data_map.data[line & MAX_SOURCE_LOCATION].locus;
+
   if (set ==  NULL || line < RESERVED_LOCATION_COUNT)
     return NULL;
 
@@ -571,6 +705,9 @@ linemap_macro_map_lookup (struct line_maps *set, source_location line)
   unsigned int md, mn, mx;
   const struct line_map *cached, *result;
 
+  if (IS_ADHOC_LOC (line))
+    line = set->location_adhoc_data_map.data[line & MAX_SOURCE_LOCATION].locus;
+
   linemap_assert (line >= LINEMAPS_MACRO_LOWEST_LOCATION (set));
 
   if (set ==  NULL)
@@ -697,6 +834,10 @@ linemap_get_expansion_line (struct line_maps *set,
 {
   const struct line_map *map = NULL;
 
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   if (location < RESERVED_LOCATION_COUNT)
     return 0;
 
@@ -721,6 +862,10 @@ linemap_get_expansion_filename (struct line_maps *set,
 {
   const struct line_map *map = NULL;
 
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   if (location < RESERVED_LOCATION_COUNT)
     return NULL;
 
@@ -755,13 +900,39 @@ linemap_location_in_system_header_p (struct line_maps *set,
 {
   const struct line_map *map = NULL;
 
-  location =
-    linemap_resolve_location (set, location, LRK_SPELLING_LOCATION, &map);
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
 
   if (location < RESERVED_LOCATION_COUNT)
     return false;
 
-  return LINEMAP_SYSP (map);
+  /* Let's look at where the token for LOCATION comes from.  */
+  while (true)
+    {
+      map = linemap_lookup (set, location);
+      if (map != NULL)
+       {
+         if (!linemap_macro_expansion_map_p (map))
+           /* It's a normal token.  */
+           return LINEMAP_SYSP (map);
+         else
+           {
+             /* It's a token resulting from a macro expansion.  */
+             source_location loc =
+               linemap_macro_map_loc_unwind_toward_spelling (map, location);
+             if (loc < RESERVED_LOCATION_COUNT)
+               /* This token might come from a built-in macro.  Let's
+                  look at where that macro got expanded.  */
+               location = linemap_macro_map_loc_to_exp_point (map, location);
+             else
+               location = loc;
+           }
+       }
+      else
+       break;
+    }
+  return false;
 }
 
 /* Return TRUE if LOCATION is a source code location of a token coming
@@ -772,6 +943,10 @@ bool
 linemap_location_from_macro_expansion_p (struct line_maps *set,
                                         source_location location)
 {
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   linemap_assert (location <= MAX_SOURCE_LOCATION
                  && (set->highest_location
                      < LINEMAPS_MACRO_LOWEST_LOCATION (set)));
@@ -851,6 +1026,11 @@ linemap_compare_locations (struct line_maps *set,
   bool pre_virtual_p, post_virtual_p;
   source_location l0 = pre, l1 = post;
 
+  if (IS_ADHOC_LOC (l0))
+    l0 = set->location_adhoc_data_map.data[l0 & MAX_SOURCE_LOCATION].locus;
+  if (IS_ADHOC_LOC (l1))
+    l1 = set->location_adhoc_data_map.data[l1 & MAX_SOURCE_LOCATION].locus;
+
   if (l0 == l1)
     return 0;
 
@@ -912,6 +1092,10 @@ linemap_macro_loc_to_spelling_point (struct line_maps *set,
 {
   struct line_map *map;
 
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   linemap_assert (set && location >= RESERVED_LOCATION_COUNT);
 
   while (true)
@@ -946,6 +1130,10 @@ linemap_macro_loc_to_def_point (struct line_maps *set,
 {
   struct line_map *map;
 
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   linemap_assert (set && location >= RESERVED_LOCATION_COUNT);
 
   while (true)
@@ -984,6 +1172,10 @@ linemap_macro_loc_to_exp_point (struct line_maps *set,
 {
   struct line_map *map;
 
+  if (IS_ADHOC_LOC (location))
+    location = set->location_adhoc_data_map.data[location
+                                                & MAX_SOURCE_LOCATION].locus;
+
   linemap_assert (set && location >= RESERVED_LOCATION_COUNT);
 
   while (true)
@@ -1015,19 +1207,22 @@ linemap_macro_loc_to_exp_point (struct line_maps *set,
    * If LRK is set to LRK_MACRO_EXPANSION_POINT
    -------------------------------
 
-   The virtual location is resolved to the location to the locus of
-   the expansion point of the macro.
+   The virtual location is resolved to the first macro expansion point
+   that led to this macro expansion.
 
    * If LRK is set to LRK_SPELLING_LOCATION
    -------------------------------------
 
-   The virtual location is resolved to the location to the locus where
-   the token has been spelled in the source. This can follow through
-   all the macro expansions that led to the token.
+   The virtual location is resolved to the locus where the token has
+   been spelled in the source.   This can follow through all the macro
+   expansions that led to the token.
 
-   * If LRK is set to LRK_MACRO_PARM_REPLACEMENT_POINT
+   * If LRK is set to LRK_MACRO_DEFINITION_LOCATION
    --------------------------------------
 
+   The virtual location is resolved to the locus of the token in the
+   context of the macro definition.
+
    If LOC is the locus of a token that is an argument of a
    function-like macro [replacing a parameter in the replacement list
    of the macro] the virtual location is resolved to the locus of the
@@ -1038,8 +1233,8 @@ linemap_macro_loc_to_exp_point (struct line_maps *set,
    function-like macro, then the function behaves as if LRK was set to
    LRK_SPELLING_LOCATION.
 
-   If MAP is non-NULL, *MAP is set to the map of the resolved
-   location.  Note that if the resturned location wasn't originally
+   If LOC_MAP is not NULL, *LOC_MAP is set to the map encoding the
+   returned location.  Note that if the returned location wasn't originally
    encoded by a map, the *MAP is set to NULL.  This can happen if LOC
    resolves to a location reserved for the client code, like
    UNKNOWN_LOCATION or BUILTINS_LOCATION in GCC.  */
@@ -1050,6 +1245,9 @@ linemap_resolve_location (struct line_maps *set,
                          enum location_resolution_kind lrk,
                          const struct line_map **map)
 {
+  if (IS_ADHOC_LOC (loc))
+    loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+
   if (loc < RESERVED_LOCATION_COUNT)
     {
       /* A reserved location wasn't encoded in a map.  Let's return a
@@ -1097,6 +1295,9 @@ linemap_unwind_toward_expansion (struct line_maps *set,
   source_location resolved_location;
   const struct line_map *resolved_map;
 
+  if (IS_ADHOC_LOC (loc))
+    loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+
   resolved_location =
     linemap_macro_map_loc_unwind_toward_spelling (*map, loc);
   resolved_map = linemap_lookup (set, resolved_location);
@@ -1111,6 +1312,58 @@ linemap_unwind_toward_expansion (struct line_maps *set,
   return resolved_location;
 }
 
+/* If LOC is the virtual location of a token coming from the expansion
+   of a macro M and if its spelling location is reserved (e.g, a
+   location for a built-in token), then this function unwinds (using
+   linemap_unwind_toward_expansion) the location until a location that
+   is not reserved and is not in a system header is reached.  In other
+   words, this unwinds the reserved location until a location that is
+   in real source code is reached.
+
+   Otherwise, if the spelling location for LOC is not reserved or if
+   LOC doesn't come from the expansion of a macro, the function
+   returns LOC as is and *MAP is not touched.
+
+   *MAP is set to the map of the returned location if the later is
+   different from LOC.  */
+source_location
+linemap_unwind_to_first_non_reserved_loc (struct line_maps *set,
+                                         source_location loc,
+                                         const struct line_map **map)
+{
+  source_location resolved_loc;
+  const struct line_map *map0 = NULL, *map1 = NULL;
+
+  if (IS_ADHOC_LOC (loc))
+    loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+
+  map0 = linemap_lookup (set, loc);
+  if (!linemap_macro_expansion_map_p (map0))
+    return loc;
+
+  resolved_loc = linemap_resolve_location (set, loc,
+                                          LRK_SPELLING_LOCATION,
+                                          &map1);
+
+  if (resolved_loc >= RESERVED_LOCATION_COUNT
+      && !LINEMAP_SYSP (map1))
+    return loc;
+
+  while (linemap_macro_expansion_map_p (map0)
+        && (resolved_loc < RESERVED_LOCATION_COUNT
+            || LINEMAP_SYSP (map1)))
+    {
+      loc = linemap_unwind_toward_expansion (set, loc, &map0);
+      resolved_loc = linemap_resolve_location (set, loc,
+                                              LRK_SPELLING_LOCATION,
+                                              &map1);
+    }
+
+  if (map != NULL)
+    *map = map0;
+  return loc;
+}
+
 /* Expand source code location LOC and return a user readable source
    code location.  LOC must be a spelling (non-virtual) location.  If
    it's a location < RESERVED_LOCATION_COUNT a zeroed expanded source
@@ -1125,6 +1378,12 @@ linemap_expand_location (struct line_maps *set,
   expanded_location xloc;
 
   memset (&xloc, 0, sizeof (xloc));
+  if (IS_ADHOC_LOC (loc))
+    {
+      loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+      xloc.data
+       = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].data;
+    }
 
   if (loc < RESERVED_LOCATION_COUNT)
     /* The location for this token wasn't generated from a line map.
@@ -1153,6 +1412,57 @@ linemap_expand_location (struct line_maps *set,
   return xloc;
 }
 
+
+/* Dump line map at index IX in line table SET to STREAM.  If STREAM
+   is NULL, use stderr.  IS_MACRO is true if the caller wants to
+   dump a macro map, false otherwise.  */
+
+void
+linemap_dump (FILE *stream, struct line_maps *set, unsigned ix, bool is_macro)
+{
+  const char *lc_reasons_v[LC_ENTER_MACRO + 1]
+      = { "LC_ENTER", "LC_LEAVE", "LC_RENAME", "LC_RENAME_VERBATIM",
+         "LC_ENTER_MACRO" };
+  const char *reason;
+  struct line_map *map;
+
+  if (stream == NULL)
+    stream = stderr;
+
+  if (!is_macro)
+    map = LINEMAPS_ORDINARY_MAP_AT (set, ix);
+  else
+    map = LINEMAPS_MACRO_MAP_AT (set, ix);
+
+  reason = (map->reason <= LC_ENTER_MACRO) ? lc_reasons_v[map->reason] : "???";
+
+  fprintf (stream, "Map #%u [%p] - LOC: %u - REASON: %s - SYSP: %s\n",
+          ix, (void *) map, map->start_location, reason,
+          (!is_macro && ORDINARY_MAP_IN_SYSTEM_HEADER_P (map)) ? "yes" : "no");
+  if (!is_macro)
+    {
+      unsigned includer_ix;
+      struct line_map *includer_map;
+
+      includer_ix = ORDINARY_MAP_INCLUDER_FILE_INDEX (map);
+      includer_map = includer_ix < LINEMAPS_ORDINARY_USED (set)
+                    ? LINEMAPS_ORDINARY_MAP_AT (set, includer_ix)
+                    : NULL;
+
+      fprintf (stream, "File: %s:%d\n", ORDINARY_MAP_FILE_NAME (map),
+              ORDINARY_MAP_STARTING_LINE_NUMBER (map));
+      fprintf (stream, "Included from: [%d] %s\n", includer_ix,
+              includer_map ? ORDINARY_MAP_FILE_NAME (includer_map) : "None");
+    }
+  else
+    fprintf (stream, "Macro: %s (%u tokens)\n",
+            linemap_map_get_macro_name (map),
+            MACRO_MAP_NUM_MACRO_TOKENS (map));
+
+  fprintf (stream, "\n");
+}
+
+
 /* Dump debugging information about source location LOC into the file
    stream STREAM. SET is the line map set LOC comes from.  */
 
@@ -1166,6 +1476,9 @@ linemap_dump_location (struct line_maps *set,
   const char *path = "", *from = "";
   int l = -1, c = -1, s = -1, e = -1;
 
+  if (IS_ADHOC_LOC (loc))
+    loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+
   if (loc == 0)
     return;
 
@@ -1196,6 +1509,46 @@ linemap_dump_location (struct line_maps *set,
           path, from, l, c, s, (void*)map, e, loc, location);
 }
 
+/* Return the highest location emitted for a given file for which
+   there is a line map in SET.  FILE_NAME is the file name to
+   consider.  If the function returns TRUE, *LOC is set to the highest
+   location emitted for that file.  */
+
+bool
+linemap_get_file_highest_location (struct line_maps *set,
+                                  const char *file_name,
+                                  source_location *loc)
+{
+  /* If the set is empty or no ordinary map has been created then
+     there is no file to look for ...  */
+  if (set == NULL || set->info_ordinary.used == 0)
+    return false;
+
+  /* Now look for the last ordinary map created for FILE_NAME.  */
+  int i;
+  for (i = set->info_ordinary.used - 1; i >= 0; --i)
+    {
+      const char *fname = set->info_ordinary.maps[i].d.ordinary.to_file;
+      if (fname && !filename_cmp (fname, file_name))
+       break;
+    }
+
+  if (i < 0)
+    return false;
+
+  /* The highest location for a given map is either the starting
+     location of the next map minus one, or -- if the map is the
+     latest one -- the highest location of the set.  */
+  source_location result;
+  if (i == (int) set->info_ordinary.used - 1)
+    result = set->highest_location;
+  else
+    result = set->info_ordinary.maps[i + 1].start_location - 1;
+
+  *loc = result;
+  return true;
+}
+
 /* Compute and return statistics about the memory consumption of some
    parts of the line table SET.  */
 
@@ -1254,3 +1607,42 @@ linemap_get_statistics (struct line_maps *set,
   s->duplicated_macro_maps_locations_size =
     duplicated_macro_maps_locations_size;
 }
+
+
+/* Dump line table SET to STREAM.  If STREAM is NULL, stderr is used.
+   NUM_ORDINARY specifies how many ordinary maps to dump.  NUM_MACRO
+   specifies how many macro maps to dump.  */
+
+void
+line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
+                unsigned int num_macro)
+{
+  unsigned int i;
+
+  if (set == NULL)
+    return;
+
+  if (stream == NULL)
+    stream = stderr;
+
+  fprintf (stream, "# of ordinary maps:  %d\n", LINEMAPS_ORDINARY_USED (set));
+  fprintf (stream, "# of macro maps:     %d\n", LINEMAPS_MACRO_USED (set));
+  fprintf (stream, "Include stack depth: %d\n", set->depth);
+  fprintf (stream, "Highest location:    %u\n", set->highest_location);
+
+  if (num_ordinary)
+    {
+      fprintf (stream, "\nOrdinary line maps\n");
+      for (i = 0; i < num_ordinary && i < LINEMAPS_ORDINARY_USED (set); i++)
+       linemap_dump (stream, set, i, false);
+      fprintf (stream, "\n");
+    }
+
+  if (num_macro)
+    {
+      fprintf (stream, "\nMacro line maps\n");
+      for (i = 0; i < num_macro && i < LINEMAPS_MACRO_USED (set); i++)
+       linemap_dump (stream, set, i, true);
+      fprintf (stream, "\n");
+    }
+}