Move class substring_loc from c-family into gcc
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 7 Sep 2016 16:56:23 +0000 (16:56 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 7 Sep 2016 16:56:23 +0000 (16:56 +0000)
gcc/ChangeLog:
* Makefile.in (OBJS): Add substring-locations.o.
* langhooks-def.h (class substring_loc): New forward decl.
(lhd_get_substring_location): New decl.
(LANG_HOOKS_GET_SUBSTRING_LOCATION): New macro.
(LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_GET_SUBSTRING_LOCATION.
* langhooks.c (lhd_get_substring_location): New function.
* langhooks.h (class substring_loc): New forward decl.
(struct lang_hooks): Add field get_substring_location.
* substring-locations.c: New file, taking definition of
format_warning_va and format_warning_at_substring from
c-family/c-format.c, making them non-static.
* substring-locations.h (class substring_loc): Move class here
from c-family/c-common.h.  Add and rewrite comments.
(format_warning_va): New decl.
(format_warning_at_substring): New decl.
(get_source_location_for_substring): Add comment.

gcc/c-family/ChangeLog:
* c-common.c (get_cpp_ttype_from_string_type): Handle being passed
a POINTER_TYPE.
(substring_loc::get_location): Move to substring-locations.c,
keeping implementation as...
(c_get_substring_location): New function, from the above, reworked
to use accessors rather than member lookup.
* c-common.h (class substring_loc): Move to substring-locations.h,
replacing with a forward decl.
(c_get_substring_location): New decl.
* c-format.c: Include "substring-locations.h".
(format_warning_va): Move to substring-locations.c.
(format_warning_at_substring): Likewise.

gcc/c/ChangeLog:
* c-lang.c (LANG_HOOKS_GET_SUBSTRING_LOCATION): Use
c_get_substring_location for this new langhook.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic_plugin_test_string_literals.c: Include
"substring-locations.h".

From-SVN: r240028

15 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/c/ChangeLog
gcc/c/c-lang.c
gcc/langhooks-def.h
gcc/langhooks.c
gcc/langhooks.h
gcc/substring-locations.c [new file with mode: 0644]
gcc/substring-locations.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.c

index 752fac022d663e96f0cebfd1b06a3ed5655b2e70..f31907a88248e058b9e5d160c919d937e18ef10c 100644 (file)
@@ -1,3 +1,22 @@
+2016-09-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (OBJS): Add substring-locations.o.
+       * langhooks-def.h (class substring_loc): New forward decl.
+       (lhd_get_substring_location): New decl.
+       (LANG_HOOKS_GET_SUBSTRING_LOCATION): New macro.
+       (LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_GET_SUBSTRING_LOCATION.
+       * langhooks.c (lhd_get_substring_location): New function.
+       * langhooks.h (class substring_loc): New forward decl.
+       (struct lang_hooks): Add field get_substring_location.
+       * substring-locations.c: New file, taking definition of
+       format_warning_va and format_warning_at_substring from
+       c-family/c-format.c, making them non-static.
+       * substring-locations.h (class substring_loc): Move class here
+       from c-family/c-common.h.  Add and rewrite comments.
+       (format_warning_va): New decl.
+       (format_warning_at_substring): New decl.
+       (get_source_location_for_substring): Add comment.
+
 2016-09-07  Eric Gallager  <egall@gwmail.gwu.edu>
 
        * config/i386/i386.c: Add 'U' suffix to processor feature bits
index 7c1828599988412688c5e5894aeedf3b979f3b86..332c85e2fb2e7e23283414c8abd9d72303a5cfba 100644 (file)
@@ -1443,6 +1443,7 @@ OBJS = \
        store-motion.o \
        streamer-hooks.o \
        stringpool.o \
+       substring-locations.o \
        target-globals.o \
        targhooks.o \
        timevar.o \
index 5d642d71ecee9c20deb4bf164188930c5f74891a..a3902f3027a844165eeb04c46477dabdc05ccee6 100644 (file)
@@ -1,3 +1,18 @@
+2016-09-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-common.c (get_cpp_ttype_from_string_type): Handle being passed
+       a POINTER_TYPE.
+       (substring_loc::get_location): Move to substring-locations.c,
+       keeping implementation as...
+       (c_get_substring_location): New function, from the above, reworked
+       to use accessors rather than member lookup.
+       * c-common.h (class substring_loc): Move to substring-locations.h,
+       replacing with a forward decl.
+       (c_get_substring_location): New decl.
+       * c-format.c: Include "substring-locations.h".
+       (format_warning_va): Move to substring-locations.c.
+       (format_warning_at_substring): Likewise.
+
 2016-09-06 Martin Sebor  <msebor@redhat.com>
 
        PR c/77336
index de9f881e2362c835eb61ed7a2156e46800fdfbf4..656f639767db5e5d4b75af20f8f122949a368a77 100644 (file)
@@ -1122,6 +1122,9 @@ static enum cpp_ttype
 get_cpp_ttype_from_string_type (tree string_type)
 {
   gcc_assert (string_type);
+  if (TREE_CODE (string_type) == POINTER_TYPE)
+    string_type = TREE_TYPE (string_type);
+
   if (TREE_CODE (string_type) != ARRAY_TYPE)
     return CPP_OTHER;
 
@@ -1148,23 +1151,23 @@ get_cpp_ttype_from_string_type (tree string_type)
 
 GTY(()) string_concat_db *g_string_concat_db;
 
-/* Attempt to determine the source location of the substring.
-   If successful, return NULL and write the source location to *OUT_LOC.
-   Otherwise return an error message.  Error messages are intended
-   for GCC developers (to help debugging) rather than for end-users.  */
+/* Implementation of LANG_HOOKS_GET_SUBSTRING_LOCATION.  */
 
 const char *
-substring_loc::get_location (location_t *out_loc) const
+c_get_substring_location (const substring_loc &substr_loc,
+                         location_t *out_loc)
 {
-  gcc_assert (out_loc);
-
-  enum cpp_ttype tok_type = get_cpp_ttype_from_string_type (m_string_type);
+  enum cpp_ttype tok_type
+    = get_cpp_ttype_from_string_type (substr_loc.get_string_type ());
   if (tok_type == CPP_OTHER)
     return "unrecognized string type";
 
   return get_source_location_for_substring (parse_in, g_string_concat_db,
-                                           m_fmt_string_loc, tok_type,
-                                           m_caret_idx, m_start_idx, m_end_idx,
+                                           substr_loc.get_fmt_string_loc (),
+                                           tok_type,
+                                           substr_loc.get_caret_idx (),
+                                           substr_loc.get_start_idx (),
+                                           substr_loc.get_end_idx (),
                                            out_loc);
 }
 
index 42ce9698bdbdf2aabbbf95f0c2c5a18f0e66f51c..1d923c90de41aeb3d5308393278c4b6f049fdd1b 100644 (file)
@@ -1132,35 +1132,9 @@ extern const char *cb_get_suggestion (cpp_reader *, const char *,
 
 extern GTY(()) string_concat_db *g_string_concat_db;
 
-/* libcpp can calculate location information about a range of characters
-   within a string literal, but doing so is non-trivial.
-
-   This class encapsulates such a source location, so that it can be
-   passed around (e.g. within c-format.c).  It is effectively a deferred
-   call into libcpp.  If needed by a diagnostic, the actual source_range
-   can be calculated by calling the get_range method.  */
-
-class substring_loc
-{
- public:
-  substring_loc (location_t fmt_string_loc, tree string_type,
-                int caret_idx, int start_idx, int end_idx)
-  : m_fmt_string_loc (fmt_string_loc), m_string_type (string_type),
-    m_caret_idx (caret_idx), m_start_idx (start_idx), m_end_idx (end_idx) {}
-
-  void set_caret_index (int caret_idx) { m_caret_idx = caret_idx; }
-
-  const char *get_location (location_t *out_loc) const;
-
-  location_t get_fmt_string_loc () const { return m_fmt_string_loc; }
-
- private:
-  location_t m_fmt_string_loc;
-  tree m_string_type;
-  int m_caret_idx;
-  int m_start_idx;
-  int m_end_idx;
-};
+class substring_loc;
+extern const char *c_get_substring_location (const substring_loc &substr_loc,
+                                            location_t *out_loc);
 
 /* In c-gimplify.c  */
 extern void c_genericize (tree);
index 413962eec21086d9eb0b719360124baa87a8512a..09d514ec594c00d4fa82e4ae9f3011189eb204f4 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-format.h"
 #include "diagnostic.h"
+#include "substring-locations.h"
 #include "selftest.h"
 #include "builtins.h"
 
@@ -68,162 +69,6 @@ static int first_target_format_type;
 static const char *format_name (int format_num);
 static int format_flags (int format_num);
 
-/* Emit a warning governed by option OPT, using GMSGID as the format
-   string and AP as its arguments.
-
-   Attempt to obtain precise location information within a string
-   literal from FMT_LOC.
-
-   Case 1: if substring location is available, and is within the range of
-   the format string itself, the primary location of the
-   diagnostic is the substring range obtained from FMT_LOC, with the
-   caret at the *end* of the substring range.
-
-   For example:
-
-     test.c:90:10: warning: problem with '%i' here [-Wformat=]
-     printf ("hello %i", msg);
-                    ~^
-
-   Case 2: if the substring location is available, but is not within
-   the range of the format string, the primary location is that of the
-   format string, and an note is emitted showing the substring location.
-
-   For example:
-     test.c:90:10: warning: problem with '%i' here [-Wformat=]
-     printf("hello " INT_FMT " world", msg);
-            ^~~~~~~~~~~~~~~~~~~~~~~~~
-     test.c:19: note: format string is defined here
-     #define INT_FMT "%i"
-                      ~^
-
-   Case 3: if precise substring information is unavailable, the primary
-   location is that of the whole string passed to FMT_LOC's constructor.
-   For example:
-
-     test.c:90:10: warning: problem with '%i' here [-Wformat=]
-     printf(fmt, msg);
-            ^~~
-
-   For each of cases 1-3, if param_range is non-NULL, then it is used
-   as a secondary range within the warning.  For example, here it
-   is used with case 1:
-
-     test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
-     printf ("foo %s bar", long_i + long_j);
-                  ~^       ~~~~~~~~~~~~~~~
-
-   and here with case 2:
-
-     test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
-     printf ("foo " STR_FMT " bar", long_i + long_j);
-             ^~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~
-     test.c:89:16: note: format string is defined here
-     #define STR_FMT "%s"
-                      ~^
-
-   and with case 3:
-
-     test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
-     printf(fmt, msg);
-            ^~~  ~~~
-
-   If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide
-   a fix-it hint, suggesting that it should replace the text within the
-   substring range.  For example:
-
-     test.c:90:10: warning: problem with '%i' here [-Wformat=]
-     printf ("hello %i", msg);
-                    ~^
-                    %s
-
-   Return true if a warning was emitted, false otherwise.  */
-
-ATTRIBUTE_GCC_DIAG (5,0)
-static bool
-format_warning_va (const substring_loc &fmt_loc, source_range *param_range,
-                  const char *corrected_substring,
-                  int opt, const char *gmsgid, va_list *ap)
-{
-  bool substring_within_range = false;
-  location_t primary_loc;
-  location_t fmt_substring_loc = UNKNOWN_LOCATION;
-  source_range fmt_loc_range
-    = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ());
-  const char *err = fmt_loc.get_location (&fmt_substring_loc);
-  source_range fmt_substring_range
-    = get_range_from_loc (line_table, fmt_substring_loc);
-  if (err)
-    /* Case 3: unable to get substring location.  */
-    primary_loc = fmt_loc.get_fmt_string_loc ();
-  else
-    {
-      if (fmt_substring_range.m_start >= fmt_loc_range.m_start
-         && fmt_substring_range.m_finish <= fmt_loc_range.m_finish)
-       /* Case 1.  */
-       {
-         substring_within_range = true;
-         primary_loc = fmt_substring_loc;
-       }
-      else
-       /* Case 2.  */
-       {
-         substring_within_range = false;
-         primary_loc = fmt_loc.get_fmt_string_loc ();
-       }
-    }
-
-  rich_location richloc (line_table, primary_loc);
-
-  if (param_range)
-    {
-      location_t param_loc = make_location (param_range->m_start,
-                                           param_range->m_start,
-                                           param_range->m_finish);
-      richloc.add_range (param_loc, false);
-    }
-
-  if (!err && corrected_substring && substring_within_range)
-    richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
-
-  diagnostic_info diagnostic;
-  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
-  diagnostic.option_index = opt;
-  bool warned = report_diagnostic (&diagnostic);
-
-  if (!err && fmt_substring_loc && !substring_within_range)
-    /* Case 2.  */
-    if (warned)
-      {
-       rich_location substring_richloc (line_table, fmt_substring_loc);
-       if (corrected_substring)
-         substring_richloc.add_fixit_replace (fmt_substring_range,
-                                              corrected_substring);
-       inform_at_rich_loc (&substring_richloc,
-                           "format string is defined here");
-      }
-
-  return warned;
-}
-
-/* Variadic call to format_warning_va.  */
-
-ATTRIBUTE_GCC_DIAG (5,0)
-static bool
-format_warning_at_substring (const substring_loc &fmt_loc,
-                            source_range *param_range,
-                            const char *corrected_substring,
-                            int opt, const char *gmsgid, ...)
-{
-  va_list ap;
-  va_start (ap, gmsgid);
-  bool warned = format_warning_va (fmt_loc, param_range, corrected_substring,
-                                  opt, gmsgid, &ap);
-  va_end (ap);
-
-  return warned;
-}
-
 /* Emit a warning as per format_warning_va, but construct the substring_loc
    for the character at offset (CHAR_IDX - 1) within a string constant
    FORMAT_STRING_CST at FMT_STRING_LOC.  */
index 7fee5b8556a6517891d91f0338b6d842c1265d7d..a647263841123d5a21735480641049e73176896e 100644 (file)
@@ -1,3 +1,8 @@
+2016-09-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-lang.c (LANG_HOOKS_GET_SUBSTRING_LOCATION): Use
+       c_get_substring_location for this new langhook.
+
 2016-09-02  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/65467
index b26be6ad92cf60f6dd6b3464bbe6cc8656b045be..b4096d064ee05c66d243855edb21be3e43f49ec9 100644 (file)
@@ -43,6 +43,9 @@ enum c_language_kind c_language = clk_c;
 #define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_c_tests
 #endif /* #if CHECKING_P */
 
+#undef LANG_HOOKS_GET_SUBSTRING_LOCATION
+#define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location
+
 /* Each front end provides its own lang hook initializer.  */
 struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 
index 10d910c960d4cf12af4dc2654c7d4f4c73b9415a..cf5f91da1252873580df2d5dc67a7caad2f56b46 100644 (file)
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "hooks.h"
 
 struct diagnostic_info;
+class substring_loc;
 
 /* Note to creators of new hooks:
 
@@ -81,6 +82,9 @@ extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
                                               tree);
 extern bool lhd_omp_mappable_type (tree);
 
+extern const char *lhd_get_substring_location (const substring_loc &,
+                                              location_t *out_loc);
+
 #define LANG_HOOKS_NAME                        "GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE     sizeof (struct lang_identifier)
 #define LANG_HOOKS_INIT                        hook_bool_void_false
@@ -121,6 +125,7 @@ extern bool lhd_omp_mappable_type (tree);
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP      false
 #define LANG_HOOKS_DEEP_UNSHARING      false
 #define LANG_HOOKS_RUN_LANG_SELFTESTS   lhd_do_nothing
+#define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
 
 /* Attribute hooks.  */
 #define LANG_HOOKS_ATTRIBUTE_TABLE             NULL
@@ -323,7 +328,8 @@ extern void lhd_end_section (void);
   LANG_HOOKS_BLOCK_MAY_FALLTHRU, \
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
   LANG_HOOKS_DEEP_UNSHARING, \
-  LANG_HOOKS_RUN_LANG_SELFTESTS \
+  LANG_HOOKS_RUN_LANG_SELFTESTS, \
+  LANG_HOOKS_GET_SUBSTRING_LOCATION \
 }
 
 #endif /* GCC_LANG_HOOKS_DEF_H */
index 3256a9d10cc18d44f153b23c63b46635772e878e..538d9f9271084d9b1f407a21dabb145ee73fde89 100644 (file)
@@ -693,6 +693,14 @@ lhd_enum_underlying_base_type (const_tree enum_type)
                                         TYPE_UNSIGNED (enum_type));
 }
 
+/* Default implementation of LANG_HOOKS_GET_SUBSTRING_LOCATION.  */
+
+const char *
+lhd_get_substring_location (const substring_loc &, location_t *)
+{
+  return "unimplemented";
+}
+
 /* Returns true if the current lang_hooks represents the GNU C frontend.  */
 
 bool
index 44c258e963808c59a999a796b47c70f1672e2397..c109c8c7e150c48e385d585ded155fd54d294f25 100644 (file)
@@ -34,6 +34,8 @@ typedef void (*lang_print_tree_hook) (FILE *, tree, int indent);
 enum classify_record
   { RECORD_IS_STRUCT, RECORD_IS_CLASS, RECORD_IS_INTERFACE };
 
+class substring_loc;
+
 /* The following hooks are documented in langhooks.c.  Must not be
    NULL.  */
 
@@ -513,6 +515,13 @@ struct lang_hooks
   /* Run all lang-specific selftests.  */
   void (*run_lang_selftests) (void);
 
+  /* Attempt to determine the source location of the substring.
+     If successful, return NULL and write the source location to *OUT_LOC.
+     Otherwise return an error message.  Error messages are intended
+     for GCC developers (to help debugging) rather than for end-users.  */
+  const char *(*get_substring_location) (const substring_loc &,
+                                        location_t *out_loc);
+
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
      and langhooks.c accordingly.  */
 };
diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
new file mode 100644 (file)
index 0000000..60bf1b0
--- /dev/null
@@ -0,0 +1,195 @@
+/* Source locations within string literals.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "substring-locations.h"
+
+/* Emit a warning governed by option OPT, using GMSGID as the format
+   string and AP as its arguments.
+
+   Attempt to obtain precise location information within a string
+   literal from FMT_LOC.
+
+   Case 1: if substring location is available, and is within the range of
+   the format string itself, the primary location of the
+   diagnostic is the substring range obtained from FMT_LOC, with the
+   caret at the *end* of the substring range.
+
+   For example:
+
+     test.c:90:10: warning: problem with '%i' here [-Wformat=]
+     printf ("hello %i", msg);
+                    ~^
+
+   Case 2: if the substring location is available, but is not within
+   the range of the format string, the primary location is that of the
+   format string, and an note is emitted showing the substring location.
+
+   For example:
+     test.c:90:10: warning: problem with '%i' here [-Wformat=]
+     printf("hello " INT_FMT " world", msg);
+            ^~~~~~~~~~~~~~~~~~~~~~~~~
+     test.c:19: note: format string is defined here
+     #define INT_FMT "%i"
+                      ~^
+
+   Case 3: if precise substring information is unavailable, the primary
+   location is that of the whole string passed to FMT_LOC's constructor.
+   For example:
+
+     test.c:90:10: warning: problem with '%i' here [-Wformat=]
+     printf(fmt, msg);
+            ^~~
+
+   For each of cases 1-3, if param_range is non-NULL, then it is used
+   as a secondary range within the warning.  For example, here it
+   is used with case 1:
+
+     test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
+     printf ("foo %s bar", long_i + long_j);
+                  ~^       ~~~~~~~~~~~~~~~
+
+   and here with case 2:
+
+     test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
+     printf ("foo " STR_FMT " bar", long_i + long_j);
+             ^~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~
+     test.c:89:16: note: format string is defined here
+     #define STR_FMT "%s"
+                      ~^
+
+   and with case 3:
+
+     test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
+     printf(fmt, msg);
+            ^~~  ~~~
+
+   If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide
+   a fix-it hint, suggesting that it should replace the text within the
+   substring range.  For example:
+
+     test.c:90:10: warning: problem with '%i' here [-Wformat=]
+     printf ("hello %i", msg);
+                    ~^
+                    %s
+
+   Return true if a warning was emitted, false otherwise.  */
+
+ATTRIBUTE_GCC_DIAG (5,0)
+bool
+format_warning_va (const substring_loc &fmt_loc,
+                  const source_range *param_range,
+                  const char *corrected_substring,
+                  int opt, const char *gmsgid, va_list *ap)
+{
+  bool substring_within_range = false;
+  location_t primary_loc;
+  location_t fmt_substring_loc = UNKNOWN_LOCATION;
+  source_range fmt_loc_range
+    = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ());
+  const char *err = fmt_loc.get_location (&fmt_substring_loc);
+  source_range fmt_substring_range
+    = get_range_from_loc (line_table, fmt_substring_loc);
+  if (err)
+    /* Case 3: unable to get substring location.  */
+    primary_loc = fmt_loc.get_fmt_string_loc ();
+  else
+    {
+      if (fmt_substring_range.m_start >= fmt_loc_range.m_start
+         && fmt_substring_range.m_finish <= fmt_loc_range.m_finish)
+       /* Case 1.  */
+       {
+         substring_within_range = true;
+         primary_loc = fmt_substring_loc;
+       }
+      else
+       /* Case 2.  */
+       {
+         substring_within_range = false;
+         primary_loc = fmt_loc.get_fmt_string_loc ();
+       }
+    }
+
+  rich_location richloc (line_table, primary_loc);
+
+  if (param_range)
+    {
+      location_t param_loc = make_location (param_range->m_start,
+                                           param_range->m_start,
+                                           param_range->m_finish);
+      richloc.add_range (param_loc, false);
+    }
+
+  if (!err && corrected_substring && substring_within_range)
+    richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
+
+  diagnostic_info diagnostic;
+  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
+  diagnostic.option_index = opt;
+  bool warned = report_diagnostic (&diagnostic);
+
+  if (!err && fmt_substring_loc && !substring_within_range)
+    /* Case 2.  */
+    if (warned)
+      {
+       rich_location substring_richloc (line_table, fmt_substring_loc);
+       if (corrected_substring)
+         substring_richloc.add_fixit_replace (fmt_substring_range,
+                                              corrected_substring);
+       inform_at_rich_loc (&substring_richloc,
+                           "format string is defined here");
+      }
+
+  return warned;
+}
+
+/* Variadic call to format_warning_va.  */
+
+bool
+format_warning_at_substring (const substring_loc &fmt_loc,
+                            const source_range *param_range,
+                            const char *corrected_substring,
+                            int opt, const char *gmsgid, ...)
+{
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool warned = format_warning_va (fmt_loc, param_range, corrected_substring,
+                                  opt, gmsgid, &ap);
+  va_end (ap);
+
+  return warned;
+}
+
+/* Attempt to determine the source location of the substring.
+   If successful, return NULL and write the source location to *OUT_LOC.
+   Otherwise return an error message.  Error messages are intended
+   for GCC developers (to help debugging) rather than for end-users.  */
+
+const char *
+substring_loc::get_location (location_t *out_loc) const
+{
+  gcc_assert (out_loc);
+  return lang_hooks.get_substring_location (*this, out_loc);
+}
index f839c74563550b68e45243738f1d1b67033052b8..f8788c9b3c4d8fc6c9efe70dce6e16911676b98b 100644 (file)
@@ -20,6 +20,77 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_SUBSTRING_LOCATIONS_H
 #define GCC_SUBSTRING_LOCATIONS_H
 
