From d8f169c14939d4e25c516f18647b3fb06cba4fca Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 20 Dec 2017 16:46:17 -0500
Subject: [PATCH 34/42] FIXME: WIP on PR middle-end/83516

---
 gcc/substring-locations.c                          |  4 +
 ...est-string-literals-format_warning_at-inlined.c | 23 ++++++
 ...t-string-literals-format_warning_at-percent-G.c | 23 ++++++
 ...t-string-literals-format_warning_at-percent-K.c | 23 ++++++
 ...nostic-test-string-literals-format_warning_at.c | 16 ++++
 ...stic-test-string-literals-format_warning_n_at.c | 18 +++++
 .../diagnostic_plugin_test_string_literals.c       | 85 +++++++++++++++++++---
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |  7 +-
 8 files changed, 186 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-inlined.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-G.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-K.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_n_at.c

diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
index db88f20..a896446 100644
--- a/gcc/substring-locations.c
+++ b/gcc/substring-locations.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "substring-locations.h"
 #include "gcc-rich-location.h"
+#include "tree-pretty-print.h"
 
 /* format_string_diagnostic_t's ctor, giving information for use by
    the emit_warning* member functions, as follows:
@@ -213,6 +214,9 @@ format_string_diagnostic_t::emit_warning_n_va (int opt,
     diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc,
 			 DK_WARNING);
   diagnostic.option_index = opt;
+  diagnostic.message.x_data = &diagnostic.x_data;
+  percent_K_format (&diagnostic.message, primary_loc,
+		    LOCATION_BLOCK (primary_loc));
   bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
 
   if (!err && fmt_substring_loc && !substring_within_range)
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-inlined.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-inlined.c
new file mode 100644
index 0000000..a8d9be6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-inlined.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -O -fdiagnostics-show-caret" } */
+
+extern void __emit_format_warning_at_substring (const void *literal, int caret_idx,
+						int start_idx, int end_idx);
+
+__attribute__((always_inline))
+static void
+test_of_inlining (void)
+{
+  __emit_format_warning_at_substring ("0123456789", /* { dg-warning "message" } */
+				      6, 6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_format_warning_at_substring ("0123456789",
+                                              ^~
+   { dg-end-multiline-output "" } */
+}
+
+int main ()
+{
+  test_of_inlining ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-G.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-G.c
new file mode 100644
index 0000000..f7bf6de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-G.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -O -fdiagnostics-show-caret" } */
+
+extern void __emit_format_warning_at_substring_G (const void *literal, int caret_idx,
+						  int start_idx, int end_idx);
+
+__attribute__((always_inline))
+static void
+test_of_inlining_with_G (void)
+{
+  __emit_format_warning_at_substring_G ("0123456789", /* { dg-warning "message" } */
+					6, 6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_format_warning_at_substring_G ("0123456789",
+                                                ^~
+   { dg-end-multiline-output "" } */
+}
+
+int main ()
+{
+  test_of_inlining_with_G ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-K.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-K.c
new file mode 100644
index 0000000..e741316
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at-percent-K.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -O -fdiagnostics-show-caret" } */
+
+extern void __emit_format_warning_at_substring_K (const void *literal, int caret_idx,
+						  int start_idx, int end_idx);
+
+__attribute__((always_inline))
+static void
+test_of_inlining_with_K (void)
+{
+  __emit_format_warning_at_substring_K ("0123456789", /* { dg-warning "message" } */
+					6, 6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_format_warning_at_substring_K ("0123456789",
+                                                ^~
+   { dg-end-multiline-output "" } */
+}
+
+int main ()
+{
+  test_of_inlining_with_K ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at.c
new file mode 100644
index 0000000..da8cfdd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_at.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -O -fdiagnostics-show-caret" } */
+
+extern void __emit_format_warning_at_substring (const void *literal, int caret_idx,
+						int start_idx, int end_idx);
+
+void
+test (void)
+{
+  __emit_format_warning_at_substring ("0123456789", /* { dg-warning "message" } */
+				      6, 6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_format_warning_at_substring ("0123456789",
+                                              ^~
+   { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_n_at.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_n_at.c
new file mode 100644
index 0000000..76a9368
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-format_warning_n_at.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdiagnostics-show-caret" } */
+
+// FIXME
+
+extern void __emit_format_warning_n_at_substring (const void *literal, int caret_idx,
+						  int start_idx, int end_idx);
+
+void
+test_of_plural_forms (void)
+{
+  __emit_format_warning_n_at_substring ("0123456789", /* { dg-warning "range" } */
+					6, 6, 7);
+/* { dg-begin-multiline-output "" }
+   __emit_format_warning_n_at_substring ("0123456789",
+                                                ^~
+   { dg-end-multiline-output "" } */
+}
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 cf99697..99f93a4 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
@@ -1,6 +1,6 @@
 /* This plugin uses the diagnostics code to verify tracking of source code
    locations within string literals.  */
-/* { dg-options "-O" } */
+/* { dg-options "-Og" } */
 
 #include "gcc-plugin.h"
 #include "config.h"
@@ -65,15 +65,26 @@ public:
 
 }; // class pass_test_string_literals
 
+enum kind
+{
+  KIND_EMIT_WARNING,
+  KIND_FORMAT_WARNING_AT_SUBSTRING,
+  KIND_FORMAT_WARNING_AT_SUBSTRING_G,
+  KIND_FORMAT_WARNING_AT_SUBSTRING_K,
+  KIND_FORMAT_WARNING_N_AT_SUBSTRING,
+};
+
+// FIXME:
 /* Determine if STMT is a call with NUM_ARGS arguments to a function
-   named FUNCNAME.
+   with a name starting with FUNCNAME_PREFIX.
    If so, return STMT as a gcall *.  Otherwise return NULL.  */
 
 static gcall *
-check_for_named_call (gimple *stmt,
-		      const char *funcname, unsigned int num_args)
+check_for_named_call_prefix (gimple *stmt, const char *funcname_prefix,
+			     enum kind *out_kind)
 {
-  gcc_assert (funcname);
+  gcc_assert (funcname_prefix);
+  gcc_assert (out_kind);
 
   gcall *call = dyn_cast <gcall *> (stmt);
   if (!call)
@@ -83,7 +94,22 @@ check_for_named_call (gimple *stmt,
   if (!fndecl)
     return NULL;
 
-  if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
+  const char *funcname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+  unsigned int num_args = 4;
+  if (0 == strcmp (funcname, "__emit_string_literal_range"))
+    *out_kind = KIND_EMIT_WARNING;
+  else if (0 == strcmp (funcname, "__emit_format_warning_at_substring"))
+    *out_kind = KIND_FORMAT_WARNING_AT_SUBSTRING;
+  else if (0 == strcmp (funcname, "__emit_format_warning_at_substring_G"))
+    *out_kind = KIND_FORMAT_WARNING_AT_SUBSTRING_G;
+  else if (0 == strcmp (funcname, "__emit_format_warning_at_substring_K"))
+    *out_kind = KIND_FORMAT_WARNING_AT_SUBSTRING_K;
+  else if (0 == strcmp (funcname, "__emit_format_warning_n_at_substring"))
+    {
+      *out_kind = KIND_FORMAT_WARNING_N_AT_SUBSTRING;
+      num_args = 5;
+    }
+  else
     return NULL;
 
   if (gimple_call_num_args (call) != num_args)
@@ -112,7 +138,7 @@ emit_warning (location_t loc)
 /* Support code for verifying that we are correctly tracking ranges
    within string literals, for use by diagnostic-test-string-literals-*.c.
    Emit a warning showing the range of a string literal, for each call to
-   a function named "__emit_string_literal_range".
+   a function with a name starting with "__emit_string_literal_range".
    The initial argument should be a string literal; arguments 2, 3, and 4
    should be integer constants, giving the caret and range within the string
    to be printed.  */
@@ -120,7 +146,9 @@ emit_warning (location_t loc)
 static void
 test_string_literals (gimple *stmt)
 {
-  gcall *call = check_for_named_call (stmt, "__emit_string_literal_range", 4);
+  enum kind kind;
+  gcall *call
+    = check_for_named_call_prefix (stmt, "__emit_string_literal_range", &kind);
   if (!call)
     return;
 
@@ -171,9 +199,42 @@ test_string_literals (gimple *stmt)
 			    caret_idx, start_idx, end_idx);
   const char *err = substr_loc.get_location (&loc);
   if (err)
-    error_at (strloc, "unable to read substring location: %s", err);
-  else
-    emit_warning (loc);
+    {
+      error_at (strloc, "unable to read substring location: %s", err);
+      return;
+    }
+  switch (kind)
+    {
+    default:
+      gcc_unreachable ();
+
+    case KIND_EMIT_WARNING:
+      emit_warning (loc);
+      break;
+
+    case KIND_FORMAT_WARNING_AT_SUBSTRING:
+      format_warning_at_substring (substr_loc, NULL, UNKNOWN_LOCATION, NULL,
+				   NULL, 0, "message");
+      break;
+
+    case KIND_FORMAT_WARNING_AT_SUBSTRING_G:
+      format_warning_at_substring (substr_loc, NULL, UNKNOWN_LOCATION, NULL,
+				   NULL, 0, "%Gmessage", call);
+      break;
+
+    case KIND_FORMAT_WARNING_AT_SUBSTRING_K:
+      {
+	tree t = build1 (NOP_EXPR, void_type_node, size_zero_node);
+	SET_EXPR_LOCATION (t, gimple_location (call));
+	format_warning_at_substring (substr_loc, NULL, UNKNOWN_LOCATION, NULL,
+				     NULL, 0, "%Kmessage", t);
+      }
+      break;
+
+    case KIND_FORMAT_WARNING_N_AT_SUBSTRING:
+      // FIXME
+      break;
+    }
 }
 
 /* Call test_string_literals on every statement within FUN.  */
@@ -209,7 +270,7 @@ plugin_init (struct plugin_name_args *plugin_info,
     return 1;
 
   pass_info.pass = new pass_test_string_literals (g);
-  pass_info.reference_pass_name = "ssa";
+  pass_info.reference_pass_name = "*warn_function_noreturn";
   pass_info.ref_pass_instance_number = 1;
   pass_info.pos_op = PASS_POS_INSERT_AFTER;
   register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index e80226b..e8cb084 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -89,7 +89,12 @@ set plugin_test_list [list \
 	  diagnostic-test-string-literals-1.c \
 	  diagnostic-test-string-literals-2.c \
 	  diagnostic-test-string-literals-3.c \
-	  diagnostic-test-string-literals-4.c } \
+	  diagnostic-test-string-literals-4.c \
+	  diagnostic-test-string-literals-format_warning_at.c \
+	  diagnostic-test-string-literals-format_warning_at-inlined.c \
+	  diagnostic-test-string-literals-format_warning_at-percent-K.c \
+	  diagnostic-test-string-literals-format_warning_at-percent-G.c \
+	  diagnostic-test-string-literals-format_warning_n_at.c } \
     { diagnostic_plugin_test_inlining.c \
 	  diagnostic-test-inlining-1.c \
 	  diagnostic-test-inlining-2.c \
-- 
1.8.5.3

