From b31decc5d92f6445f0420fb7ac2db8914965bb94 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 6 Jul 2016 15:41:56 -0400
Subject: [PATCH 09/25] FIXME: even more WIP on on-demand substring locations

---
 gcc/c-family/c-common.c                            |   1 -
 gcc/c-family/c-common.h                            |   2 +
 gcc/c-family/c-lex.c                               |  34 +-
 gcc/c-family/c-opts.c                              |   5 +
 gcc/cp/parser.c                                    |   4 +-
 gcc/input.c                                        | 399 ++++++++++++++-------
 gcc/input.h                                        |  28 ++
 gcc/selftest.h                                     |  28 +-
 .../diagnostic_plugin_test_string_literals.c       |   3 +-
 gcc/tree.c                                         |  25 --
 gcc/tree.h                                         |  10 -
 libcpp/charset.c                                   |   4 +-
 libcpp/macro.c                                     |   1 -
 13 files changed, 350 insertions(+), 194 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 48c40a6..936ddfb 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -962,7 +962,6 @@ fname_as_string (int pretty_p)
   snprintf (namep, len, "\"%s\"", name);
   strname.text = (unsigned char *) namep;
   strname.len = len - 1;
-  //strname.loc.init_raw (UNKNOWN_LOCATION, len, 1, 1, line_table);
 
   if (cpp_interpret_string (parse_in, &strname, 1, &cstr, CPP_STRING))
     {
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 3ad5400..0dc2a80 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1116,6 +1116,8 @@ extern tree c_build_bind_expr (location_t, tree, tree);
 extern enum cpp_ttype
 conflict_marker_get_final_tok_kind (enum cpp_ttype tok1_kind);
 
+extern string_concat_db *g_string_concat_db;
+
 /* In c-pch.c  */
 extern void pch_init (void);
 extern void pch_cpp_save_state (void);
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 04f5b95..c18e8ee 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -1072,6 +1072,10 @@ interpret_fixed (const cpp_token *token, unsigned int flags)
   return value;
 }
 
+/* FIXME.  */
+
+string_concat_db GTY (()) *g_string_concat_db;
+
 /* Convert a series of STRING, WSTRING, STRING16, STRING32 and/or
    UTF8STRING tokens into a tree, performing string constant
    concatenation.  TOK is the first of these.  VALP is the location to
@@ -1097,15 +1101,16 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
   tree value;
   size_t concats = 0;
   struct obstack str_ob;
+  struct obstack loc_ob;
   cpp_string istr;
   enum cpp_ttype type = tok->type;
 
   /* Try to avoid the overhead of creating and destroying an obstack
      for the common case of just one string.  */
   cpp_string str = tok->val.str;
-  //ensure_string_has_location (&str, tok->src_loc);
+  location_t init_loc = tok->src_loc;
   cpp_string *strs = &str;
-  //location_t str0_loc = tok->src_loc;
+  location_t *locs = NULL;
 
   /* objc_at_sign_was_seen is only used when doing Objective-C string
      concatenation.  It is 'true' if we have seen an '@' before the
@@ -1150,13 +1155,14 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
       if (!concats)
 	{
 	  gcc_obstack_init (&str_ob);
-	  //ensure_string_has_location (&str, str0_loc);
+	  gcc_obstack_init (&loc_ob);
 	  obstack_grow (&str_ob, &str, sizeof (cpp_string));
+	  obstack_grow (&loc_ob, &init_loc, sizeof (location_t));
 	}
 
       concats++;
-      //ensure_string_has_location (&tok->val.str, tok->src_loc);
       obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+      obstack_grow (&loc_ob, &tok->src_loc, sizeof (location_t));
 
       if (objc_string)
 	objc_at_sign_was_seen = false;
@@ -1170,20 +1176,29 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
   /* We have read one more token than we want.  */
   _cpp_backup_tokens (parse_in, 1);
   if (concats)
-    strs = XOBFINISH (&str_ob, cpp_string *);
+    {
+      strs = XOBFINISH (&str_ob, cpp_string *);
+      locs = XOBFINISH (&loc_ob, location_t *);
+    }
 
   if (concats && !objc_string && !in_system_header_at (input_location))
     warning (OPT_Wtraditional,
 	     "traditional C rejects string constant concatenation");
 
-  // FIXME: record the concatenation here???
-
   if ((translate
        ? cpp_interpret_string : cpp_interpret_string_notranslate)
       (parse_in, strs, concats + 1, &istr, type))
     {
       value = build_string (istr.len, (const char *) istr.text);//, &istr.loc);
       free (CONST_CAST (unsigned char *, istr.text));
+
+      // FIXME: what about the notranslate case?
+      if (concats)
+	{
+	  gcc_assert (locs);
+	  gcc_assert (g_string_concat_db);
+	  g_string_concat_db->record_string_concatenation (concats + 1, locs);
+	}
     }
   else
     {
@@ -1235,7 +1250,10 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
   *valp = fix_string_type (value);
 
   if (concats)
-    obstack_free (&str_ob, 0);
+    {
+      obstack_free (&str_ob, 0);
+      obstack_free (&loc_ob, 0);
+    }
 
   return objc_string ? CPP_OBJC_STRING : type;
 }
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..c90c4a4 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -216,6 +216,11 @@ c_common_init_options (unsigned int decoded_options_count,
   unsigned int i;
   struct cpp_callbacks *cb;
 
+#if 1
+  // FIXME: use GGC
+  g_string_concat_db = new string_concat_db ();
+#endif
+
   parse_in = cpp_create_reader (c_dialect_cxx () ? CLK_GNUCXX: CLK_GNUC89,
 				ident_hash, line_table);
   cb = cpp_get_callbacks (parse_in);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 17452f4..3e8270e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3878,7 +3878,6 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
 
       str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
       str.len = TREE_STRING_LENGTH (string_tree);
-      //str.loc.init_raw (tok->location, str.len, 1, 1, line_table);
       count = 1;
 
       if (curr_tok_is_userdef_p)
@@ -3904,7 +3903,6 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
 	  count++;
 	  str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
 	  str.len = TREE_STRING_LENGTH (string_tree);
-	  //str.loc.init_raw (tok->location, str.len, 1, 1, line_table);
 
 	  if (curr_tok_is_userdef_p)
 	    {
@@ -3978,7 +3976,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
   if ((translate ? cpp_interpret_string : cpp_interpret_string_notranslate)
       (parse_in, strs, count, &istr, type))
     {
-      value = build_string (istr.len, (const char *)istr.text);//, &istr.loc);
+      value = build_string (istr.len, (const char *)istr.text);
       free (CONST_CAST (unsigned char *, istr.text));
 
       switch (type)
diff --git a/gcc/input.c b/gcc/input.c
index 2f06b5c..ed28ae1 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -1141,8 +1141,62 @@ dump_location_info (FILE *stream)
 
 /* FIXME.  */
 
+string_concat::string_concat (int num, location_t *locs)
+  : m_num (num)
+{
+  m_locs = ggc_vec_alloc <location_t> (num);
+  for (int i = 0; i < num; i++)
+    m_locs[i] = locs[i];
+}
+
+/* FIXME.  */
+
+void
+string_concat_db::record_string_concatenation (int num, location_t *locs)
+{
+  gcc_assert (num > 1);
+  gcc_assert (locs);
+
+  location_t key_loc = get_key_loc (locs[0]);
+
+  m_table.put (key_loc, string_concat (num, locs));
+}
+
+/* FIXME.  */
+
+bool
+string_concat_db::get_string_concatenation (location_t loc,
+					    int *out_num,
+					    location_t **out_locs)
+{
+  gcc_assert (out_num);
+  gcc_assert (out_locs);
+
+  location_t key_loc = get_key_loc (loc);
+
+  string_concat *concat = m_table.get (key_loc);
+  if (!concat)
+    return false;
+
+  *out_num = concat->m_num;
+  *out_locs = concat->m_locs;
+  return true;
+}
+
+/* FIXME.  */
+
+location_t
+string_concat_db::get_key_loc (location_t loc)
+{
+  return get_range_from_loc (line_table, loc).m_start;
+}
+
+
+/* FIXME.  */
+
 static bool
 get_substring_ranges_for_loc (cpp_reader *pfile,
+			      string_concat_db *concats,
 			      location_t strloc,
 			      cpp_substring_ranges &ranges)
 {
@@ -1153,42 +1207,57 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
 
   /* FIXME: handle concatenated strings by doing this repeatedly, somehow.
      We'd need to capture concatenations when they happen.  */
+  int num_locs = 1;
+  location_t *strlocs = &strloc;
+  if (concats)
+    concats->get_string_concatenation (strloc, &num_locs, &strlocs);
 
-  /* Get range of strloc.  We will use it to locate the start and finish
-     of the literal token within the line.  */
-  source_range src_range = get_range_from_loc (line_table, strloc);
-
-  if (src_range.m_start >= LINE_MAP_MAX_LOCATION_WITH_COLS)
-    /* If so, we can't reliably determine where the token started within
-       its line.  */
-    return false;
-
-  if (src_range.m_finish >= LINE_MAP_MAX_LOCATION_WITH_COLS)
-    /* If so, we can't reliably determine where the token finished within
-       its line.  */
-    return false;
-
-  expanded_location start
-    = expand_location_to_spelling_point (src_range.m_start);
-  expanded_location finish
-    = expand_location_to_spelling_point (src_range.m_finish);
-  if (start.file != finish.file)
-    return false;
-  if (start.line != finish.line)
-    return false;
-  if (start.column > finish.column)
-    return false;
-
-  int line_width;
-  const char *line = location_get_source_line (start.file, start.line,
-					       &line_width);
-  if (line == NULL)
-    return false;
+  auto_vec <cpp_string> strs (num_locs);
+  for (int i = 0; i < num_locs; i++)
+    {
 
-  /* Determine the location of the literal (including quotes
-     and leading FIXME.  */
-  const char *literal = line + start.column - 1;
-  int literal_length = finish.column - start.column + 1;
+      /* Get range of strloc.  We will use it to locate the start and finish
+	 of the literal token within the line.  */
+      source_range src_range = get_range_from_loc (line_table, strloc);
+
+      if (src_range.m_start >= LINE_MAP_MAX_LOCATION_WITH_COLS)
+	/* If so, we can't reliably determine where the token started within
+	   its line.  */
+	return false;
+
+      if (src_range.m_finish >= LINE_MAP_MAX_LOCATION_WITH_COLS)
+	/* If so, we can't reliably determine where the token finished within
+	   its line.  */
+	return false;
+
+      expanded_location start
+	= expand_location_to_spelling_point (src_range.m_start);
+      expanded_location finish
+	= expand_location_to_spelling_point (src_range.m_finish);
+      if (start.file != finish.file)
+	return false;
+      if (start.line != finish.line)
+	return false;
+      if (start.column > finish.column)
+	return false;
+
+      int line_width;
+      const char *line = location_get_source_line (start.file, start.line,
+						   &line_width);
+      if (line == NULL)
+	return false;
+
+      /* Determine the location of the literal (including quotes
+	 and leading FIXME.  */
+      const char *literal = line + start.column - 1;
+      int literal_length = finish.column - start.column + 1;
+
+      gcc_assert (line_width >= (start.column - 1 + literal_length));
+      cpp_string from;
+      from.len = literal_length;
+      from.text = (const unsigned char *)literal;
+      strs.safe_push (from);
+    }
 
   /* Rerun cpp_interpret_string, or rather, a modified version of it.  */
   /* FIXME: CPP_STRING32 captures the unicode in a fixed-width (4-byte
@@ -1196,12 +1265,8 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
      ranges, and do the UTF-8 thing separately.
      For now, we simply constrain ourselves to the UTF-8 case (for both
      source and execution encoding).  */
-  cpp_string from;
-  gcc_assert (line_width >= (start.column - 1 + literal_length));
-  from.len = literal_length;
-  from.text = (const unsigned char *)literal;
 
-  if (!cpp_interpret_string_ranges (pfile, &from, &src_range.m_start, 1,
+  if (!cpp_interpret_string_ranges (pfile, strs.address (), strlocs, num_locs,
 				    &ranges))
     return false;
 
@@ -1212,7 +1277,9 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
 /* FIXME.  */
 
 bool
-get_source_range_for_substring (cpp_reader *pfile, location_t strloc,
+get_source_range_for_substring (cpp_reader *pfile,
+				string_concat_db *concats,
+				location_t strloc,
 				int start_idx, int end_idx, source_range *out)
 {
   gcc_checking_assert (start_idx >= 0);
@@ -1220,7 +1287,7 @@ get_source_range_for_substring (cpp_reader *pfile, location_t strloc,
   gcc_assert (out);
 
   cpp_substring_ranges ranges;
-  if (!get_substring_ranges_for_loc (pfile, strloc, ranges))
+  if (!get_substring_ranges_for_loc (pfile, concats, strloc, ranges))
     return false;
 
   if (start_idx >= ranges.get_num_ranges ()
@@ -1235,13 +1302,15 @@ get_source_range_for_substring (cpp_reader *pfile, location_t strloc,
 /* FIXME.  */
 
 bool
-get_num_source_ranges_for_substring (cpp_reader *pfile, location_t strloc,
+get_num_source_ranges_for_substring (cpp_reader *pfile,
+				     string_concat_db *concats,
+				     location_t strloc,
 				     int *out)
 {
   gcc_assert (out);
 
   cpp_substring_ranges ranges;
-  if (!get_substring_ranges_for_loc (pfile, strloc, ranges))
+  if (!get_substring_ranges_for_loc (pfile, concats, strloc, ranges))
     return false;
 
   *out = ranges.get_num_ranges ();
@@ -1465,74 +1534,6 @@ test_builtins ()
   ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
 }
 
-/* Verify that locations within string literals are correctly handled.  */
-
-/* FIXME.  */
-
-static void
-assert_char_at_range (const location &loc,
-		      cpp_reader *pfile,
-		      location_t strloc, int idx,
-		      int expected_start_col, int expected_finish_col)
-{
-  source_range actual_range;
-  bool result = get_source_range_for_substring (pfile, strloc, idx, idx,
-						&actual_range);
-  if (should_have_column_data_p (strloc))
-    ASSERT_TRUE (result);
-  else
-    {
-      ASSERT_FALSE (result);
-      return;
-    }
-
-  if (should_have_column_data_p (actual_range.m_start))
-    {
-      int actual_start_col = LOCATION_COLUMN (actual_range.m_start);
-      ASSERT_EQ_AT (loc, expected_start_col, actual_start_col);
-    }
-  if (should_have_column_data_p (actual_range.m_finish))
-    {
-      int actual_finish_col = LOCATION_COLUMN (actual_range.m_finish);
-      ASSERT_EQ_AT (loc, expected_finish_col, actual_finish_col);
-    }
-}
-
-/* Macro for calling assert_char_at_range, supplying SELFTEST_LOCATION for
-   the effective location of any errors.  */
-
-#define ASSERT_CHAR_AT_RANGE(CPP_READER, STRLOC, IDX, EXPECTED_START_COL, \
-			     EXPECTED_FINISH_COL)			\
-  assert_char_at_range (SELFTEST_LOCATION, (CPP_READER), (STRLOC), (IDX),	\
-			(EXPECTED_START_COL), (EXPECTED_FINISH_COL))
-
-/* FIXME.  */
-
-static void
-assert_num_substring_ranges (const location &loc,
-			     cpp_reader *pfile,
-			     location_t strloc,
-			     int expected_num_ranges)
-{
-  int actual_num_ranges;
-  bool result
-    = get_num_source_ranges_for_substring (pfile, strloc, &actual_num_ranges);
-  if (should_have_column_data_p (strloc))
-    ASSERT_TRUE (result);
-  else
-    {
-      ASSERT_FALSE (result);
-      return;
-    }
-  ASSERT_EQ_AT (loc, expected_num_ranges, actual_num_ranges);
-}
-
-/* FIXME.  */
-
-#define ASSERT_NUM_SUBSTRING_RANGES(CPP_READER, STRLOC, EXPECTED_NUM_RANGES) \
-    assert_num_substring_ranges (SELFTEST_LOCATION, (CPP_READER), (STRLOC), \
-				 (EXPECTED_NUM_RANGES))
-
 #if 0
 
 /* Verify a complicated example of locations within a string literal.
@@ -1852,6 +1853,7 @@ struct lexer_test
   temp_source_file m_tempfile;
   temp_line_table m_tmp_lt;
   cpp_reader *m_parser;
+  string_concat_db m_concats;
 };
 
 /* Constructor.  Override line_table with a new instance based on CASE_,
@@ -1862,7 +1864,8 @@ lexer_test::lexer_test (const line_table_case &case_, const char *content) :
   /* Create a tempfile and write the text to it.  */
   m_tempfile (SELFTEST_LOCATION, ".c", content),
   m_tmp_lt (case_),
-  m_parser (cpp_create_reader (CLK_GNUC99, NULL, line_table))
+  m_parser (cpp_create_reader (CLK_GNUC99, NULL, line_table)),
+  m_concats ()
 {
   cpp_init_iconv (m_parser);
 
@@ -1899,6 +1902,81 @@ lexer_test::get_token ()
   return tok;
 }
 
+/* Verify that locations within string literals are correctly handled.  */
+
+/* FIXME.  */
+
+static void
+assert_char_at_range (const location &loc,
+		      lexer_test& test,
+		      location_t strloc, int idx,
+		      int expected_start_col, int expected_finish_col)
+{
+  cpp_reader *pfile = test.m_parser;
+  string_concat_db *concats = &test.m_concats;
+
+  source_range actual_range;
+  bool result = get_source_range_for_substring (pfile, concats, strloc,
+						idx, idx, &actual_range);
+  if (should_have_column_data_p (strloc))
+    ASSERT_TRUE_AT (loc, result);
+  else
+    {
+      ASSERT_FALSE_AT (loc, result);
+      return;
+    }
+
+  if (should_have_column_data_p (actual_range.m_start))
+    {
+      int actual_start_col = LOCATION_COLUMN (actual_range.m_start);
+      ASSERT_EQ_AT (loc, expected_start_col, actual_start_col);
+    }
+  if (should_have_column_data_p (actual_range.m_finish))
+    {
+      int actual_finish_col = LOCATION_COLUMN (actual_range.m_finish);
+      ASSERT_EQ_AT (loc, expected_finish_col, actual_finish_col);
+    }
+}
+
+/* Macro for calling assert_char_at_range, supplying SELFTEST_LOCATION for
+   the effective location of any errors.  */
+
+#define ASSERT_CHAR_AT_RANGE(LEXER_TEST, STRLOC, IDX, EXPECTED_START_COL, \
+			     EXPECTED_FINISH_COL)			\
+  assert_char_at_range (SELFTEST_LOCATION, (LEXER_TEST), (STRLOC), (IDX),	\
+			(EXPECTED_START_COL), (EXPECTED_FINISH_COL))
+
+/* FIXME.  */
+
+static void
+assert_num_substring_ranges (const location &loc,
+			     lexer_test& test,
+			     location_t strloc,
+			     int expected_num_ranges)
+{
+  cpp_reader *pfile = test.m_parser;
+  string_concat_db *concats = &test.m_concats;
+
+  int actual_num_ranges;
+  bool result
+    = get_num_source_ranges_for_substring (pfile, concats, strloc,
+					   &actual_num_ranges);
+  if (should_have_column_data_p (strloc))
+    ASSERT_TRUE (result);
+  else
+    {
+      ASSERT_FALSE (result);
+      return;
+    }
+  ASSERT_EQ_AT (loc, expected_num_ranges, actual_num_ranges);
+}
+
+/* FIXME.  */
+
+#define ASSERT_NUM_SUBSTRING_RANGES(LEXER_TEST, STRLOC, EXPECTED_NUM_RANGES) \
+    assert_num_substring_ranges (SELFTEST_LOCATION, (LEXER_TEST), (STRLOC), \
+				 (EXPECTED_NUM_RANGES))
+
 /* Lex a simple string literal.  Verify the substring location data, before
    and after running cpp_interpret_string on it.  */
 
@@ -1928,9 +2006,10 @@ test_lexer_string_locations_simple (const line_table_case &case_)
   /* Verify ranges of individual characters.  This no longer includes the
      quotes.  */
   for (int i = 0; i < 9; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i,
+			  10 + i, 10 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 10);
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 10);
 }
 
 /* Lex a string literal containing a hex-escaped character.
@@ -1963,12 +2042,12 @@ test_lexer_string_locations_hex (const line_table_case &case_)
   /* Verify ranges of individual characters.  This no longer includes the
      quotes.  */
   for (int i = 0; i < 5; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
-  ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, 5, 15, 18);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
+  ASSERT_CHAR_AT_RANGE (test, tok->src_loc, 5, 15, 18);
   for (int i = 6; i <= 9; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 13 + i, 13 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 13 + i, 13 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 10);
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 10);
 }
 
 /* Lex a string literal containing an octal-escaped character.
@@ -1995,12 +2074,12 @@ test_lexer_string_locations_oct (const line_table_case &case_)
   /* Verify ranges of individual characters.  This no longer includes the
      quotes.  */
   for (int i = 0; i < 5; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
-  ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, 5, 15, 18);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
+  ASSERT_CHAR_AT_RANGE (test, tok->src_loc, 5, 15, 18);
   for (int i = 6; i <= 9; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 13 + i, 13 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 13 + i, 13 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 10);
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 10);
 }
 
 /* Lex a string literal containing UCN 4 characters.
@@ -2048,18 +2127,18 @@ test_lexer_string_locations_ucn4 (const line_table_case &case_)
      quotes.
      '01234'.  */
   for (int i = 0; i < 4; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
   /* U+2174.  */
   for (int i = 5; i < 7; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 15, 20);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 15, 20);
   /* U+2175.  */
   for (int i = 8; i < 10; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 21, 26);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 21, 26);
   /* '789'.  */
   for (int i = 11; i <= 13; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 16 + i, 16 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 16 + i, 16 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 14);
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 14);
 }
 
 /* Lex a string literal containing UCN 8 characters.
@@ -2090,18 +2169,18 @@ test_lexer_string_locations_ucn8 (const line_table_case &case_)
      quotes.
      '01234'.  */
   for (int i = 0; i < 4; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
   /* U+2174.  */
   for (int i = 5; i < 7; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 15, 24);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 15, 24);
   /* U+2175.  */
   for (int i = 8; i < 10; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 25, 34);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 25, 34);
   /* '789' at columns 35-37  */
   for (int i = 11; i <= 13; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 24 + i, 24 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 24 + i, 24 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 14);
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 14);
 }
 
 /* Lex a u8-string literal.
@@ -2126,7 +2205,7 @@ test_lexer_string_locations_u8 (const line_table_case &case_)
   /* Verify ranges of individual characters.  This no longer includes the
      quotes.  */
   for (int i = 0; i < 9; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
 }
 
 /* Lex a string literal containing UTF-8 source characters.
@@ -2136,7 +2215,6 @@ test_lexer_string_locations_u8 (const line_table_case &case_)
 static void
 test_lexer_string_locations_utf8_source (const line_table_case &case_)
 {
-
  /* This string literal is written out to the source file as UTF-8,
     and is of the form "before mojibake after", where "mojibake"
     is written as the following four unicode code points:
@@ -2196,9 +2274,57 @@ test_lexer_string_locations_utf8_source (const line_table_case &case_)
      Assuming that both source and execution encodings are UTF-8, we have
      a run of 25 octets in each.  */
   for (int i = 0; i < 25; i++)
-    ASSERT_CHAR_AT_RANGE (test.m_parser, tok->src_loc, i, 10 + i, 10 + i);
+    ASSERT_CHAR_AT_RANGE (test, tok->src_loc, i, 10 + i, 10 + i);
+
+  ASSERT_NUM_SUBSTRING_RANGES (test, tok->src_loc, 25);
+}
+
+/* Test of string literal concatenation.  */
+
+static void
+test_lexer_string_locations_concatenation (const line_table_case &case_)
+{
+  /* Digits 0-9.
+     .....................000000000.111111.11112222222222
+     .....................123456789.012345.67890123456789.  */
+  const char *content = ("        \"01234\" /* non-str */\n"
+			 "        \"56789\" /* non-str */\n");
+  lexer_test test (case_, content);
+
+  //cpp_string input_strs[2];
+  location_t input_locs[2];
+
+  /* Verify that we get the expected tokens back.  */
+  const cpp_token *tok_a = test.get_token ();
+  ASSERT_EQ (tok_a->type, CPP_STRING);
+  ASSERT_TOKEN_AS_TEXT_EQ
+    (test.m_parser, tok_a,
+     "\"01234\"");
+  location_t initial_loc = tok_a->src_loc;
+  input_locs[0] = tok_a->src_loc;
+
+  const cpp_token *tok_b = test.get_token ();
+  ASSERT_EQ (tok_b->type, CPP_STRING);
+  ASSERT_TOKEN_AS_TEXT_EQ
+    (test.m_parser, tok_b,
+     "\"56789\"");
+  input_locs[1] = tok_b->src_loc;
+
+  /* Simulate c-lex.c's lex_string in order to record concatenation.  */
+  test.m_concats.record_string_concatenation (2, input_locs);
+#if 0
+  m_parser-
+  cpp_string output_str;
+  cpp_interpret_string (test.m_parser, input_strs, 2, &output_str, CPP_STRING);
+  ASSERT_STREQ ((const char *)output_str.text, "0123456789");
+#endif
+
+  for (int i = 0; i < 5; i++)
+    ASSERT_CHAR_AT_RANGE (test, initial_loc, i, 10 + i, 10 + i);
+  for (int i = 5; i <= 9; i++)
+    ASSERT_CHAR_AT_RANGE (test, initial_loc, i, 5 + i, 5 + i);
 
-  ASSERT_NUM_SUBSTRING_RANGES (test.m_parser, tok->src_loc, 25);
+  ASSERT_NUM_SUBSTRING_RANGES (test, initial_loc, 10);
 }
 
 /* A table of interesting location_t values, giving one axis of our test
@@ -2266,6 +2392,7 @@ input_c_tests ()
 	  test_lexer_string_locations_ucn8 (c);
 	  test_lexer_string_locations_u8 (c);
 	  test_lexer_string_locations_utf8_source (c);
+	  test_lexer_string_locations_concatenation (c);
 	  num_cases_tested++;
 	}
     }
diff --git a/gcc/input.h b/gcc/input.h
index 0caf962..8906000 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -82,7 +82,35 @@ void dump_location_info (FILE *stream);
 
 void diagnostics_file_cache_fini (void);
 
+class GTY(()) string_concat
+{
+ public:
+  string_concat (int num, location_t *locs);
+
+  //private:
+  int m_num;
+  location_t *m_locs;
+};
+
+struct location_hash : int_hash <location_t, UNKNOWN_LOCATION> { };
+
+class GTY(()) string_concat_db
+{
+ public:
+  void record_string_concatenation (int num, location_t *locs);
+
+  bool get_string_concatenation (location_t loc,
+				 int *out_num,
+				 location_t **out_locs);
+
+ private:
+  static location_t get_key_loc (location_t loc);
+
+  hash_map <location_hash, string_concat > m_table;
+};
+
 extern bool get_source_range_for_substring (cpp_reader *pfile,
+					    string_concat_db *concats,
 					    location_t strloc,
 					    int start_idx, int end_idx,
 					    source_range *out);
diff --git a/gcc/selftest.h b/gcc/selftest.h
index c3a253b..02e4694 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -102,13 +102,19 @@ extern int num_passes;
    ::selftest::fail if it false.  */
 
 #define ASSERT_TRUE(EXPR)				\
+  ASSERT_TRUE_AT (SELFTEST_LOCATION, (EXPR))
+
+/* Like ASSERT_TRUE, but treat LOC as the effective location of the
+   selftest.  */
+
+#define ASSERT_TRUE_AT(LOC, EXPR)			\
   SELFTEST_BEGIN_STMT					\
   const char *desc = "ASSERT_TRUE (" #EXPR ")";		\
   bool actual = (EXPR);					\
   if (actual)						\
-    ::selftest::pass (SELFTEST_LOCATION, desc);	\
+    ::selftest::pass ((LOC), desc);			\
   else							\
-    ::selftest::fail (SELFTEST_LOCATION, desc);		\
+    ::selftest::fail ((LOC), desc);			\
   SELFTEST_END_STMT
 
 /* Evaluate EXPR and coerce to bool, calling
@@ -116,13 +122,19 @@ extern int num_passes;
    ::selftest::fail if it true.  */
 
 #define ASSERT_FALSE(EXPR)					\
+  ASSERT_FALSE_AT (SELFTEST_LOCATION, (EXPR))
+
+/* Like ASSERT_FALSE, but treat LOC as the effective location of the
+   selftest.  */
+
+#define ASSERT_FALSE_AT(LOC, EXPR)				\
   SELFTEST_BEGIN_STMT						\
