From cde4c49915e02f86b0e1e48b5727bd91678a83c7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 23 Oct 2015 12:52:13 -0400
Subject: [PATCH 10/27] Add ranges to libcpp tokens (via ad-hoc data,
 unoptimized)

This patch:

  - generalizes the meaning of the source_location (aka location_t) type
    from being a caret within the source code to being a caret plus
    a source_range.  The latter data is stored purely in the ad-hoc data
    lookaside for now.

  - captures ranges for libcpp tokens by generating source_location
    values with caret == start and finish == the last character of the
    token

This is elegant, since we can store caret+range data in location_t as
before, without having to track ranges everywhere: all location_t
values (such as input_location) become the ranges of tokens; a followup
patch fixes the diagnostic machinery to automatically extract the
ranges when building rich_location instances, which means that all
calls to warning, warning_at, error, error_at etc get underlines
showing the range of the pertinent token "for free".

However, it's inefficient, since it means generating an ad-hoc location
for every token in libcpp.  A followup patch optimizes this by packing
short ranges into location_t, without needing to use ad-hoc locations,
which covers most tokens efficiently.

gcc/ChangeLog:
	* gimple.h (gimple_set_block): Use set_block function.
	* tree-cfg.c (move_block_to_fn): Likewise.
	(move_block_to_fn): Likewise.
	* tree-inline.c (copy_phis_for_bb): Likewise.
	* tree.c (tree_set_block): Likewise.
	(set_block): New function.
	* tree.h (set_block): New declaration.

libcpp/ChangeLog:
	* include/cpplib.h (struct cpp_token): Update comment for src_loc
	to indicate that the range of the token is "baked into" the
	source_location.
	* include/line-map.h (location_adhoc_data): Add source_range
	field.
	(get_combined_adhoc_loc): Add source_range param.
	(get_range_from_adhoc_loc): New declaration.
	(get_range_from_loc): New inline function.
	(COMBINE_LOCATION_DATA):  Add source_range param.
	* lex.c (_cpp_lex_direct): Capture the range of the token, baking
	it into token->src_loc via a call to COMBINE_LOCATION_DATA.
	* line-map.c (location_adhoc_data_hash): Add the src_range into
	the hash value.
	(location_adhoc_data_eq): Require equality of the src_range
	values.
	(get_combined_adhoc_loc): Add src_range param, and store it
	within the lookaside table.  Remove the requirement that data
	is non-NULL.
	(get_range_from_adhoc_loc): New function.
	(linemap_expand_location): Extract the data pointer before
	extracting the location.
---
 gcc/gimple.h              |  6 +-----
 gcc/tree-cfg.c            |  9 ++-------
 gcc/tree-inline.c         |  5 +----
 gcc/tree.c                | 11 +++++++----
 gcc/tree.h                |  3 +++
 libcpp/include/cpplib.h   |  3 ++-
 libcpp/include/line-map.h | 23 ++++++++++++++++++++---
 libcpp/lex.c              | 10 ++++++++++
 libcpp/line-map.c         | 26 ++++++++++++++++++++------
 9 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/gcc/gimple.h b/gcc/gimple.h
index a456f54..ba66931 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1709,11 +1709,7 @@ gimple_block (const gimple *g)
 static inline void
 gimple_set_block (gimple *g, tree block)
 {
-  if (block)
-    g->location =
-	COMBINE_LOCATION_DATA (line_table, g->location, block);
-  else
-    g->location = LOCATION_LOCUS (g->location);
+  g->location = set_block (g->location, block);
 }
 
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 735ac46..8ef2443 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6739,10 +6739,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 	    continue;
 	  if (d->orig_block == NULL_TREE || block == d->orig_block)
 	    {
-	      if (d->new_block == NULL_TREE)
-		locus = LOCATION_LOCUS (locus);
-	      else
-		locus = COMBINE_LOCATION_DATA (line_table, locus, d->new_block);
+	      locus = set_block (locus, d->new_block);
 	      gimple_phi_arg_set_location (phi, i, locus);
 	    }
 	}
@@ -6802,9 +6799,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 	tree block = LOCATION_BLOCK (e->goto_locus);
 	if (d->orig_block == NULL_TREE
 	    || block == d->orig_block)
-	  e->goto_locus = d->new_block ?
-	      COMBINE_LOCATION_DATA (line_table, e->goto_locus, d->new_block) :
-	      LOCATION_LOCUS (e->goto_locus);
+	  e->goto_locus = set_block (e->goto_locus, d->new_block);
       }
 }
 
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 9b525f3..58eca90 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2352,10 +2352,7 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
 		  tree *n;
 		  n = id->decl_map->get (LOCATION_BLOCK (locus));
 		  gcc_assert (n);
-		  if (*n)
-		    locus = COMBINE_LOCATION_DATA (line_table, locus, *n);
-		  else
-		    locus = LOCATION_LOCUS (locus);
+		  locus = set_block (locus, *n);
 		}
 	      else
 		locus = LOCATION_LOCUS (locus);
diff --git a/gcc/tree.c b/gcc/tree.c
index f78a2c2..426803c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -11669,10 +11669,7 @@ tree_set_block (tree t, tree b)
 
   if (IS_EXPR_CODE_CLASS (c))
     {
-      if (b)
-	t->exp.locus = COMBINE_LOCATION_DATA (line_table, t->exp.locus, b);
-      else
-	t->exp.locus = LOCATION_LOCUS (t->exp.locus);
+      t->exp.locus = set_block (t->exp.locus, b);
     }
   else
     gcc_unreachable ();
