diff options
author | Manuel López-Ibáñez <manu@gcc.gnu.org> | 2015-05-21 06:49:38 +0000 |
---|---|---|
committer | Manuel López-Ibáñez <manu@gcc.gnu.org> | 2015-05-21 06:49:38 +0000 |
commit | 0fee2ac2882790ca549b1c5504f7fa1e59b25a39 (patch) | |
tree | 339d4f9e9dc8f2baacaec5f92a172caf24d16c36 /gcc/c-family/c-format.c | |
parent | a4f238b6d7ecee86b9c0a664b44add65058b0a91 (diff) | |
download | gcc-0fee2ac2882790ca549b1c5504f7fa1e59b25a39.tar.gz |
re PR c/52952 (Wformat location info is bad (wrong column number))
gcc/testsuite/ChangeLog:
2015-05-21 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/52952
* gcc.dg/redecl-4.c: Update column numbers.
* gcc.dg/format/bitfld-1.c: Likewise.
* gcc.dg/format/attr-2.c: Likewise.
* gcc.dg/format/attr-6.c: Likewise.
* gcc.dg/format/attr-7.c (baz): Likewise.
* gcc.dg/format/asm_fprintf-1.c: Likewise.
* gcc.dg/format/attr-4.c: Likewise.
* gcc.dg/format/branch-1.c: Likewise.
* gcc.dg/format/c90-printf-1.c: Likewise. Add tests for column
locations within strings with embedded escape sequences.
gcc/c-family/ChangeLog:
2015-05-21 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/52952
* c-format.c (location_column_from_byte_offset): New.
(location_from_offset): New.
(struct format_wanted_type): Add offset_loc field.
(check_format_info): Move handling of location for extra arguments
closer to the point of warning.
(check_format_info_main): Pass the result of location_from_offset
to warning_at.
(format_type_warning): Pass the result of location_from_offset
to warning_at.
From-SVN: r223470
Diffstat (limited to 'gcc/c-family/c-format.c')
-rw-r--r-- | gcc/c-family/c-format.c | 156 |
1 files changed, 136 insertions, 20 deletions
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index 9d03ff03834..145bbfd393f 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -78,6 +78,78 @@ static int first_target_format_type; static const char *format_name (int format_num); static int format_flags (int format_num); +/* Given a string S of length LINE_WIDTH, find the visual column + corresponding to OFFSET bytes. */ + +static unsigned int +location_column_from_byte_offset (const char *s, int line_width, + unsigned int offset) +{ + const char * c = s; + if (*c != '"') + return 0; + + c++, offset--; + while (offset > 0) + { + if (c - s >= line_width) + return 0; + + switch (*c) + { + case '\\': + c++; + if (c - s >= line_width) + return 0; + switch (*c) + { + case '\\': case '\'': case '"': case '?': + case '(': case '{': case '[': case '%': + case 'a': case 'b': case 'f': case 'n': + case 'r': case 't': case 'v': + case 'e': case 'E': + c++, offset--; + break; + + default: + return 0; + } + break; + + case '"': + /* We found the end of the string too early. */ + return 0; + + default: + c++, offset--; + break; + } + } + return c - s; +} + +/* Return a location that encodes the same location as LOC but shifted + by OFFSET bytes. */ + +static location_t +location_from_offset (location_t loc, int offset) +{ + gcc_checking_assert (offset >= 0); + if (linemap_location_from_macro_expansion_p (line_table, loc) + || offset < 0) + return loc; + + expanded_location s = expand_location_to_spelling_point (loc); + int line_width; + const char *line = location_get_source_line (s, &line_width); + line += s.column - 1 ; + line_width -= s.column - 1; + unsigned int column = + location_column_from_byte_offset (line, line_width, (unsigned) offset); + + return linemap_position_for_loc_and_offset (line_table, loc, column); +} + /* Check that we have a pointer to a string suitable for use as a format. The default is to check for a char type. For objective-c dialects, this is extended to include references to string @@ -390,6 +462,9 @@ typedef struct format_wanted_type tree param; /* The argument number of that parameter. */ int arg_num; + /* The offset location of this argument with respect to the format + string location. */ + unsigned int offset_loc; /* The next type to check for this format conversion, or NULL if none. */ struct format_wanted_type *next; } format_wanted_type; @@ -1358,8 +1433,6 @@ check_format_info (function_format_info *info, tree params) format_tree, arg_num); location_t loc = format_ctx.res->format_string_loc; - if (res.extra_arg_loc == UNKNOWN_LOCATION) - res.extra_arg_loc = loc; if (res.number_non_literal > 0) { @@ -1405,8 +1478,12 @@ check_format_info (function_format_info *info, tree params) case of extra format arguments. */ if (res.number_extra_args > 0 && res.number_non_literal == 0 && res.number_other == 0) - warning_at (res.extra_arg_loc, OPT_Wformat_extra_args, - "too many arguments for format"); + { + if (res.extra_arg_loc == UNKNOWN_LOCATION) + res.extra_arg_loc = loc; + warning_at (res.extra_arg_loc, OPT_Wformat_extra_args, + "too many arguments for format"); + } if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 && res.number_other == 0) warning_at (loc, OPT_Wformat_extra_args, "unused arguments in $-style format"); @@ -1682,7 +1759,9 @@ check_format_info_main (format_check_results *res, continue; if (*format_chars == 0) { - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "spurious trailing %<%%%> in format"); continue; } @@ -1727,7 +1806,10 @@ check_format_info_main (format_check_results *res, *format_chars, NULL); if (strchr (flag_chars, *format_chars) != 0) { - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars + 1 + - orig_format_chars), + OPT_Wformat_, "repeated %s in format", _(s->name)); } else @@ -1807,6 +1889,8 @@ check_format_info_main (format_check_results *res, width_wanted_type.format_length = 1; width_wanted_type.param = cur_param; width_wanted_type.arg_num = arg_num; + width_wanted_type.offset_loc = + format_chars - orig_format_chars; width_wanted_type.next = NULL; if (last_wanted_type != 0) last_wanted_type->next = &width_wanted_type; @@ -1849,7 +1933,9 @@ check_format_info_main (format_check_results *res, flag_chars[i++] = fki->left_precision_char; flag_chars[i] = 0; if (!ISDIGIT (*format_chars)) - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "empty left precision in %s format", fki->name); while (ISDIGIT (*format_chars)) ++format_chars; @@ -1914,6 +2000,8 @@ check_format_info_main (format_check_results *res, precision_wanted_type.format_start = format_chars - 2; precision_wanted_type.format_length = 2; precision_wanted_type.arg_num = arg_num; + precision_wanted_type.offset_loc = + format_chars - orig_format_chars; precision_wanted_type.next = NULL; if (last_wanted_type != 0) last_wanted_type->next = &precision_wanted_type; @@ -1926,7 +2014,9 @@ check_format_info_main (format_check_results *res, { if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) && !ISDIGIT (*format_chars)) - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "empty precision in %s format", fki->name); while (ISDIGIT (*format_chars)) ++format_chars; @@ -2012,7 +2102,10 @@ check_format_info_main (format_check_results *res, { const format_flag_spec *s = get_flag_spec (flag_specs, *format_chars, NULL); - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars + - orig_format_chars), + OPT_Wformat_, "repeated %s in format", _(s->name)); } else @@ -2030,7 +2123,9 @@ check_format_info_main (format_check_results *res, || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) && format_char == '%')) { - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "conversion lacks type at end of format"); continue; } @@ -2042,11 +2137,15 @@ check_format_info_main (format_check_results *res, if (fci->format_chars == 0) { if (ISGRAPH (format_char)) - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "unknown conversion type character %qc in format", format_char); else - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "unknown conversion type character 0x%x in format", format_char); continue; @@ -2054,7 +2153,9 @@ check_format_info_main (format_check_results *res, if (pedantic) { if (ADJ_STD (fci->std) > C_STD_VER) - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "%s does not support the %<%%%c%> %s format", C_STD_NAME (fci->std), format_char, fki->name); } @@ -2071,8 +2172,10 @@ check_format_info_main (format_check_results *res, continue; if (strchr (fci->flag_chars, flag_chars[i]) == 0) { - warning_at (format_string_loc, - OPT_Wformat_, "%s used with %<%%%c%> %s format", + warning_at (location_from_offset (format_string_loc, + format_chars + - orig_format_chars), + OPT_Wformat_, "%s used with %<%%%c%> %s format", _(s->name), format_char, fki->name); d++; continue; @@ -2186,7 +2289,9 @@ check_format_info_main (format_check_results *res, ++format_chars; if (*format_chars != ']') /* The end of the format string was reached. */ - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "no closing %<]%> for %<%%[%> format"); } @@ -2200,8 +2305,11 @@ check_format_info_main (format_check_results *res, wanted_type_std = fci->types[length_chars_val].std; if (wanted_type == 0) { - warning_at (format_string_loc, OPT_Wformat_, - "use of %qs length modifier with %qc type character", + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, + "use of %qs length modifier with %qc type character" + " has either no effect or undefined behavior", length_chars, format_char); /* Heuristic: skip one argument when an invalid length/type combination is encountered. */ @@ -2218,7 +2326,9 @@ check_format_info_main (format_check_results *res, && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) { if (ADJ_STD (wanted_type_std) > C_STD_VER) - warning_at (format_string_loc, OPT_Wformat_, + warning_at (location_from_offset (format_string_loc, + format_chars - orig_format_chars), + OPT_Wformat_, "%s does not support the %<%%%s%c%> %s format", C_STD_NAME (wanted_type_std), length_chars, format_char, fki->name); @@ -2303,6 +2413,7 @@ check_format_info_main (format_check_results *res, wanted_type_ptr->arg_num = arg_num; wanted_type_ptr->format_start = format_start; wanted_type_ptr->format_length = format_chars - format_start; + wanted_type_ptr->offset_loc = format_chars - orig_format_chars; wanted_type_ptr->next = NULL; if (last_wanted_type != 0) last_wanted_type->next = wanted_type_ptr; @@ -2327,7 +2438,9 @@ check_format_info_main (format_check_results *res, } if (format_chars - orig_format_chars != format_length) - warning_at (format_string_loc, OPT_Wformat_contains_nul, + warning_at (location_from_offset (format_string_loc, + format_chars + 1 - orig_format_chars), + OPT_Wformat_contains_nul, "embedded %<\\0%> in format"); if (info->first_arg_num != 0 && params != 0 && has_operand_number <= 0) @@ -2535,6 +2648,7 @@ format_type_warning (location_t loc, format_wanted_type *type, int format_length = type->format_length; int pointer_count = type->pointer_count; int arg_num = type->arg_num; + unsigned int offset_loc = type->offset_loc; char *p; /* If ARG_TYPE is a typedef with a misleading name (for example, @@ -2568,6 +2682,8 @@ format_type_warning (location_t loc, format_wanted_type *type, p[pointer_count + 1] = 0; } + loc = location_from_offset (loc, offset_loc); + if (wanted_type_name) { if (arg_type) |