+/* The substring_loc class encapsulates information on the source location
+   of a range of characters within a STRING_CST.
+
+   If needed by a diagnostic, the actual location_t of the substring_loc
+   can be calculated by calling its get_location method.  This calls a
+   langhook, since this is inherently frontend-specific.  For the C family
+   of frontends, it calls back into libcpp to reparse the strings.  This
+   gets the location information "on demand", rather than storing the
+   location information in the initial lex for every string.  Thus the
+   substring_loc can also be thought of as a deferred call into libcpp,
+   to allow the non-trivial work of reparsing the string to be delayed
+   until we actually need it (to emit a diagnostic for a particular range
+   of characters).
+
+   substring_loc::get_location returns NULL if it succeeds, or an
+   error message if it fails.  Error messages are intended for GCC
+   developers (to help debugging) rather than for end-users.
+
+   The easiest way to use a substring_loc is via the format_warning_* APIs,
+   which gracefully handle failure of substring_loc::get_location by using
+   the location of the string as a whole if substring-information is
+   unavailable.  */
+
+class substring_loc
+{
+ public:
+  /* Constructor.  FMT_STRING_LOC is the location of the string as
+     a whole.  STRING_TYPE is the type of the string.  It should be an
+     ARRAY_TYPE of INTEGER_TYPE, or a POINTER_TYPE to such an ARRAY_TYPE.
+     CARET_IDX, START_IDX, and END_IDX are offsets from the start
+     of the string data.  */
+  substring_loc (location_t fmt_string_loc, tree string_type,
+                int caret_idx, int start_idx, int end_idx)
+  : m_fmt_string_loc (fmt_string_loc), m_string_type (string_type),
+    m_caret_idx (caret_idx), m_start_idx (start_idx), m_end_idx (end_idx) {}
+
+  void set_caret_index (int caret_idx) { m_caret_idx = caret_idx; }
+
+  const char *get_location (location_t *out_loc) const;
+
+  location_t get_fmt_string_loc () const { return m_fmt_string_loc; }
+  tree get_string_type () const { return m_string_type; }
+  int get_caret_idx () const { return m_caret_idx; }
+  int get_start_idx () const { return m_start_idx; }
+  int get_end_idx () const { return m_end_idx; }
+
+ private:
+  location_t m_fmt_string_loc;
+  tree m_string_type;
+  int m_caret_idx;
+  int m_start_idx;
+  int m_end_idx;
+};
+
+/* Functions for emitting a warning about a format string.  */
+
+extern bool format_warning_va (const substring_loc &fmt_loc,
+                              const source_range *param_range,
+                              const char *corrected_substring,
+                              int opt, const char *gmsgid, va_list *ap)
+  ATTRIBUTE_GCC_DIAG (5,0);
+
+extern bool format_warning_at_substring (const substring_loc &fmt_loc,
+                                        const source_range *param_range,
+                                        const char *corrected_substring,
+                                        int opt, const char *gmsgid, ...)
+  ATTRIBUTE_GCC_DIAG (5,0);
+
+/* Implementation detail, for use when implementing
+   LANG_HOOKS_GET_SUBSTRING_LOCATION.  */
+
 extern const char *get_source_location_for_substring (cpp_reader *pfile,
                                                      string_concat_db *concats,
                                                      location_t strloc,
index cfe3a081d372516d78b6548a15525f0fa2f1fe12..2867c1ec27f159ffab9e107dc6f1653311e0324e 100644 (file)
@@ -1,3 +1,8 @@
+2016-09-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcc.dg/plugin/diagnostic_plugin_test_string_literals.c: Include
+       "substring-locations.h".
+
 2016-09-07  Richard Biener  <rguenther@suse.de>
 
        PR c/77450
index dff999c3aa96e9675da5c5ae30f352b7e6aa4729..99a504dc541566cd003f6f9295f0b9e9338e5d8a 100644 (file)
@@ -33,6 +33,7 @@
 #include "print-tree.h"
 #include "cpplib.h"
 #include "c-family/c-pragma.h"
+#include "substring-locations.h"
 
 int plugin_is_GPL_compatible;