Commit 26f6672d by Joseph Myers Committed by Joseph Myers

c-common.c (enum format_type): Add strfmon_format_type.

	* c-common.c (enum format_type): Add strfmon_format_type.
	(decl_attributes): Handle format attributes strfmon and
	__strfmon__.
	(FMT_FLAG_USE_DOLLAR, FMT_FLAG_ZERO_WIDTH_BAD,
	FMT_FLAG_EMPTY_PREC_OK): Define.
	(format_char_info): Update comment for flag_chars.
	(format_flag_spec): Add skip_next_char.
	(format_kind_info): Add left_precision_char.
	(printf_flag_specs, scanf_flag_specs, strftime_flag_specs,
	format_types): Update for these new structure members and flags.
	(time_char_table): Make const.
	(strfmon_length_specs, strfmon_flag_specs, strfmon_flag_pairs,
	monetary_char_table): New.
	(format_types): Add details of strfmon formats.
	(init_function_format_info): Create default attribute for strfmon.
	(check_format_info_main): Check the new flags.  Handle
	skip_next_char and left precision.
	* toplev.c (documented_lang_options): Update description of
	-Wformat.
	* extend.texi: Document strfmon format attributes.  Document
	attribute forms such as __printf__.  Clarify format_arg attribute
	documentation.
	* invoke.texi (-Wformat): Update for strfmon formats.

testsuite:
	* gcc.dg/format-strfmon-1.c: New test.

