#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 *,
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;
+ line_map_realloc reallocator
+ = set->reallocator ? set->reallocator : 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
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);
}
/* Check for and warn about line_maps entered but not exited. */
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
num_tokens * sizeof (source_location));
LINEMAPS_MACRO_CACHE (set) = LINEMAPS_MACRO_USED (set) - 1;
- set->max_column_hint = 0;
return map;
}
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;
}
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);
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;
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)
{
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;
{
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;
{
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
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)));
{
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)
{
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)
{
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)
* 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
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. */
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
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);
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
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.
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. */
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;
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");
+ }
+}