mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-16 02:20:27 +08:00
Move class substring_loc from c-family into gcc
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
This commit is contained in:
parent
7100c1f253
commit
e5106e27fe
@ -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
|
||||
|
@ -1443,6 +1443,7 @@ OBJS = \
|
||||
store-motion.o \
|
||||
streamer-hooks.o \
|
||||
stringpool.o \
|
||||
substring-locations.o \
|
||||
target-globals.o \
|
||||
targhooks.o \
|
||||
timevar.o \
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
};
|
||||
|
195
gcc/substring-locations.c
Normal file
195
gcc/substring-locations.c
Normal file
@ -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);
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user