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:
parent
df7978d9b7
commit
26f6672d2e
@ -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.
|
||||
|
186
gcc/c-common.c
186
gcc/c-common.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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.
|
||||
|
68
gcc/testsuite/gcc.dg/format-strfmon-1.c
Normal file
68
gcc/testsuite/gcc.dg/format-strfmon-1.c
Normal 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" } */
|
||||
}
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user