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
This commit is contained in:
Joseph Myers 2000-12-28 18:48:05 +00:00 committed by Joseph Myers
parent df7978d9b7
commit 26f6672d2e
7 changed files with 277 additions and 73 deletions

View File

@ -1,3 +1,29 @@
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>
* expmed.c (store_bit_field): Fix last patch.

View File

@ -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};
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 *,
int, int, int));
@ -955,6 +955,9 @@ decl_attributes (node, attributes, prefix_attributes)
else if (!strcmp (p, "strftime")
|| !strcmp (p, "__strftime__"))
format_type = strftime_format_type;
else if (!strcmp (p, "strfmon")
|| !strcmp (p, "__strfmon__"))
format_type = strfmon_format_type;
else
{
warning ("`%s' is an unrecognized format function type", p);
@ -1357,13 +1360,17 @@ enum
FMT_FLAG_FANCY_PERCENT_OK = 4,
/* With $ operand numbers, it is OK to reference the same argument more
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
(controlled by width_char and precision_char); details of whether
'*' can be used for these (width_type and precision_type); details
of whether length modifiers can occur (length_char_specs); details
of when $ operand numbers are allowed (always, for the formats
supported, if arguments are converted). */
of whether length modifiers can occur (length_char_specs). */
};
@ -1415,7 +1422,8 @@ typedef struct
/* Types accepted for each length modifier. */
format_type_detail types[FMT_LEN_MAX];
/* 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),
"*" for scanf suppression, and "E" and "O" for those strftime
modifiers. */
@ -1447,6 +1455,9 @@ typedef struct
the unpredicated one, for any pedantic warning. For example, 'o'
for strftime formats (meaning 'O' is an extension over C99). */
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,
N_("`0' flag"), N_("field width"). */
const char *name;
@ -1497,7 +1508,11 @@ typedef struct
int flags;
/* Flag character to treat a width as, or 0 if width not used. */
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;
/* If a flag character has the effect of suppressing the conversion of
an argument ('*' in scanf), that flag character, otherwise 0. */
@ -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[] =
{
{ ' ', 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 },
{ '+', 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 },
{ '#', 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 },
{ '0', 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 },
{ '-', 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 },
{ '\'', 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT },
{ 'I', 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT },
{ 'w', 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, NULL, NULL, 0 }
{ ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 },
{ '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 },
{ '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 },
{ '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 },
{ '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 },
{ '\'', 0, 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT },
{ 'I', 0, 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
{ 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
{ 0, 0, 0, NULL, NULL, 0 }
};
@ -1606,13 +1630,13 @@ static const format_flag_pair printf_flag_pairs[] =
static const format_flag_spec scanf_flag_specs[] =
{
{ '*', 0, N_("assignment suppression"), N_("assignment suppression"), STD_C89 },
{ 'a', 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT },
{ 'w', 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 },
{ '\'', 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT },
{ 'I', 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT },
{ 0, 0, NULL, NULL, 0 }
{ '*', 0, 0, N_("assignment suppression"), N_("assignment suppression"), STD_C89 },
{ 'a', 0, 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
{ 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
{ '\'', 0, 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT },
{ 'I', 0, 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT },
{ 0, 0, 0, NULL, NULL, 0 }
};
@ -1625,16 +1649,16 @@ static const format_flag_pair scanf_flag_pairs[] =
static const format_flag_spec strftime_flag_specs[] =
{
{ '_', 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT },
{ '-', 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT },
{ '0', 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT },
{ '^', 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT },
{ '#', 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT },
{ 'w', 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
{ 'E', 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 },
{ 'O', 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 },
{ 'O', 'o', NULL, N_("the `O' modifier"), STD_EXT },
{ 0, 0, NULL, NULL, 0 }
{ '_', 0, 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT },
{ '-', 0, 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT },
{ '0', 0, 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT },
{ '^', 0, 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT },
{ '#', 0, 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT },
{ 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
{ 'E', 0, 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 },
{ 'O', 0, 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 },
{ 'O', 'o', 0, NULL, N_("the `O' modifier"), STD_EXT },
{ 0, 0, 0, NULL, NULL, 0 }
};
@ -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 T89_I { STD_C89, NULL, T_I }
#define T99_I { STD_C99, NULL, T_I }
@ -1748,7 +1794,7 @@ static const format_char_info scan_char_table[] =
{ NULL, 0, 0, NOLENGTHS, NULL, NULL }
};
static format_char_info time_char_table[] =
static const format_char_info time_char_table[] =
{
/* C89 conversion specifiers. */
{ "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" },
@ -1775,23 +1821,36 @@ static format_char_info time_char_table[] =
{ 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. */
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,
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
},
{ "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
{ "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
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
},
{ "strftime", NULL, time_char_table, "_-0^#", "EO",
{ "strftime", NULL, time_char_table, "_-0^#", "EO",
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
}
};
@ -1934,6 +1993,9 @@ init_function_format_info ()
record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
record_international_format (get_identifier ("dgettext"), 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,
}
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.
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,
while (*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)
{
const format_flag_spec *s = get_flag_spec (flag_specs,
*format_chars, NULL);
status_warning (status, "repeated %s in format", _(s->name));
}
else
@ -2721,6 +2783,15 @@ check_format_info_main (status, res, info, format_chars, format_length,
flag_chars[i++] = *format_chars;
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;
}
@ -2785,9 +2856,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
else
{
/* Possibly read a numeric width. If the width is zero,
we complain; for scanf this is bad according to the
standard, and for printf and strftime it cannot occur
because 0 is a flag. */
we complain if appropriate. */
int non_zero_width_char = FALSE;
int found_width = FALSE;
while (ISDIGIT (*format_chars))
@ -2797,7 +2866,8 @@ check_format_info_main (status, res, info, format_chars, format_length,
non_zero_width_char = TRUE;
++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",
fki->name);
if (found_width)
@ -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$. */
if (fki->precision_char != 0 && *format_chars == '.')
{
@ -2870,6 +2954,10 @@ check_format_info_main (status, res, info, format_chars, format_length,
}
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))
++format_chars;
}

View File

@ -1381,7 +1381,7 @@ hack ((union foo) x);
@cindex functions that behave like malloc
@cindex @code{volatile} 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 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.
@item format (@var{archetype}, @var{string-index}, @var{first-to-check})
@cindex @code{format} function attribute
The @code{format} attribute specifies that a function takes @code{printf},
@code{scanf}, or @code{strftime} style arguments which should be type-checked
against a format string. For example, the declaration:
@code{scanf}, @code{strftime} or @code{strfmon} style arguments which
should be type-checked against a format string. For example, the
declaration:
@smallexample
extern int
@ -1520,8 +1521,9 @@ for consistency with the @code{printf} style format string argument
@code{my_format}.
The parameter @var{archetype} determines how the format string is
interpreted, and should be either @code{printf}, @code{scanf}, or
@code{strftime}. The
interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
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
string argument (starting from 1), while @var{first-to-check} is the
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},
warnings are requested (using @samp{-Wformat}), so there is no need to
modify the header file @file{stdio.h}. In C99 mode, the functions
@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}.
@item format_arg (@var{string-index})
@cindex @code{format_arg} function attribute
The @code{format_arg} attribute specifies that a function takes
@code{printf} or @code{scanf} style arguments, modifies it (for example,
to translate it into another language), and passes it to a @code{printf}
or @code{scanf} style function. For example, the declaration:
The @code{format_arg} attribute specifies that a function takes a format
string for a @code{printf}, @code{scanf}, @code{strftime} or
@code{strfmon} style function and modifies it (for example, to translate
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
extern char *
@ -1562,22 +1569,28 @@ my_dgettext (char *my_domain, const char *my_format)
@end smallexample
@noindent
causes the compiler to check the arguments in calls to
@code{my_dgettext} whose result is passed to a @code{printf},
@code{scanf}, or @code{strftime} type function for consistency with the
@code{printf} style format string argument @code{my_format}.
causes the compiler to check the arguments in calls to a @code{printf},
@code{scanf}, @code{strftime} or @code{strfmon} type function, whose
format string argument is a call to the @code{my_dgettext} function, for
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
string argument (starting from 1).
The @code{format-arg} attribute allows you to identify your own
functions which modify format strings, so that GNU CC can check the
calls to @code{printf}, @code{scanf}, or @code{strftime} function whose
operands are a call to one of your own function. The compiler always
treats @code{gettext}, @code{dgettext}, and @code{dcgettext} in this
manner except when strict ISO C support is requested by @samp{-ansi} or
an appropriate @samp{-std} option, or @samp{-ffreestanding} is used.
@xref{C Dialect Options,,Options Controlling C Dialect}.
calls to @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon}
type function whose operands are a call to one of your own function.
The compiler always treats @code{gettext}, @code{dgettext}, and
@code{dcgettext} in this manner except when strict ISO C support is
requested by @samp{-ansi} or an appropriate @samp{-std} option, or
@samp{-ffreestanding} is used. @xref{C Dialect Options,,Options
Controlling C Dialect}.
@item no_instrument_function
@cindex @code{no_instrument_function} function attribute

View File

@ -1596,7 +1596,11 @@ comment, or whenever a Backslash-Newline appears in a @samp{//} comment.
@item -Wformat
Check calls to @code{printf} and @code{scanf}, etc., to make sure that
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
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
features; GCC does not support warning about features that go beyond a
particular library's limitations. However, if @samp{-pedantic} is used
with @samp{-Wformat}, warnings will be given about format features not
in the selected standard version. @xref{C Dialect Options,,Options
Controlling C Dialect}.
in the selected standard version (but not for @code{strfmon} formats,
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
aspects of format checking, the options @samp{-Wno-format-y2k},

View File

@ -1,3 +1,7 @@
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>
* gcc.c-torture/execute/stdio-opt-1.c: Test __builtin_ style too.

View File

@ -0,0 +1,68 @@
/* 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" } */
}

View File

@ -1226,7 +1226,7 @@ documented_lang_options[] =
{ "-Wno-comments", "" },
{ "-Wconversion", "Warn about possibly confusing type conversions" },
{ "-Wno-conversion", "" },
{ "-Wformat", "Warn about printf/scanf/strftime format anomalies" },
{ "-Wformat", "Warn about printf/scanf/strftime/strfmon format anomalies" },
{ "-Wno-format", "" },
{ "-Wformat-y2k", "" },
{ "-Wno-format-y2k",