diff options
author | David Malcolm <dmalcolm@redhat.com> | 2018-10-05 19:02:17 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2018-10-05 19:02:17 +0000 |
commit | 0d48e8779c6a9ac88f5efd1b4a2d40f43ef75faf (patch) | |
tree | 153fa1d9d2a0ab481ba54a9f2f4ed6e311e2a5bf /gcc/cp/parser.c | |
parent | 1f58c814c0ade165b1691d79a79843ea31d6428b (diff) | |
download | gcc-0d48e8779c6a9ac88f5efd1b4a2d40f43ef75faf.zip gcc-0d48e8779c6a9ac88f5efd1b4a2d40f43ef75faf.tar.gz gcc-0d48e8779c6a9ac88f5efd1b4a2d40f43ef75faf.tar.bz2 |
Support string locations for C++ in -Wformat (PR c++/56856)
-Wformat in the C++ FE doesn't work as well as it could:
(a) it doesn't report precise locations within the string literal, and
(b) it doesn't underline arguments for those arguments !CAN_HAVE_LOCATION_P,
despite having location wrapper nodes.
For example:
Wformat-ranges.C:32:10: warning: format '%s' expects argument of type 'char*', but argument 2 has type 'int' [-Wformat=]
32 | printf("hello %s", 42);
| ^~~~~~~~~~
(a) is due to not wiring up the langhook for extracting substring
locations.
This patch uses the one in c-family; it also fixes string literal
parsing so that it records string concatenations (needed for
extracting substring locations from concatenated strings).
(b) is due to the call to maybe_constant_value here:
fargs[j] = maybe_constant_value (argarray[j]);
within build_over_call.
The patch fixes this by building a vec of location_t values when
calling check_function_arguments.
I attempted to eliminate the maybe_constant_value call here, but
it's needed by e.g. check_function_sentinel for detecting NULL,
and that code is in "c-family", so it can't simply call into
maybe_constant_value (which is in "cp").
With this patch, the output for the above example is improved to:
Wformat-ranges.C:32:18: warning: format '%s' expects argument of type 'char*', but argument 2 has type 'int' [-Wformat=]
32 | printf("hello %s", 42);
| ~^ ~~
| | |
| | int
| char*
| %d
gcc/cp/ChangeLog:
PR c++/56856
* call.c (build_over_call): Build a vec of locations of the
arguments before the call to maybe_constant_value, and pass to
check_function_arguments.
* cp-lang.c (LANG_HOOKS_GET_SUBSTRING_LOCATION): Define as
c_get_substring_location.
* parser.c (cp_parser_string_literal): Capture string
concatenation locations.
gcc/ChangeLog:
PR c++/56856
* input.c (expand_location_to_spelling_point): Add param "aspect"
and use rather than hardcoding LOCATION_ASPECT_CARET.
(get_substring_ranges_for_loc): Handle the case of a single token
within a macro expansion.
* input.h (expand_location_to_spelling_point): Add "aspect" param,
defaulting to LOCATION_ASPECT_CARET.
gcc/testsuite/ChangeLog:
PR c++/56856
* g++.dg/ext/builtin4.C: Set expected location for warning to the
correct location within the format string.
* g++.dg/plugin/plugin.exp (plugin_test_list): Add the plugin and
files for testing locations within string literal locations from
the C frontend.
* g++.dg/warn/Wformat-method.C: New test.
* g++.dg/warn/Wformat-pr71863.C: New test.
* g++.dg/warn/Wformat-ranges-c++11.C: New test.
* g++.dg/warn/Wformat-ranges.C: New test, based on
gcc.dg/format/diagnostic-ranges.c.
* gcc.dg/plugin/diagnostic-test-string-literals-1.c
(test_multitoken_macro): Generalize expected output to work with
both C and C++.
* gcc.dg/plugin/diagnostic-test-string-literals-2.c
(test_stringified_token_1): Likewise.
(test_stringified_token_3): Likewise.
From-SVN: r264887
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a17cc3f..032108a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4034,6 +4034,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, tree value; size_t count; struct obstack str_ob; + struct obstack loc_ob; cpp_string str, istr, *strs; cp_token *tok; enum cpp_ttype type, curr_type; @@ -4090,6 +4091,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, { location_t last_tok_loc = tok->location; gcc_obstack_init (&str_ob); + gcc_obstack_init (&loc_ob); count = 0; do @@ -4135,6 +4137,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, } obstack_grow (&str_ob, &str, sizeof (cpp_string)); + obstack_grow (&loc_ob, &tok->location, sizeof (location_t)); last_tok_loc = tok->location; @@ -4173,6 +4176,12 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, { value = build_string (istr.len, (const char *)istr.text); free (CONST_CAST (unsigned char *, istr.text)); + if (count > 1) + { + location_t *locs = (location_t *)obstack_finish (&loc_ob); + gcc_assert (g_string_concat_db); + g_string_concat_db->record_string_concatenation (count, locs); + } switch (type) { @@ -4209,7 +4218,10 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, value = error_mark_node; if (count > 1) - obstack_free (&str_ob, 0); + { + obstack_free (&str_ob, 0); + obstack_free (&loc_ob, 0); + } return cp_expr (value, loc); } |