-  const char *desc = "ASSERT_FALSE (" #EXPR ")";		\
-  bool actual = (EXPR);					\
-  if (actual)							\
-    ::selftest::fail (SELFTEST_LOCATION, desc);				\
-  else								\
-    ::selftest::pass (SELFTEST_LOCATION, desc);				\
+  const char *desc = "ASSERT_FALSE (" #EXPR ")";			\
+  bool actual = (EXPR);							\
+  if (actual)								\
+    ::selftest::fail ((LOC), desc);			\
+  else									\
+    ::selftest::pass ((LOC), desc);					\
   SELFTEST_END_STMT
 
 /* Evaluate EXPECTED and ACTUAL and compare them with ==, calling
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.c
index 71e6e7c..d92c2b5 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.c
@@ -27,6 +27,7 @@
 #include "tree-pass.h"
 #include "intl.h"
 #include "plugin-version.h"
+#include "c-family/c-common.h"
 #include "diagnostic.h"
 #include "context.h"
 #include "print-tree.h"
@@ -159,7 +160,7 @@ test_string_literals (gimple *stmt)
   /* A STRING_CST doesn't have a location, but the ADDR_EXPR does.  */
   location_t strloc = EXPR_LOCATION (t_addr_string);
   source_range src_range;
-  if (get_source_range_for_substring (parse_in, strloc,
+  if (get_source_range_for_substring (parse_in, g_string_concat_db, strloc,
 				      start_idx, end_idx, &src_range))
     emit_warning (src_range);
   else
diff --git a/gcc/tree.c b/gcc/tree.c
index afb8435..bc60190 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -62,7 +62,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "ipa-utils.h"
 #include "selftest.h"
-#include "cpplib.h"
 
 /* Tree code classes.  */
 
@@ -2010,30 +2009,6 @@ build_string (int len, const char *str)
   return s;
 }
 
-#if 0
-/* As above, but with per-character location information.  */
-
-struct cpp_string_location_stats cpp_string_location_stats;
-
-tree
-build_string (int len, const char *str, cpp_string_location *strloc)
-{
-  tree s = build_string (len, str);
-
-  /* Need to allocate a copy:  */
-  TREE_STRING_LOCATION (s) = ggc_alloc <cpp_string_location> ();
-  *TREE_STRING_LOCATION (s) = *strloc;
-
-  /* Maintain stats on string locations.  */
-  cpp_string_location_stats.count_all++;
-  if (strloc->trivial_p ())
-    cpp_string_location_stats.count_trivial++;
-
-  return s;
-}
-#endif
-
-
 /* Return a newly constructed COMPLEX_CST node whose value is
    specified by the real and imaginary parts REAL and IMAG.
    Both REAL and IMAG should be constant nodes.  TYPE, if specified,
diff --git a/gcc/tree.h b/gcc/tree.h
index 1e34fd0..99ed8ff 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1008,16 +1008,6 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define TREE_STRING_POINTER(NODE) \
   ((const char *)(STRING_CST_CHECK (NODE)->string.str))
 
-extern struct cpp_string_location_stats
-{
-  /* How many have been used to construct STRING_CST.  */
-  int count_all;
-
-  /* How many of these consisted of a single run of 1-byte-per-char
-     bytes.  */
-  int count_trivial;
-} cpp_string_location_stats;
-
 /* In a COMPLEX_CST node.  */
 #define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real)
 #define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag)
diff --git a/libcpp/charset.c b/libcpp/charset.c
index 4169a13..9dbf4d9 100644
--- a/libcpp/charset.c
+++ b/libcpp/charset.c
@@ -2440,7 +2440,9 @@ cpp_string_location_reader (source_location src_loc,
 			    line_maps *line_table)
 : m_line_table (line_table)
 {
-  /* LOC might be a macro location.  It only makes sense to do
+  src_loc = get_range_from_loc (line_table, src_loc).m_start;
+
+  /* SRC_LOC might be a macro location.  It only makes sense to do
      column-by-column calculations on ordinary maps, so get the
      corresponding location in an ordinary map.  */
   m_loc
diff --git a/libcpp/macro.c b/libcpp/macro.c
index d003ebe..a3b8348 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -217,7 +217,6 @@ new_string_token (cpp_reader *pfile, unsigned char *text, unsigned int len)
   token->type = CPP_STRING;
   token->val.str.len = len;
   token->val.str.text = text;
-  //token->val.str.loc.init ();
   token->flags = 0;
   return token;
 }
-- 
1.8.5.3