@@ -13656,5 +13653,11 @@ nonnull_arg_p (const_tree arg)
   return false;
 }
 
+location_t
+set_block (location_t loc, tree block)
+{
+  source_range src_range = get_range_from_loc (line_table, loc);
+  return COMBINE_LOCATION_DATA (line_table, loc, src_range, block);
+}
 
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index 4c803f4..92cc929 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5139,6 +5139,9 @@ type_with_alias_set_p (const_tree t)
   return false;
 }
 
+extern location_t
+set_block (location_t loc, tree block);
+
 extern void gt_ggc_mx (tree &);
 extern void gt_pch_nx (tree &);
 extern void gt_pch_nx (tree &, gt_pointer_operator, void *);
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index a2bdfa0..f5c2a21 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -237,7 +237,8 @@ struct GTY(()) cpp_identifier {
 /* A preprocessing token.  This has been carefully packed and should
    occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts.  */
 struct GTY(()) cpp_token {
-  source_location src_loc;	/* Location of first char of token.  */
+  source_location src_loc;	/* Location of first char of token,
+				   together with range of full token.  */
   ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT;  /* token type */
   unsigned short flags;		/* flags - see above */
 
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index c8f636d..979eab1 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -524,9 +524,11 @@ struct GTY(()) maps_info_macro {
   unsigned int cache;
 };
 
-/* Data structure to associate an arbitrary data to a source location.  */
+/* Data structure to associate a source_range together with an arbitrary
+   data pointer with a source location.  */
 struct GTY(()) location_adhoc_data {
   source_location locus;
+  source_range src_range;
   void * GTY((skip)) data;
 };
 
@@ -825,10 +827,14 @@ LINEMAPS_LAST_ALLOCATED_MACRO_MAP (const line_maps *set)
 
 extern void location_adhoc_data_fini (struct line_maps *);
 extern source_location get_combined_adhoc_loc (struct line_maps *,
-					       source_location, void *);
+					       source_location,
+					       source_range,
+					       void *);
 extern void *get_data_from_adhoc_loc (struct line_maps *, source_location);
 extern source_location get_location_from_adhoc_loc (struct line_maps *,
 						    source_location);
+extern source_range get_range_from_adhoc_loc (struct line_maps *,
+					      source_location);
 
 /* Get whether location LOC is an ad-hoc location.  */
 
@@ -838,14 +844,25 @@ IS_ADHOC_LOC (source_location loc)
   return (loc & MAX_SOURCE_LOCATION) != loc;
 }
 
+inline source_range
+get_range_from_loc (struct line_maps *set,
+		    source_location loc)
+{
+  if (IS_ADHOC_LOC (loc))
+    return get_range_from_adhoc_loc (set, loc);
+  else
+    return source_range::from_location (loc);
+}
+
 /* Combine LOC and BLOCK, giving a combined adhoc location.  */
 
 inline source_location
 COMBINE_LOCATION_DATA (struct line_maps *set,
 		       source_location loc,
+		       source_range src_range,
 		       void *block)
 {
-  return get_combined_adhoc_loc (set, loc, block);
+  return get_combined_adhoc_loc (set, loc, src_range, block);
 }
 
 extern void rebuild_location_adhoc_htab (struct line_maps *);
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 0aa1090..f4c964f 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -2723,6 +2723,16 @@ _cpp_lex_direct (cpp_reader *pfile)
       break;
     }
 
+  source_range tok_range;
+  tok_range.m_start = result->src_loc;
+  tok_range.m_finish =
+    linemap_position_for_column (pfile->line_table,
+				 CPP_BUF_COLUMN (buffer, buffer->cur));
+
+  result->src_loc = COMBINE_LOCATION_DATA (pfile->line_table,
+					   result->src_loc,
+					   tok_range, NULL);
+
   return result;
 }
 
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 3c19f93..3810c88 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -69,7 +69,10 @@ 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;
+  return ((hashval_t) lb->locus
+	  + (hashval_t) lb->src_range.m_start
+	  + (hashval_t) lb->src_range.m_finish
+	  + (size_t) lb->data);
 }
 
 /* Compare function for location_adhoc_data hashtable.  */
@@ -81,7 +84,10 @@ location_adhoc_data_eq (const void *l1, const void *l2)
       (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;
+  return (lb1->locus == lb2->locus
+	  && lb1->src_range.m_start == lb2->src_range.m_start
+	  && lb1->src_range.m_finish == lb2->src_range.m_finish
+	  && lb1->data == lb2->data);
 }
 
 /* Update the hashtable when location_adhoc_data is reallocated.  */
@@ -110,19 +116,20 @@ rebuild_location_adhoc_htab (struct line_maps *set)
 
 source_location
 get_combined_adhoc_loc (struct line_maps *set,
-			source_location locus, void *data)
+			source_location locus,
+			source_range src_range,
+			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.src_range = src_range;
   lb.data = data;
   slot = (struct location_adhoc_data **)
       htab_find_slot (set->location_adhoc_data_map.htab, &lb, INSERT);
@@ -177,6 +184,13 @@ get_location_from_adhoc_loc (struct line_maps *set, source_location loc)
   return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
 }
 
+source_range
+get_range_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].src_range;
+}
+
 /* Finalize the location_adhoc_data structure.  */
 void
 location_adhoc_data_fini (struct line_maps *set)
@@ -1478,9 +1492,9 @@ linemap_expand_location (struct line_maps *set,
   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;
+      loc = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
     }
 
   if (loc < RESERVED_LOCATION_COUNT)
-- 
1.8.5.3

