summaryrefslogtreecommitdiff
path: root/gcc/c-family/c-format.c
diff options
context:
space:
mode:
authorManuel López-Ibáñez <manu@gcc.gnu.org>2015-05-21 06:49:38 +0000
committerManuel López-Ibáñez <manu@gcc.gnu.org>2015-05-21 06:49:38 +0000
commit0fee2ac2882790ca549b1c5504f7fa1e59b25a39 (patch)
tree339d4f9e9dc8f2baacaec5f92a172caf24d16c36 /gcc/c-family/c-format.c
parenta4f238b6d7ecee86b9c0a664b44add65058b0a91 (diff)
downloadgcc-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.c156
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)