From 9134ffed65ad5327e79d5cd1669410e189fadc1c Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 8 Jul 2016 17:30:36 -0400
Subject: [PATCH 14/38] FIXME: WIP on C++ support for locations within string
 literals

---
 gcc/cp/parser.c                                    |  14 +-
 gcc/gimplify.c                                     |   2 +-
 gcc/testsuite/g++.dg/ext/builtin4.C                |   8 +-
 .../plugin/diagnostic-test-string-literals-1.C     | 172 +++++++++++++++++++++
 gcc/testsuite/g++.dg/plugin/plugin.exp             |   3 +
 5 files changed, 196 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/plugin/diagnostic-test-string-literals-1.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d2e7bae..5787f21 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3867,7 +3867,9 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
   tree value;
   size_t count;
   struct obstack str_ob;
+  struct obstack loc_ob;
   cpp_string str, istr, *strs;
+  location_t *locs = NULL;
   cp_token *tok;
   enum cpp_ttype type, curr_type;
   int have_suffix_p = 0;
@@ -3923,6 +3925,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
     {
       location_t last_tok_loc = tok->location;
       gcc_obstack_init (&str_ob);
+      gcc_obstack_init (&loc_ob);
       count = 0;
 
       do
@@ -3968,6 +3971,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
 	    }
 
 	  obstack_grow (&str_ob, &str, sizeof (cpp_string));
+	  obstack_grow (&loc_ob, &tok->location, sizeof (location_t));
 
 	  last_tok_loc = tok->location;
 
@@ -3993,6 +3997,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
       loc = make_location (loc, loc, get_finish (last_tok_loc));
 
       strs = (cpp_string *) obstack_finish (&str_ob);
+      locs = (location_t *) obstack_finish (&loc_ob);
+
+      gcc_assert (locs);
+      gcc_assert (g_string_concat_db);
+      g_string_concat_db->record_string_concatenation (count, locs);
     }
 
   if (type != CPP_STRING && !wide_ok)
@@ -4042,7 +4051,10 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
     value = error_mark_node;
 
   if (count > 1)
-    obstack_free (&str_ob, 0);
+    {
+      obstack_free (&str_ob, 0);
+      obstack_free (&loc_ob, 0);
+    }
 
   return cp_expr (value, loc);
 }
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 2f0dd88..9480eb1 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -2397,7 +2397,7 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location,
   /* FIXME diagnostics: This will mess up gcc.dg/Warray-bounds.c.  */
   /* Make sure arguments have the same location as the function call
      itself.  */
-  protected_set_expr_location (*arg_p, call_location);
+  //protected_set_expr_location (*arg_p, call_location);
 
   /* There is a sequence point before a function call.  Side effects in
      the argument list must occur before the actual call. So, when
diff --git a/gcc/testsuite/g++.dg/ext/builtin4.C b/gcc/testsuite/g++.dg/ext/builtin4.C
index 8804b53..4d9bf10 100644
--- a/gcc/testsuite/g++.dg/ext/builtin4.C
+++ b/gcc/testsuite/g++.dg/ext/builtin4.C
@@ -1,10 +1,16 @@
 // Verify that builtin is used when declared in global namespace
 
 // { dg-do compile }
-// { dg-options "-Wall" }
+// { dg-options "-Wall -fdiagnostics-show-caret" }
 
 extern "C" int printf(const char*,...);
 
 void foo() {
   printf("%d"); 		// { dg-warning "expects a matching" }
+
+  /* Verify source range of diagnostic (PR c++/56856).  */
+  /* { dg-begin-multiline-output "" }
+   printf("%d");
+           ~^
+   { dg-end-multiline-output "" } */
 }
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-string-literals-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-string-literals-1.C
new file mode 100644
index 0000000..73c5b2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-string-literals-1.C
@@ -0,0 +1,172 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdiagnostics-show-caret" } */
+
+/* This is a collection of unittests for ranges within string literals,
+   using diagnostic_plugin_test_string_literals, which handles
+   "__emit_string_literal_range" by generating a warning at the given
+   subset of a string literal.
+
+   The indices are 0-based.  It's easiest to verify things using string
+   literals that are runs of 0-based digits (to avoid having to count
+   characters).  */
+
+extern void __emit_string_literal_range (const char *literal,
+					 int start_idx, int end_idx);
+
+void
+test_simple_string_literal (void)
+{
+  __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */
+			       6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("0123456789",
+                                       ^~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_concatenated_string_literal (void)
+{
+  __emit_string_literal_range ("01234" "56789", /* { dg-warning "range" } */
+			       3, 6);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234" "56789",
+                                    ^~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_multiline_string_literal (void)
+{
+  __emit_string_literal_range ("01234" /* { dg-warning "range" } */
+                               "56789",
+                               3, 6);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234"
+                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                "56789",
+                                ~~~  
+   { dg-end-multiline-output "" } */
+  /* FIXME: why does the above need two trailing spaces?  */
+}
+
+/* Tests of various unicode encodings.
+
+   Digits 0 through 9 are unicode code points:
+      U+0030 DIGIT ZERO
+      ...
+      U+0039 DIGIT NINE
+   However, these are not always valid as UCN (see the comment in
+   libcpp/charset.c:_cpp_valid_ucn).
+
+   Hence we need to test UCN using an alternative unicode
+   representation of numbers; let's use Roman numerals,
+   (though these start at one, not zero):
+      U+2170 SMALL ROMAN NUMERAL ONE
+      ...
+      U+2174 SMALL ROMAN NUMERAL FIVE  ("v")
+      U+2175 SMALL ROMAN NUMERAL SIX   ("vi")
+      ...
+      U+2178 SMALL ROMAN NUMERAL NINE.  */
+
+void
+test_hex (void)
+{
+  /* Digits 0-9, expressing digit 5 in ASCII as "\x35"
+     and with a space in place of digit 6, to terminate the escaped
+     hex code.  */
+  __emit_string_literal_range ("01234\x35 789", /* { dg-warning "range" } */
+			       3, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234\x35 789"
+                                    ^~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_oct (void)
+{
+  /* Digits 0-9, expressing digit 5 in ASCII as "\065"
+     and with a space in place of digit 6, to terminate the escaped
+     octal code.  */
+  __emit_string_literal_range ("01234\065 789", /* { dg-warning "range" } */
+			       3, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234\065 789"
+                                    ^~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_multiple (void)
+{
+  /* Digits 0-9, expressing digit 5 in ASCII as hex "\x35"
+     digit 6 in ASCII as octal "\066", concatenating multiple strings.  */
+  __emit_string_literal_range ("01234"  "\x35"  "\066"  "789", /* { dg-warning "range" } */
+			       3, 8);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234"  "\x35"  "\066"  "789",
+                                    ^~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_ucn4 (void)
+{
+  /* Digits 0-9, expressing digits 5 and 6 as Roman numerals expressed
+     as UCN 4.
+     The resulting string is encoded as UTF-8.  Most of the digits are 1 byte
+     each, but digits 5 and 6 are encoded with 3 bytes each.
+     Hence to underline digits 4-7 we need to underling using bytes 4-11 in
+     the UTF-8 encoding.  */
+  __emit_string_literal_range ("01234\u2174\u2175789", /* { dg-warning "range" } */
+			       4, 11);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234\u2174\u2175789",
+                                     ^~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_ucn8 (void)
+{
+  /* Digits 0-9, expressing digits 5 and 6 as Roman numerals as UCN 8.
+     The resulting string is the same as as in test_ucn4 above, and hence
+     has the same UTF-8 encoding, and so we again need to underline bytes
+     4-11 in the UTF-8 encoding in order to underline digits 4-7.  */
+  __emit_string_literal_range ("01234\U00002174\U00002175789", /* { dg-warning "range" } */
+			       4, 11);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range ("01234\U00002174\U00002175789",
+                                     ^~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_u8 (void)
+{
+  /* Digits 0-9.  */
+  __emit_string_literal_range (u8"0123456789", /* { dg-warning "range" } */
+			       4, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range (u8"0123456789",
+                                       ^~~~
+   { dg-end-multiline-output "" } */
+}
+
+void
+test_macro (void)
+{
+#define START "01234"  /* { dg-warning "range" } */
+  __emit_string_literal_range (START
+                               "56789",
+                               3, 6);
+/* { dg-begin-multiline-output "" }
+ #define START "01234"
+                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   __emit_string_literal_range (START
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                "56789",
+                                ~~~
+   { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp
index 5247697..4702000 100644
--- a/gcc/testsuite/g++.dg/plugin/plugin.exp
+++ b/gcc/testsuite/g++.dg/plugin/plugin.exp
@@ -65,6 +65,9 @@ set plugin_test_list [list \
     { def_plugin.c def-plugin-test.C } \
     { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
 	  diagnostic-test-expressions-1.C } \
+    { ../../gcc.dg/plugin/diagnostic_plugin_test_string_literals.c \
+	  diagnostic-test-string-literals-1.C } \
+
 ]
 
 foreach plugin_test $plugin_test_list {
-- 
1.8.5.3