From-SVN: r38512
parent df7978d9
2000-12-28 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.c (enum format_type): Add strfmon_format_type.
(decl_attributes): Handle format attributes strfmon and
__strfmon__.
(FMT_FLAG_USE_DOLLAR, FMT_FLAG_ZERO_WIDTH_BAD,
FMT_FLAG_EMPTY_PREC_OK): Define.
(format_char_info): Update comment for flag_chars.
(format_flag_spec): Add skip_next_char.
(format_kind_info): Add left_precision_char.
(printf_flag_specs, scanf_flag_specs, strftime_flag_specs,
format_types): Update for these new structure members and flags.
(time_char_table): Make const.
(strfmon_length_specs, strfmon_flag_specs, strfmon_flag_pairs,
monetary_char_table): New.
(format_types): Add details of strfmon formats.
(init_function_format_info): Create default attribute for strfmon.
(check_format_info_main): Check the new flags. Handle
skip_next_char and left precision.
* toplev.c (documented_lang_options): Update description of
-Wformat.
* extend.texi: Document strfmon format attributes. Document
attribute forms such as __printf__. Clarify format_arg attribute
documentation.
* invoke.texi (-Wformat): Update for strfmon formats.
2000-12-28 Andreas Jaeger <aj@suse.de> 2000-12-28 Andreas Jaeger <aj@suse.de>
* expmed.c (store_bit_field): Fix last patch. * expmed.c (store_bit_field): Fix last patch.
......
...@@ -230,7 +230,7 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION, ...@@ -230,7 +230,7 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
A_NO_LIMIT_STACK, A_PURE}; A_NO_LIMIT_STACK, A_PURE};
enum format_type { printf_format_type, scanf_format_type, enum format_type { printf_format_type, scanf_format_type,
strftime_format_type }; strftime_format_type, strfmon_format_type };
static void add_attribute PARAMS ((enum attrs, const char *, static void add_attribute PARAMS ((enum attrs, const char *,
int, int, int)); int, int, int));
...@@ -955,6 +955,9 @@ decl_attributes (node, attributes, prefix_attributes) ...@@ -955,6 +955,9 @@ decl_attributes (node, attributes, prefix_attributes)
else if (!strcmp (p, "strftime") else if (!strcmp (p, "strftime")
|| !strcmp (p, "__strftime__")) || !strcmp (p, "__strftime__"))
format_type = strftime_format_type; format_type = strftime_format_type;
else if (!strcmp (p, "strfmon")
|| !strcmp (p, "__strfmon__"))
format_type = strfmon_format_type;
else else
{ {
warning ("`%s' is an unrecognized format function type", p); warning ("`%s' is an unrecognized format function type", p);
...@@ -1357,13 +1360,17 @@ enum ...@@ -1357,13 +1360,17 @@ enum
FMT_FLAG_FANCY_PERCENT_OK = 4, FMT_FLAG_FANCY_PERCENT_OK = 4,
/* With $ operand numbers, it is OK to reference the same argument more /* With $ operand numbers, it is OK to reference the same argument more
than once. */ than once. */
FMT_FLAG_DOLLAR_MULTIPLE = 8 FMT_FLAG_DOLLAR_MULTIPLE = 8,
/* This format type uses $ operand numbers (strfmon doesn't). */
FMT_FLAG_USE_DOLLAR = 16,
/* Zero width is bad in this type of format (scanf). */
FMT_FLAG_ZERO_WIDTH_BAD = 32,
/* Empty precision specification is OK in this type of format (printf). */
FMT_FLAG_EMPTY_PREC_OK = 64
/* Not included here: details of whether width or precision may occur /* Not included here: details of whether width or precision may occur
(controlled by width_char and precision_char); details of whether (controlled by width_char and precision_char); details of whether
'*' can be used for these (width_type and precision_type); details '*' can be used for these (width_type and precision_type); details
of whether length modifiers can occur (length_char_specs); details of whether length modifiers can occur (length_char_specs). */
of when $ operand numbers are allowed (always, for the formats
supported, if arguments are converted). */
}; };
...@@ -1415,7 +1422,8 @@ typedef struct ...@@ -1415,7 +1422,8 @@ typedef struct
/* Types accepted for each length modifier. */ /* Types accepted for each length modifier. */
format_type_detail types[FMT_LEN_MAX]; format_type_detail types[FMT_LEN_MAX];
/* List of other modifier characters allowed with these specifiers. /* List of other modifier characters allowed with these specifiers.
This lists flags, and additionally "w" for width, "p" for precision, This lists flags, and additionally "w" for width, "p" for precision
(right precision, for strfmon), "#" for left precision (strfmon),
"a" for scanf "a" allocation extension (not applicable in C99 mode), "a" for scanf "a" allocation extension (not applicable in C99 mode),
"*" for scanf suppression, and "E" and "O" for those strftime "*" for scanf suppression, and "E" and "O" for those strftime
modifiers. */ modifiers. */
...@@ -1447,6 +1455,9 @@ typedef struct ...@@ -1447,6 +1455,9 @@ typedef struct
the unpredicated one, for any pedantic warning. For example, 'o' the unpredicated one, for any pedantic warning. For example, 'o'
for strftime formats (meaning 'O' is an extension over C99). */ for strftime formats (meaning 'O' is an extension over C99). */
int predicate; int predicate;
/* Nonzero if the next character after this flag in the format should
be skipped ('=' in strfmon), zero otherwise. */
int skip_next_char;
/* The name to use for this flag in diagnostic messages. For example, /* The name to use for this flag in diagnostic messages. For example,
N_("`0' flag"), N_("field width"). */ N_("`0' flag"), N_("field width"). */
const char *name; const char *name;
...@@ -1497,7 +1508,11 @@ typedef struct ...@@ -1497,7 +1508,11 @@ typedef struct
int flags; int flags;
/* Flag character to treat a width as, or 0 if width not used. */ /* Flag character to treat a width as, or 0 if width not used. */
int width_char; int width_char;
/* Flag character to treat a precision as, or 0 if precision not used. */ /* Flag character to treat a left precision (strfmon) as,
or 0 if left precision not used. */
int left_precision_char;
/* Flag character to treat a precision (for strfmon, right precision) as,
or 0 if precision not used. */
int precision_char; int precision_char;
/* If a flag character has the effect of suppressing the conversion of /* If a flag character has the effect of suppressing the conversion of
an argument ('*' in scanf), that flag character, otherwise 0. */ an argument ('*' in scanf), that flag character, otherwise 0. */
...@@ -1579,19 +1594,28 @@ static const format_length_info scanf_length_specs[] = ...@@ -1579,19 +1594,28 @@ static const format_length_info scanf_length_specs[] =
}; };
/* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings
make no sense for a format type not part of any C standard version. */
static const format_length_info strfmon_length_specs[] =
{
/* A GNU extension. */
{ "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
{ NULL, 0, 0, NULL, 0, 0 }
};
static const format_flag_spec printf_flag_specs[] = static const format_flag_spec printf_flag_specs[] =
{ {
{ ' ', 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 }, { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 },
{ '+', 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 }, { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 },
{ '#', 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 }, { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 },
{ '0', 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 }, { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 },
{ '-', 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 }, { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 },
{ '\'', 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT }, { '\'', 0, 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT },
{ 'I', 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT }, { 'I', 0, 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT },
{ 'w', 0, N_("field width"), N_("field width in printf format"), STD_C89 }, { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, N_("precision"), N_("precision in printf format"), STD_C89 }, { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, NULL, NULL, 0 } { 0, 0, 0, NULL, NULL, 0 }
}; };
...@@ -1606,13 +1630,13 @@ static const format_flag_pair printf_flag_pairs[] = ...@@ -1606,13 +1630,13 @@ static const format_flag_pair printf_flag_pairs[] =
static const format_flag_spec scanf_flag_specs[] = static const format_flag_spec scanf_flag_specs[] =
{ {
{ '*', 0, N_("assignment suppression"), N_("assignment suppression"), STD_C89 }, { '*', 0, 0, N_("assignment suppression"), N_("assignment suppression"), STD_C89 },
{ 'a', 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT }, { 'a', 0, 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT },
{ 'w', 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
{ 'L', 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
{ '\'', 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT }, { '\'', 0, 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT },
{ 'I', 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT }, { 'I', 0, 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT },
{ 0, 0, NULL, NULL, 0 } { 0, 0, 0, NULL, NULL, 0 }
}; };
...@@ -1625,16 +1649,16 @@ static const format_flag_pair scanf_flag_pairs[] = ...@@ -1625,16 +1649,16 @@ static const format_flag_pair scanf_flag_pairs[] =
static const format_flag_spec strftime_flag_specs[] = static const format_flag_spec strftime_flag_specs[] =
{ {
{ '_', 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT }, { '_', 0, 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT },
{ '-', 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT }, { '-', 0, 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT },
{ '0', 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT }, { '0', 0, 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT },
{ '^', 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT }, { '^', 0, 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT },
{ '#', 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT }, { '#', 0, 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT },
{ 'w', 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
{ 'E', 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 }, { 'E', 0, 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 },
{ 'O', 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 }, { 'O', 0, 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 },
{ 'O', 'o', NULL, N_("the `O' modifier"), STD_EXT }, { 'O', 'o', 0, NULL, N_("the `O' modifier"), STD_EXT },
{ 0, 0, NULL, NULL, 0 } { 0, 0, 0, NULL, NULL, 0 }
}; };
...@@ -1649,6 +1673,28 @@ static const format_flag_pair strftime_flag_pairs[] = ...@@ -1649,6 +1673,28 @@ static const format_flag_pair strftime_flag_pairs[] =
}; };
static const format_flag_spec strfmon_flag_specs[] =
{
{ '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
{ '^', 0, 0, N_("`^' flag"), N_("the `^' strfmon flag"), STD_C89 },
{ '+', 0, 0, N_("`+' flag"), N_("the `+' strfmon flag"), STD_C89 },
{ '(', 0, 0, N_("`(' flag"), N_("the `(' strfmon flag"), STD_C89 },
{ '!', 0, 0, N_("`!' flag"), N_("the `!' strfmon flag"), STD_C89 },
{ '-', 0, 0, N_("`-' flag"), N_("the `-' strfmon flag"), STD_C89 },
{ 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
{ '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
{ 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, 0 }
};
static const format_flag_pair strfmon_flag_pairs[] =
{
{ '+', '(', 0, 0 },
{ 0, 0, 0, 0 }
};
#define T_I &integer_type_node #define T_I &integer_type_node
#define T89_I { STD_C89, NULL, T_I } #define T89_I { STD_C89, NULL, T_I }
#define T99_I { STD_C99, NULL, T_I } #define T99_I { STD_C99, NULL, T_I }
...@@ -1748,7 +1794,7 @@ static const format_char_info scan_char_table[] = ...@@ -1748,7 +1794,7 @@ static const format_char_info scan_char_table[] =
{ NULL, 0, 0, NOLENGTHS, NULL, NULL } { NULL, 0, 0, NOLENGTHS, NULL, NULL }
}; };
static format_char_info time_char_table[] = static const format_char_info time_char_table[] =
{ {
/* C89 conversion specifiers. */ /* C89 conversion specifiers. */
{ "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" }, { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" },
...@@ -1775,23 +1821,36 @@ static format_char_info time_char_table[] = ...@@ -1775,23 +1821,36 @@ static format_char_info time_char_table[] =
{ NULL, 0, 0, NOLENGTHS, NULL, NULL } { NULL, 0, 0, NOLENGTHS, NULL, NULL }
}; };
static const format_char_info monetary_char_table[] =
{
{ "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "" },
{ NULL, 0, 0, NOLENGTHS, NULL, NULL }
};
/* This must be in the same order as enum format_type. */ /* This must be in the same order as enum format_type. */
static const format_kind_info format_types[] = static const format_kind_info format_types[] =
{ {
{ "printf", printf_length_specs, print_char_table, " +#0-'I", NULL, { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL,
printf_flag_specs, printf_flag_pairs, printf_flag_specs, printf_flag_pairs,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE, 'w', 'p', 0, 'L', FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
'w', 0, 'p', 0, 'L',
&integer_type_node, &integer_type_node &integer_type_node, &integer_type_node
}, },
{ "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
scanf_flag_specs, scanf_flag_pairs, scanf_flag_specs, scanf_flag_pairs,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE, 'w', 0, '*', 'L', FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD,
'w', 0, 0, '*', 'L',
NULL, NULL NULL, NULL
}, },
{ "strftime", NULL, time_char_table, "_-0^#", "EO", { "strftime", NULL, time_char_table, "_-0^#", "EO",
strftime_flag_specs, strftime_flag_pairs, strftime_flag_specs, strftime_flag_pairs,
FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
NULL, NULL
},
{ "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
strfmon_flag_specs, strfmon_flag_pairs,
FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L',
NULL, NULL NULL, NULL
} }
}; };
...@@ -1934,6 +1993,9 @@ init_function_format_info () ...@@ -1934,6 +1993,9 @@ init_function_format_info ()
record_international_format (get_identifier ("gettext"), NULL_TREE, 1); record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
record_international_format (get_identifier ("dgettext"), NULL_TREE, 2); record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2); record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
/* X/Open strfmon function. */
record_function_format (get_identifier ("strfmon"), NULL_TREE,
strfmon_format_type, 3, 4);
} }
} }
...@@ -2684,7 +2746,7 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2684,7 +2746,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
} }
flag_chars[0] = 0; flag_chars[0] = 0;
if ((fki->flags & FMT_FLAG_ARG_CONVERT) && has_operand_number != 0) if ((fki->flags & FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
{ {
/* Possibly read a $ operand number at the start of the format. /* Possibly read a $ operand number at the start of the format.
If one was previously used, one is required here. If one If one was previously used, one is required here. If one
...@@ -2709,10 +2771,10 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2709,10 +2771,10 @@ check_format_info_main (status, res, info, format_chars, format_length,
while (*format_chars != 0 while (*format_chars != 0
&& strchr (fki->flag_chars, *format_chars) != 0) && strchr (fki->flag_chars, *format_chars) != 0)
{ {
const format_flag_spec *s = get_flag_spec (flag_specs,
*format_chars, NULL);
if (strchr (flag_chars, *format_chars) != 0) if (strchr (flag_chars, *format_chars) != 0)
{ {
const format_flag_spec *s = get_flag_spec (flag_specs,
*format_chars, NULL);
status_warning (status, "repeated %s in format", _(s->name)); status_warning (status, "repeated %s in format", _(s->name));
} }
else else
...@@ -2721,6 +2783,15 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2721,6 +2783,15 @@ check_format_info_main (status, res, info, format_chars, format_length,
flag_chars[i++] = *format_chars; flag_chars[i++] = *format_chars;
flag_chars[i] = 0; flag_chars[i] = 0;
} }
if (s->skip_next_char)
{
++format_chars;
if (*format_chars == 0)
{
status_warning (status, "missing fill character at end of strfmon format");
return;
}
}
++format_chars; ++format_chars;
} }
...@@ -2785,9 +2856,7 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2785,9 +2856,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
else else
{ {
/* Possibly read a numeric width. If the width is zero, /* Possibly read a numeric width. If the width is zero,
we complain; for scanf this is bad according to the we complain if appropriate. */
standard, and for printf and strftime it cannot occur
because 0 is a flag. */
int non_zero_width_char = FALSE; int non_zero_width_char = FALSE;
int found_width = FALSE; int found_width = FALSE;
while (ISDIGIT (*format_chars)) while (ISDIGIT (*format_chars))
...@@ -2797,7 +2866,8 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2797,7 +2866,8 @@ check_format_info_main (status, res, info, format_chars, format_length,
non_zero_width_char = TRUE; non_zero_width_char = TRUE;
++format_chars; ++format_chars;
} }
if (found_width && !non_zero_width_char) if (found_width && !non_zero_width_char &&
(fki->flags & FMT_FLAG_ZERO_WIDTH_BAD))
status_warning (status, "zero width in %s format", status_warning (status, "zero width in %s format",
fki->name); fki->name);
if (found_width) if (found_width)
...@@ -2809,6 +2879,20 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2809,6 +2879,20 @@ check_format_info_main (status, res, info, format_chars, format_length,
} }
} }
/* Read any format left precision (must be a number, not *). */
if (fki->left_precision_char != 0 && *format_chars == '#')
{
++format_chars;
i = strlen (flag_chars);
flag_chars[i++] = fki->left_precision_char;
flag_chars[i] = 0;
if (!ISDIGIT (*format_chars))
status_warning (status, "empty left precision in %s format",
fki->name);
while (ISDIGIT (*format_chars))
++format_chars;
}
/* Read any format precision, possibly * or *m$. */ /* Read any format precision, possibly * or *m$. */
if (fki->precision_char != 0 && *format_chars == '.') if (fki->precision_char != 0 && *format_chars == '.')
{ {
...@@ -2870,6 +2954,10 @@ check_format_info_main (status, res, info, format_chars, format_length, ...@@ -2870,6 +2954,10 @@ check_format_info_main (status, res, info, format_chars, format_length,
} }
else else
{ {
if (!(fki->flags & FMT_FLAG_EMPTY_PREC_OK)
&& !ISDIGIT (*format_chars))
status_warning (status, "empty precision in %s format",
fki->name);
while (ISDIGIT (*format_chars)) while (ISDIGIT (*format_chars))
++format_chars; ++format_chars;
} }
......
...@@ -1381,7 +1381,7 @@ hack ((union foo) x); ...@@ -1381,7 +1381,7 @@ hack ((union foo) x);
@cindex functions that behave like malloc @cindex functions that behave like malloc
@cindex @code{volatile} applied to function @cindex @code{volatile} applied to function
@cindex @code{const} applied to function @cindex @code{const} applied to function
@cindex functions with @code{printf}, @code{scanf} or @code{strftime} style arguments @cindex functions with @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon} style arguments
@cindex functions that are passed arguments in registers on the 386 @cindex functions that are passed arguments in registers on the 386
@cindex functions that pop the argument stack on the 386 @cindex functions that pop the argument stack on the 386
@cindex functions that do not pop the argument stack on the 386 @cindex functions that do not pop the argument stack on the 386
...@@ -1505,8 +1505,9 @@ specifies that the @samp{const} must be attached to the return value. ...@@ -1505,8 +1505,9 @@ specifies that the @samp{const} must be attached to the return value.
@item format (@var{archetype}, @var{string-index}, @var{first-to-check}) @item format (@var{archetype}, @var{string-index}, @var{first-to-check})
@cindex @code{format} function attribute @cindex @code{format} function attribute
The @code{format} attribute specifies that a function takes @code{printf}, The @code{format} attribute specifies that a function takes @code{printf},
@code{scanf}, or @code{strftime} style arguments which should be type-checked @code{scanf}, @code{strftime} or @code{strfmon} style arguments which
against a format string. For example, the declaration: should be type-checked against a format string. For example, the
declaration:
@smallexample @smallexample
extern int extern int
...@@ -1520,8 +1521,9 @@ for consistency with the @code{printf} style format string argument ...@@ -1520,8 +1521,9 @@ for consistency with the @code{printf} style format string argument
@code{my_format}. @code{my_format}.
The parameter @var{archetype} determines how the format string is The parameter @var{archetype} determines how the format string is
interpreted, and should be either @code{printf}, @code{scanf}, or interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
@code{strftime}. The or @code{strfmon}. (You can also use @code{__printf__},
@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.) The
parameter @var{string-index} specifies which argument is the format parameter @var{string-index} specifies which argument is the format
string argument (starting from 1), while @var{first-to-check} is the string argument (starting from 1), while @var{first-to-check} is the
number of the first argument to check against the format string. For number of the first argument to check against the format string. For
...@@ -1545,15 +1547,20 @@ for the standard library functions @code{printf}, @code{fprintf}, ...@@ -1545,15 +1547,20 @@ for the standard library functions @code{printf}, @code{fprintf},
warnings are requested (using @samp{-Wformat}), so there is no need to warnings are requested (using @samp{-Wformat}), so there is no need to
modify the header file @file{stdio.h}. In C99 mode, the functions modify the header file @file{stdio.h}. In C99 mode, the functions
@code{snprintf}, @code{vsnprintf}, @code{vscanf}, @code{vfscanf} and @code{snprintf}, @code{vsnprintf}, @code{vscanf}, @code{vfscanf} and
@code{vsscanf} are also checked. @code{vsscanf} are also checked. Except in strictly conforming C
standard modes, the X/Open function @code{strfmon} is also checked.
@xref{C Dialect Options,,Options Controlling C Dialect}. @xref{C Dialect Options,,Options Controlling C Dialect}.
@item format_arg (@var{string-index}) @item format_arg (@var{string-index})
@cindex @code{format_arg} function attribute @cindex @code{format_arg} function attribute
The @code{format_arg} attribute specifies that a function takes The @code{format_arg} attribute specifies that a function takes a format
@code{printf} or @code{scanf} style arguments, modifies it (for example, string for a @code{printf}, @code{scanf}, @code{strftime} or
to translate it into another language), and passes it to a @code{printf} @code{strfmon} style function and modifies it (for example, to translate
or @code{scanf} style function. For example, the declaration: it into another language), so the result can be passed to a
@code{printf}, @code{scanf}, @code{strftime} or @code{strfmon} style
function (with the remaining arguments to the format function the same
as they would have been for the unmodified string). For example, the
declaration:
@smallexample @smallexample
extern char * extern char *
...@@ -1562,22 +1569,28 @@ my_dgettext (char *my_domain, const char *my_format) ...@@ -1562,22 +1569,28 @@ my_dgettext (char *my_domain, const char *my_format)
@end smallexample @end smallexample
@noindent @noindent
causes the compiler to check the arguments in calls to causes the compiler to check the arguments in calls to a @code{printf},
@code{my_dgettext} whose result is passed to a @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon} type function, whose
@code{scanf}, or @code{strftime} type function for consistency with the format string argument is a call to the @code{my_dgettext} function, for
@code{printf} style format string argument @code{my_format}. consistency with the format string argument @code{my_format}. If the
@code{format_arg} attribute had not been specified, all the compiler
could tell in such calls to format functions would be that the format
string argument is not constant; this would generate a warning when
@code{-Wformat-nonliteral} is used, but the calls could not be checked
without the attribute.
The parameter @var{string-index} specifies which argument is the format The parameter @var{string-index} specifies which argument is the format
string argument (starting from 1). string argument (starting from 1).
The @code{format-arg} attribute allows you to identify your own The @code{format-arg} attribute allows you to identify your own
functions which modify format strings, so that GNU CC can check the functions which modify format strings, so that GNU CC can check the
calls to @code{printf}, @code{scanf}, or @code{strftime} function whose calls to @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon}
operands are a call to one of your own function. The compiler always type function whose operands are a call to one of your own function.
treats @code{gettext}, @code{dgettext}, and @code{dcgettext} in this The compiler always treats @code{gettext}, @code{dgettext}, and
manner except when strict ISO C support is requested by @samp{-ansi} or @code{dcgettext} in this manner except when strict ISO C support is
an appropriate @samp{-std} option, or @samp{-ffreestanding} is used. requested by @samp{-ansi} or an appropriate @samp{-std} option, or
@xref{C Dialect Options,,Options Controlling C Dialect}. @samp{-ffreestanding} is used. @xref{C Dialect Options,,Options
Controlling C Dialect}.
@item no_instrument_function @item no_instrument_function
@cindex @code{no_instrument_function} function attribute @cindex @code{no_instrument_function} function attribute
......
...@@ -1596,7 +1596,11 @@ comment, or whenever a Backslash-Newline appears in a @samp{//} comment. ...@@ -1596,7 +1596,11 @@ comment, or whenever a Backslash-Newline appears in a @samp{//} comment.
@item -Wformat @item -Wformat
Check calls to @code{printf} and @code{scanf}, etc., to make sure that Check calls to @code{printf} and @code{scanf}, etc., to make sure that
the arguments supplied have types appropriate to the format string the arguments supplied have types appropriate to the format string
specified. specified, and that the conversions specified in the format string make
sense. This includes standard functions, and others specified by format
attributes (@pxref{Function Attributes}), in the @code{printf},
@code{scanf}, @code{strftime} and @code{strfmon} (an X/Open extension,
not in the C standard) families.
The formats are checked against the format features supported by GNU The formats are checked against the format features supported by GNU
libc version 2.2. These include all ISO C89 and C99 features, as well libc version 2.2. These include all ISO C89 and C99 features, as well
...@@ -1605,8 +1609,9 @@ extensions. Other library implementations may not support all these ...@@ -1605,8 +1609,9 @@ extensions. Other library implementations may not support all these
features; GCC does not support warning about features that go beyond a features; GCC does not support warning about features that go beyond a
particular library's limitations. However, if @samp{-pedantic} is used particular library's limitations. However, if @samp{-pedantic} is used
with @samp{-Wformat}, warnings will be given about format features not with @samp{-Wformat}, warnings will be given about format features not
in the selected standard version. @xref{C Dialect Options,,Options in the selected standard version (but not for @code{strfmon} formats,
Controlling C Dialect}. since those are not in any version of the C standard). @xref{C Dialect
Options,,Options Controlling C Dialect}.
@samp{-Wformat} is included in @samp{-Wall}. For more control over some @samp{-Wformat} is included in @samp{-Wall}. For more control over some
aspects of format checking, the options @samp{-Wno-format-y2k}, aspects of format checking, the options @samp{-Wno-format-y2k},
......
2000-12-28 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/format-strfmon-1.c: New test.
2000-12-27 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> 2000-12-27 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.c-torture/execute/stdio-opt-1.c: Test __builtin_ style too. * gcc.c-torture/execute/stdio-opt-1.c: Test __builtin_ style too.
......
/* Test for strfmon format checking. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99 -Wformat" } */
typedef __SIZE_TYPE__ size_t;
/* Kludge to get something that may be ssize_t. */
#define unsigned signed
typedef __SIZE_TYPE__ ssize_t;
#undef unsigned
#define NULL ((void *)0)
extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
void
foo (char *s, size_t m, double d, long double ld)
{
/* Examples of valid formats from Austin Group draft 5. */
strfmon (s, m, "%n", d);
strfmon (s, m, "%11n", d);
strfmon (s, m, "%#5n", d);
strfmon (s, m, "%=*#5n", d);
strfmon (s, m, "%=0#5n", d);
strfmon (s, m, "%^#5n", d);
strfmon (s, m, "%^#5.0n", d);
strfmon (s, m, "%^#5.4n", d);
strfmon (s, m, "%(#5n", d);
strfmon (s, m, "%(!#5n", d);
/* Some more valid formats, including the GNU L length extension. */
strfmon (s, m, "abc%-11ndef%==i%%", d, d);
strfmon (s, m, "%%abc%-11ndef%==Li%=%i", d, ld, d);
strfmon (s, m, "%Li", ld);
strfmon (s, m, "%11Li", ld);
strfmon (s, m, "%#5Li", ld);
strfmon (s, m, "%=*#5Li", ld);
strfmon (s, m, "%=0#5Li", ld);
strfmon (s, m, "%^#5Li", ld);
strfmon (s, m, "%^#5.0Li", ld);
strfmon (s, m, "%^#5.4Li", ld);
strfmon (s, m, "%(#5Li", ld);
strfmon (s, m, "%(!#5Li", ld);
/* Formats with the wrong types used. */
strfmon (s, m, "%Ln", d); /* { dg-warning "format" "wrong type" } */
strfmon (s, m, "%n", ld); /* { dg-warning "format" "wrong type" } */
/* The + and ( flags cannot be used together. */
strfmon (s, m, "%+(i", d); /* { dg-warning "flag" "+ and ( flags" } */
strfmon (s, m, "%(+i", d); /* { dg-warning "flag" "+ and ( flags" } */
/* Although empty precision is OK for printf, it isn't here. */
strfmon (s, m, "%#.5n", d); /* { dg-warning "empty" "empty left precision" } */
strfmon (s, m, "%#5.n", d); /* { dg-warning "empty" "empty right precision" } */
/* However, zero is a valid value for width and precisions. */
strfmon (s, m, "%0#0.0n", d);
/* Test bogus %% constructions. */
strfmon (s, m, "%^%"); /* { dg-warning "format" "bogus %%" } */
strfmon (s, m, "%!%\n"); /* { dg-warning "format" "bogus %%" } */
strfmon (s, m, "%5%\n"); /* { dg-warning "format" "bogus %%" } */
strfmon (s, m, "%.5%\n"); /* { dg-warning "format" "bogus %%" } */
strfmon (s, m, "%#5%\n"); /* { dg-warning "format" "bogus %%" } */
/* Miscellaneous bogus formats. */
strfmon (s, m, "%n%n", d); /* { dg-warning "arguments" "too few args" } */
strfmon (s, m, ""); /* { dg-warning "zero-length" "empty" } */
strfmon (s, m, NULL); /* { dg-warning "null" "null format string" } */
strfmon (s, m, "%"); /* { dg-warning "trailing" "tailing %" } */
strfmon (s, m, "%n\0", d); /* { dg-warning "embedded" "embedded NUL" } */
strfmon (s, m, "%^^n", d); /* { dg-warning "repeated" "repeated flag" } */
}
...@@ -1226,7 +1226,7 @@ documented_lang_options[] = ...@@ -1226,7 +1226,7 @@ documented_lang_options[] =
{ "-Wno-comments", "" }, { "-Wno-comments", "" },
{ "-Wconversion", "Warn about possibly confusing type conversions" }, { "-Wconversion", "Warn about possibly confusing type conversions" },
{ "-Wno-conversion", "" }, { "-Wno-conversion", "" },
{ "-Wformat", "Warn about printf/scanf/strftime format anomalies" }, { "-Wformat", "Warn about printf/scanf/strftime/strfmon format anomalies" },
{ "-Wno-format", "" }, { "-Wno-format", "" },
{ "-Wformat-y2k", "" }, { "-Wformat-y2k", "" },
{ "-Wno-format-y2k", { "-Wno-format-y2k",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment