On Fri, 2016-09-02 at 16:55 -0600, Martin Sebor wrote: > I've successfully tested the patch below by incorporating it into > the -Wformat-length pass I've been working on. I'd like to submit > the latest and hopefully close to final version of my work for > review without duplicating this code and it might be helpful if > it was possible to build my latest patch without having to find > and install this one first. Could someone review and approve > David's patch?
I'm not quite sure what the boundaries of my "diagnostics"/"libcpp" maintainer rights are, and on whether I could self-approve this one - the addition of the langhook gave me pause. But https://gcc.gnu.org/ml/gcc-patches/2016-08/msg02161.html suggests that maybe I'm being too reticent, along with your positive feedback on the patch; it is all about diagnostics infrastructure, after all. So if no-one complains I'll commit it early next week. > Thanks > Martin > > On 08/25/2016 10:09 AM, David Malcolm wrote: > > This patch is intended to help Martin's new middle-end sprintf > > format > > warning. > > > > It moves most of the on-demand locations-within-strings > > code in c-family into gcc, into a new substring-locations.c file to > > go with substring-locations.h: class substring_loc, representing > > a source caret and source range within a STRING_CST, along with > > format_warning for handling emitting a warning relating to it. > > > > The actual work of reconstructing the source locations within > > a string seems inherently frontend-specific, so the patch > > introduces a > > langhook to do this, implementing it for C using the existing code > > (and thus hiding the details of string-concatenation as being > > specific to the c-family). Attempts to get substring location > > from other frontends will fail, and the format_warning_* calls > > handle such failures gracefully by simply using the location of > > the string as a whole for the warning. > > > > I've tested it with Martin's gimple-ssa-sprintf patch, and I'm able > > to > > emit carets and underlines in the correct places in C code from the > > middle end with this approach (patch to follow). > > > > Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. > > > > OK for trunk? > > > > 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: Include <cpplib.h>. > > (class substring_loc): Move class here from c-family/c > > -common.h. > > Add 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". > > --- > > gcc/Makefile.in | 1 + > > gcc/c-family/c-common.c | 23 +-- > > gcc/c-family/c-common.h | 32 +--- > > gcc/c-family/c-format.c | 157 +------- > > --------- > > gcc/c/c-lang.c | 3 + > > gcc/langhooks-def.h | 8 +- > > gcc/langhooks.c | 8 + > > gcc/langhooks.h | 9 + > > gcc/substring-locations.c | 195 > > +++++++++++++++++++++ > > gcc/substring-locations.h | 67 +++++++ > > .../diagnostic_plugin_test_string_literals.c | 1 + > > 11 files changed, 308 insertions(+), 196 deletions(-) > > create mode 100644 gcc/substring-locations.c > > > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > > index 1b7464b..769efcf 100644 > > --- a/gcc/Makefile.in > > +++ b/gcc/Makefile.in > > @@ -1444,6 +1444,7 @@ OBJS = \ > > store-motion.o \ > > streamer-hooks.o \ > > stringpool.o \ > > + substring-locations.o \ > > target-globals.o \ > > targhooks.o \ > > timevar.o \ > > diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c > > index 3feb910..f3e44c2 100644 > > --- a/gcc/c-family/c-common.c > > +++ b/gcc/c-family/c-common.c > > @@ -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); > > } > > > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > > index bc22baa..4470b4f 100644 > > --- a/gcc/c-family/c-common.h > > +++ b/gcc/c-family/c-common.h > > @@ -1131,35 +1131,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); > > diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c > > index d373819..ac40ac3 100644 > > --- a/gcc/c-family/c-format.c > > +++ b/gcc/c-family/c-format.c > > @@ -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" > > > > /* Handle attributes associated with format checking. */ > > @@ -67,162 +68,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. */ > > diff --git a/gcc/c/c-lang.c b/gcc/c/c-lang.c > > index b26be6a..b4096d0 100644 > > --- a/gcc/c/c-lang.c > > +++ b/gcc/c/c-lang.c > > @@ -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; > > > > diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h > > index 10d910c..cf5f91d 100644 > > --- a/gcc/langhooks-def.h > > +++ b/gcc/langhooks-def.h > > @@ -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_fal > > se > > @@ -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 */ > > diff --git a/gcc/langhooks.c b/gcc/langhooks.c > > index 3256a9d..538d9f9 100644 > > --- a/gcc/langhooks.c > > +++ b/gcc/langhooks.c > > @@ -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 > > diff --git a/gcc/langhooks.h b/gcc/langhooks.h > > index 44c258e..c109c8c 100644 > > --- a/gcc/langhooks.h > > +++ b/gcc/langhooks.h > > @@ -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 > > index 0000000..60bf1b0 > > --- /dev/null > > +++ b/gcc/substring-locations.c > > @@ -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); > > +} > > diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h > > index f839c74..bb0de4f 100644 > > --- a/gcc/substring-locations.h > > +++ b/gcc/substring-locations.h > > @@ -20,6 +20,73 @@ along with GCC; see the file COPYING3. If not > > see > > #ifndef GCC_SUBSTRING_LOCATIONS_H > > #define GCC_SUBSTRING_LOCATIONS_H > > > > +#include <cpplib.h> > > + > > +/* 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 location can be > > calculated by > > + calling the get_location method. This calls a langhook, since > > + this is inherently frontend-specific (it reparses the strings > > to > > + get the location information on-demand, rather than storing the > > + location information in the initial lex for every string). > > + > > + 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. */ > > + > > +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, > > diff --git > > a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literal > > s.c > > b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literal > > s.c > > index dff999c..99a504d 100644 > > --- > > a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literal > > s.c > > +++ > > b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literal > > s.c > > @@ -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; > > > > >