This change is from an idea suggested by Arthur David Olson.
* c-common.c (decl_attributes, record_function_format, check_format_info, init_function_format_info): Add support for strftime format checking. (enum format_type): New type. (record_function_format): Now static, and takes value of type enum format_type instead of int. (time_char_table): New constant. (struct function_format_info): format_type member renamed from is_scan. (check_format_info): Use `warning' rather than sprintf followed by `warning', to avoid mishandling `%' in warnings. Change `pedwarn' to `warning', since these warnings do not necessarily mean the program does not conform to the C Standard, as the code need not be executed. * c-tree.h (record_function_format): Remove decl; no longer extern. * extend.texi: Add documentation for strftime format checking. From-SVN: r19151
This commit is contained in:
parent
71922625f3
commit
bb72a0843b
@ -1,3 +1,25 @@
|
||||
1998-04-12 Paul Eggert <eggert@twinsun.com>
|
||||
|
||||
This change is from an idea suggested by Arthur David Olson.
|
||||
|
||||
* c-common.c (decl_attributes, record_function_format,
|
||||
check_format_info, init_function_format_info):
|
||||
Add support for strftime format checking.
|
||||
(enum format_type): New type.
|
||||
(record_function_format): Now static, and takes value of type
|
||||
enum format_type instead of int.
|
||||
(time_char_table): New constant.
|
||||
(struct function_format_info): format_type member renamed from is_scan.
|
||||
(check_format_info): Use `warning' rather than sprintf followed by
|
||||
`warning', to avoid mishandling `%' in warnings.
|
||||
Change `pedwarn' to `warning', since these warnings do not necessarily
|
||||
mean the program does not conform to the C Standard, as the code
|
||||
need not be executed.
|
||||
|
||||
* c-tree.h (record_function_format): Remove decl; no longer extern.
|
||||
|
||||
* extend.texi: Add documentation for strftime format checking.
|
||||
|
||||
Sun Apr 12 20:23:03 1998 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* mips/ecoffl.h: Do not include mips.h.
|
||||
|
360
gcc/c-common.c
360
gcc/c-common.c
@ -44,10 +44,15 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
|
||||
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
|
||||
A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
|
||||
|
||||
enum format_type { printf_format_type, scanf_format_type,
|
||||
strftime_format_type };
|
||||
|
||||
static void declare_hidden_char_array PROTO((char *, char *));
|
||||
static void add_attribute PROTO((enum attrs, char *,
|
||||
int, int, int));
|
||||
static void init_attributes PROTO((void));
|
||||
static void record_function_format PROTO((tree, tree, enum format_type,
|
||||
int, int));
|
||||
static void record_international_format PROTO((tree, tree, int));
|
||||
|
||||
/* Keep a stack of if statements. We record the number of compound
|
||||
@ -649,13 +654,13 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
|
||||
case A_FORMAT:
|
||||
{
|
||||
tree format_type = TREE_VALUE (args);
|
||||
tree format_type_id = TREE_VALUE (args);
|
||||
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
|
||||
tree first_arg_num_expr
|
||||
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
|
||||
int format_num;
|
||||
int first_arg_num;
|
||||
int is_scan;
|
||||
enum format_type format_type;
|
||||
tree argument;
|
||||
int arg_num;
|
||||
|
||||
@ -666,26 +671,27 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TREE_CODE (format_type) == IDENTIFIER_NODE
|
||||
&& (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
|
||||
|| !strcmp (IDENTIFIER_POINTER (format_type),
|
||||
"__printf__")))
|
||||
is_scan = 0;
|
||||
else if (TREE_CODE (format_type) == IDENTIFIER_NODE
|
||||
&& (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
|
||||
|| !strcmp (IDENTIFIER_POINTER (format_type),
|
||||
"__scanf__")))
|
||||
is_scan = 1;
|
||||
else if (TREE_CODE (format_type) == IDENTIFIER_NODE)
|
||||
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
|
||||
{
|
||||
warning ("`%s' is an unrecognized format function type",
|
||||
IDENTIFIER_POINTER (format_type));
|
||||
error ("unrecognized format specifier");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("unrecognized format specifier");
|
||||
continue;
|
||||
char *p = IDENTIFIER_POINTER (format_type_id);
|
||||
|
||||
if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
|
||||
format_type = printf_format_type;
|
||||
else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__"))
|
||||
format_type = scanf_format_type;
|
||||
else if (!strcmp (p, "strftime")
|
||||
|| !strcmp (p, "__strftime__"))
|
||||
format_type = strftime_format_type;
|
||||
else
|
||||
{
|
||||
error ("`%s' is an unrecognized format function type", p);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip any conversions from the string index and first arg number
|
||||
@ -751,7 +757,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
|
||||
record_function_format (DECL_NAME (decl),
|
||||
DECL_ASSEMBLER_NAME (decl),
|
||||
is_scan, format_num, first_arg_num);
|
||||
format_type, format_num, first_arg_num);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1011,12 +1017,37 @@ static format_char_info scan_char_table[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Handle format characters recognized by glibc's strftime.c.
|
||||
'2' - MUST do years as only two digits
|
||||
'3' - MAY do years as only two digits (depending on locale)
|
||||
'E' - E modifier is acceptable
|
||||
'O' - O modifier is acceptable to Standard C
|
||||
'o' - O modifier is acceptable as a GNU extension
|
||||
'G' - other GNU extensions */
|
||||
|
||||
static format_char_info time_char_table[] = {
|
||||
{ "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" },
|
||||
{ "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, "2" },
|
||||
{ "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" },
|
||||
{ "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, "3E" },
|
||||
{ "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, "" },
|
||||
{ "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, "G" },
|
||||
{ "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" },
|
||||
{ "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" },
|
||||
{ "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" },
|
||||
{ "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, "^#" },
|
||||
{ "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
|
||||
{ "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
|
||||
{ "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
typedef struct function_format_info
|
||||
{
|
||||
struct function_format_info *next; /* next structure on the list */
|
||||
tree name; /* identifier such as "printf" */
|
||||
tree assembler_name; /* optional mangled identifier (for C++) */
|
||||
int is_scan; /* TRUE if *scanf */
|
||||
enum format_type format_type; /* type of format (printf, scanf, etc.) */
|
||||
int format_num; /* number of format argument */
|
||||
int first_arg_num; /* number of first arg (zero for varargs) */
|
||||
} function_format_info;
|
||||
@ -1048,15 +1079,26 @@ static void check_format_info PROTO((function_format_info *, tree));
|
||||
void
|
||||
init_function_format_info ()
|
||||
{
|
||||
record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2);
|
||||
record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3);
|
||||
record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3);
|
||||
record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2);
|
||||
record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3);
|
||||
record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3);
|
||||
record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0);
|
||||
record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0);
|
||||
record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0);
|
||||
record_function_format (get_identifier ("printf"), NULL_TREE,
|
||||
printf_format_type, 1, 2);
|
||||
record_function_format (get_identifier ("fprintf"), NULL_TREE,
|
||||
printf_format_type, 2, 3);
|
||||
record_function_format (get_identifier ("sprintf"), NULL_TREE,
|
||||
printf_format_type, 2, 3);
|
||||
record_function_format (get_identifier ("scanf"), NULL_TREE,
|
||||
scanf_format_type, 1, 2);
|
||||
record_function_format (get_identifier ("fscanf"), NULL_TREE,
|
||||
scanf_format_type, 2, 3);
|
||||
record_function_format (get_identifier ("sscanf"), NULL_TREE,
|
||||
scanf_format_type, 2, 3);
|
||||
record_function_format (get_identifier ("vprintf"), NULL_TREE,
|
||||
printf_format_type, 1, 0);
|
||||
record_function_format (get_identifier ("vfprintf"), NULL_TREE,
|
||||
printf_format_type, 2, 0);
|
||||
record_function_format (get_identifier ("vsprintf"), NULL_TREE,
|
||||
printf_format_type, 2, 0);
|
||||
record_function_format (get_identifier ("strftime"), NULL_TREE,
|
||||
strftime_format_type, 3, 0);
|
||||
|
||||
record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
|
||||
record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
|
||||
@ -1065,19 +1107,19 @@ init_function_format_info ()
|
||||
|
||||
/* Record information for argument format checking. FUNCTION_IDENT is
|
||||
the identifier node for the name of the function to check (its decl
|
||||
need not exist yet). IS_SCAN is true for scanf-type format checking;
|
||||
false indicates printf-style format checking. FORMAT_NUM is the number
|
||||
need not exist yet).
|
||||
FORMAT_TYPE specifies the type of format checking. FORMAT_NUM is the number
|
||||
of the argument which is the format control string (starting from 1).
|
||||
FIRST_ARG_NUM is the number of the first actual argument to check
|
||||
against the format string, or zero if no checking is not be done
|
||||
(e.g. for varargs such as vfprintf). */
|
||||
|
||||
void
|
||||
record_function_format (name, assembler_name, is_scan,
|
||||
static void
|
||||
record_function_format (name, assembler_name, format_type,
|
||||
format_num, first_arg_num)
|
||||
tree name;
|
||||
tree assembler_name;
|
||||
int is_scan;
|
||||
enum format_type format_type;
|
||||
int format_num;
|
||||
int first_arg_num;
|
||||
{
|
||||
@ -1100,7 +1142,7 @@ record_function_format (name, assembler_name, is_scan,
|
||||
info->assembler_name = assembler_name;
|
||||
}
|
||||
|
||||
info->is_scan = is_scan;
|
||||
info->format_type = format_type;
|
||||
info->format_num = format_num;
|
||||
info->first_arg_num = first_arg_num;
|
||||
}
|
||||
@ -1195,7 +1237,6 @@ check_format_info (info, params)
|
||||
tree first_fillin_param;
|
||||
char *format_chars;
|
||||
format_char_info *fci;
|
||||
static char message[132];
|
||||
char flag_chars[8];
|
||||
int has_operand_number = 0;
|
||||
|
||||
@ -1304,7 +1345,7 @@ check_format_info (info, params)
|
||||
}
|
||||
flag_chars[0] = 0;
|
||||
suppressed = wide = precise = FALSE;
|
||||
if (info->is_scan)
|
||||
if (info->format_type == scanf_format_type)
|
||||
{
|
||||
suppressed = *format_chars == '*';
|
||||
if (suppressed)
|
||||
@ -1312,7 +1353,47 @@ check_format_info (info, params)
|
||||
while (isdigit (*format_chars))
|
||||
++format_chars;
|
||||
}
|
||||
else
|
||||
else if (info->format_type == strftime_format_type)
|
||||
{
|
||||
while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0)
|
||||
{
|
||||
if (pedantic)
|
||||
warning ("ANSI C does not support the strftime `%c' flag",
|
||||
*format_chars);
|
||||
if (index (flag_chars, *format_chars) != 0)
|
||||
{
|
||||
warning ("repeated `%c' flag in format",
|
||||
*format_chars);
|
||||
++format_chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = strlen (flag_chars);
|
||||
flag_chars[i++] = *format_chars++;
|
||||
flag_chars[i] = 0;
|
||||
}
|
||||
}
|
||||
while (isdigit ((unsigned char) *format_chars))
|
||||
{
|
||||
wide = TRUE;
|
||||
++format_chars;
|
||||
}
|
||||
if (wide && pedantic)
|
||||
warning ("ANSI C does not support strftime format width");
|
||||
if (*format_chars == 'E' || *format_chars == 'O')
|
||||
{
|
||||
i = strlen (flag_chars);
|
||||
flag_chars[i++] = *format_chars++;
|
||||
flag_chars[i] = 0;
|
||||
if (*format_chars == 'E' || *format_chars == 'O')
|
||||
{
|
||||
warning ("multiple E/O modifiers in format");
|
||||
while (*format_chars == 'E' || *format_chars == 'O')
|
||||
++format_chars;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (info->format_type == printf_format_type)
|
||||
{
|
||||
/* See if we have a number followed by a dollar sign. If we do,
|
||||
it is an operand number, so set PARAMS to that operand. */
|
||||
@ -1345,11 +1426,7 @@ check_format_info (info, params)
|
||||
while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
|
||||
{
|
||||
if (index (flag_chars, *format_chars) != 0)
|
||||
{
|
||||
sprintf (message, "repeated `%c' flag in format",
|
||||
*format_chars++);
|
||||
warning (message);
|
||||
}
|
||||
warning ("repeated `%c' flag in format", *format_chars++);
|
||||
else
|
||||
{
|
||||
i = strlen (flag_chars);
|
||||
@ -1392,12 +1469,7 @@ check_format_info (info, params)
|
||||
&&
|
||||
(TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
|
||||
!= unsigned_type_node))
|
||||
{
|
||||
sprintf (message,
|
||||
"field width is not type int (arg %d)",
|
||||
arg_num);
|
||||
warning (message);
|
||||
}
|
||||
warning ("field width is not type int (arg %d)", arg_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1431,12 +1503,8 @@ check_format_info (info, params)
|
||||
++arg_num;
|
||||
if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
|
||||
!= integer_type_node)
|
||||
{
|
||||
sprintf (message,
|
||||
"field width is not type int (arg %d)",
|
||||
arg_num);
|
||||
warning (message);
|
||||
}
|
||||
warning ("field width is not type int (arg %d)",
|
||||
arg_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1446,92 +1514,106 @@ check_format_info (info, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*format_chars == 'h' || *format_chars == 'l')
|
||||
length_char = *format_chars++;
|
||||
else if (*format_chars == 'q' || *format_chars == 'L')
|
||||
{
|
||||
length_char = *format_chars++;
|
||||
if (pedantic && length_char == 'q')
|
||||
pedwarn ("ANSI C does not support the `%c' length modifier",
|
||||
length_char);
|
||||
}
|
||||
else if (*format_chars == 'Z')
|
||||
{
|
||||
length_char = *format_chars++;
|
||||
if (pedantic)
|
||||
pedwarn ("ANSI C does not support the `Z' length modifier");
|
||||
}
|
||||
else
|
||||
length_char = 0;
|
||||
if (length_char == 'l' && *format_chars == 'l')
|
||||
{
|
||||
length_char = 'q', format_chars++;
|
||||
if (pedantic)
|
||||
pedwarn ("ANSI C does not support the `ll' length modifier");
|
||||
}
|
||||
|
||||
aflag = 0;
|
||||
if (*format_chars == 'a' && info->is_scan)
|
||||
|
||||
if (info->format_type != strftime_format_type)
|
||||
{
|
||||
if (format_chars[1] == 's' || format_chars[1] == 'S'
|
||||
|| format_chars[1] == '[')
|
||||
if (*format_chars == 'h' || *format_chars == 'l')
|
||||
length_char = *format_chars++;
|
||||
else if (*format_chars == 'q' || *format_chars == 'L')
|
||||
{
|
||||
/* `a' is used as a flag. */
|
||||
aflag = 1;
|
||||
format_chars++;
|
||||
length_char = *format_chars++;
|
||||
if (pedantic && length_char == 'q')
|
||||
warning ("ANSI C does not support the `%c' length modifier",
|
||||
length_char);
|
||||
}
|
||||
}
|
||||
if (suppressed && length_char != 0)
|
||||
{
|
||||
sprintf (message,
|
||||
"use of `*' and `%c' together in format",
|
||||
length_char);
|
||||
warning (message);
|
||||
else if (*format_chars == 'Z')
|
||||
{
|
||||
length_char = *format_chars++;
|
||||
if (pedantic)
|
||||
warning ("ANSI C does not support the `Z' length modifier");
|
||||
}
|
||||
else
|
||||
length_char = 0;
|
||||
if (length_char == 'l' && *format_chars == 'l')
|
||||
{
|
||||
length_char = 'q', format_chars++;
|
||||
if (pedantic)
|
||||
warning ("ANSI C does not support the `ll' length modifier");
|
||||
}
|
||||
if (*format_chars == 'a' && info->format_type == scanf_format_type)
|
||||
{
|
||||
if (format_chars[1] == 's' || format_chars[1] == 'S'
|
||||
|| format_chars[1] == '[')
|
||||
{
|
||||
/* `a' is used as a flag. */
|
||||
aflag = 1;
|
||||
format_chars++;
|
||||
}
|
||||
}
|
||||
if (suppressed && length_char != 0)
|
||||
warning ("use of `*' and `%c' together in format", length_char);
|
||||
}
|
||||
format_char = *format_chars;
|
||||
if (format_char == 0 || format_char == '%')
|
||||
if (format_char == 0
|
||||
|| (info->format_type != strftime_format_type && format_char == '%'))
|
||||
{
|
||||
warning ("conversion lacks type at end of format");
|
||||
continue;
|
||||
}
|
||||
format_chars++;
|
||||
fci = info->is_scan ? scan_char_table : print_char_table;
|
||||
switch (info->format_type)
|
||||
{
|
||||
case printf_format_type:
|
||||
fci = print_char_table;
|
||||
break;
|
||||
case scanf_format_type:
|
||||
fci = scan_char_table;
|
||||
break;
|
||||
case strftime_format_type:
|
||||
fci = time_char_table;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
while (fci->format_chars != 0
|
||||
&& index (fci->format_chars, format_char) == 0)
|
||||
++fci;
|
||||
if (fci->format_chars == 0)
|
||||
{
|
||||
if (format_char >= 040 && format_char < 0177)
|
||||
sprintf (message,
|
||||
"unknown conversion type character `%c' in format",
|
||||
warning ("unknown conversion type character `%c' in format",
|
||||
format_char);
|
||||
else
|
||||
sprintf (message,
|
||||
"unknown conversion type character 0x%x in format",
|
||||
warning ("unknown conversion type character 0x%x in format",
|
||||
format_char);
|
||||
warning (message);
|
||||
continue;
|
||||
}
|
||||
if (pedantic)
|
||||
{
|
||||
if (index (fci->flag_chars, 'G') != 0)
|
||||
warning ("ANSI C does not support `%%%c'", format_char);
|
||||
if (index (fci->flag_chars, 'o') != 0
|
||||
&& index (flag_chars, 'O') != 0)
|
||||
warning ("ANSI C does not support `%%O%c'", format_char);
|
||||
}
|
||||
if (wide && index (fci->flag_chars, 'w') == 0)
|
||||
{
|
||||
sprintf (message, "width used with `%c' format",
|
||||
format_char);
|
||||
warning (message);
|
||||
}
|
||||
warning ("width used with `%c' format", format_char);
|
||||
if (index (fci->flag_chars, '2') != 0)
|
||||
warning ("`%%%c' yields only last 2 digits of year", format_char);
|
||||
else if (index (fci->flag_chars, '3') != 0)
|
||||
warning ("`%%%c' yields only last 2 digits of year in some locales",
|
||||
format_char);
|
||||
if (precise && index (fci->flag_chars, 'p') == 0)
|
||||
{
|
||||
sprintf (message, "precision used with `%c' format",
|
||||
format_char);
|
||||
warning (message);
|
||||
}
|
||||
warning ("precision used with `%c' format", format_char);
|
||||
if (aflag && index (fci->flag_chars, 'a') == 0)
|
||||
{
|
||||
sprintf (message, "`a' flag used with `%c' format",
|
||||
format_char);
|
||||
warning (message);
|
||||
warning ("`a' flag used with `%c' format", format_char);
|
||||
/* To simplify the following code. */
|
||||
aflag = 0;
|
||||
}
|
||||
if (info->is_scan && format_char == '[')
|
||||
if (info->format_type == scanf_format_type && format_char == '[')
|
||||
{
|
||||
/* Skip over scan set, in case it happens to have '%' in it. */
|
||||
if (*format_chars == '^')
|
||||
@ -1543,39 +1625,29 @@ check_format_info (info, params)
|
||||
while (*format_chars && *format_chars != ']')
|
||||
++format_chars;
|
||||
if (*format_chars != ']')
|
||||
/* The end of the format string was reached. */
|
||||
warning ("no closing `]' for `%%[' format");
|
||||
/* The end of the format string was reached. */
|
||||
warning ("no closing `]' for `%%[' format");
|
||||
}
|
||||
if (suppressed)
|
||||
{
|
||||
if (index (fci->flag_chars, '*') == 0)
|
||||
{
|
||||
sprintf (message,
|
||||
"suppression of `%c' conversion in format",
|
||||
format_char);
|
||||
warning (message);
|
||||
}
|
||||
warning ("suppression of `%c' conversion in format", format_char);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; flag_chars[i] != 0; ++i)
|
||||
{
|
||||
if (index (fci->flag_chars, flag_chars[i]) == 0)
|
||||
{
|
||||
sprintf (message, "flag `%c' used with type `%c'",
|
||||
flag_chars[i], format_char);
|
||||
warning (message);
|
||||
}
|
||||
warning ("flag `%c' used with type `%c'",
|
||||
flag_chars[i], format_char);
|
||||
}
|
||||
if (info->format_type == strftime_format_type)
|
||||
continue;
|
||||
integral_format = (format_char == 'd' || format_char == 'i'
|
||||
|| format_char == 'o' || format_char == 'u'
|
||||
|| format_char == 'x' || format_char == 'x');
|
||||
if (precise && index (flag_chars, '0') != 0 && integral_format)
|
||||
{
|
||||
sprintf (message,
|
||||
"`0' flag ignored with precision specifier and `%c' format",
|
||||
format_char);
|
||||
warning (message);
|
||||
}
|
||||
warning ("`0' flag ignored with precision specifier and `%c' format",
|
||||
format_char);
|
||||
switch (length_char)
|
||||
{
|
||||
default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
|
||||
@ -1637,20 +1709,17 @@ check_format_info (info, params)
|
||||
continue;
|
||||
}
|
||||
if (TREE_CODE (cur_type) != ERROR_MARK)
|
||||
{
|
||||
sprintf (message,
|
||||
"format argument is not a %s (arg %d)",
|
||||
((fci->pointer_count + aflag == 1)
|
||||
? "pointer" : "pointer to a pointer"),
|
||||
arg_num);
|
||||
warning (message);
|
||||
}
|
||||
warning ("format argument is not a %s (arg %d)",
|
||||
((fci->pointer_count + aflag == 1)
|
||||
? "pointer" : "pointer to a pointer"),
|
||||
arg_num);
|
||||
break;
|
||||
}
|
||||
|
||||
/* See if this is an attempt to write into a const type with
|
||||
scanf. */
|
||||
if (info->is_scan && i == fci->pointer_count + aflag
|
||||
if (info->format_type == scanf_format_type
|
||||
&& i == fci->pointer_count + aflag
|
||||
&& wanted_type != 0
|
||||
&& TREE_CODE (cur_type) != ERROR_MARK
|
||||
&& (TYPE_READONLY (cur_type)
|
||||
@ -1658,10 +1727,7 @@ check_format_info (info, params)
|
||||
&& (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
|
||||
|| (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'd'
|
||||
&& TREE_READONLY (cur_param))))))
|
||||
{
|
||||
sprintf (message, "writing into constant object (arg %d)", arg_num);
|
||||
warning (message);
|
||||
}
|
||||
warning ("writing into constant object (arg %d)", arg_num);
|
||||
|
||||
/* Check the type of the "real" argument, if there's a type we want. */
|
||||
if (i == fci->pointer_count + aflag && wanted_type != 0
|
||||
@ -1721,11 +1787,7 @@ check_format_info (info, params)
|
||||
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
|
||||
|
||||
if (strcmp (this, that) != 0)
|
||||
{
|
||||
sprintf (message, "%s format, %s arg (arg %d)",
|
||||
this, that, arg_num);
|
||||
warning (message);
|
||||
}
|
||||
warning ("%s format, %s arg (arg %d)", this, that, arg_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1829,7 +1891,7 @@ convert_and_check (type, expr)
|
||||
|| TREE_UNSIGNED (type)
|
||||
|| ! int_fits_type_p (expr, unsigned_type (type)))
|
||||
&& skip_evaluation == 0)
|
||||
warning ("overflow in implicit constant conversion");
|
||||
warning ("overflow in implicit constant conversion");
|
||||
}
|
||||
else
|
||||
unsigned_conversion_warning (t, expr);
|
||||
|
@ -162,7 +162,6 @@ extern void gen_aux_info_record PROTO((tree, int, int, int));
|
||||
extern void declare_function_name PROTO((void));
|
||||
extern void decl_attributes PROTO((tree, tree, tree));
|
||||
extern void init_function_format_info PROTO((void));
|
||||
extern void record_function_format PROTO((tree, tree, int, int, int));
|
||||
extern void check_function_format PROTO((tree, tree, tree));
|
||||
/* Print an error message for invalid operands to arith operation CODE.
|
||||
NOP_EXPR is used as a special case (see truthvalue_conversion). */
|
||||
|
@ -1274,7 +1274,7 @@ hack ((union foo) x);
|
||||
@cindex functions in arbitrary sections
|
||||
@cindex @code{volatile} applied to function
|
||||
@cindex @code{const} applied to function
|
||||
@cindex functions with @code{printf} or @code{scanf} style arguments
|
||||
@cindex functions with @code{printf}, @code{scanf} or @code{strftime} 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
|
||||
@ -1378,9 +1378,9 @@ return @code{void}.
|
||||
|
||||
@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}
|
||||
or @code{scanf} style arguments which should be type-checked against a
|
||||
format string. For example, the declaration:
|
||||
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:
|
||||
|
||||
@smallexample
|
||||
extern int
|
||||
@ -1394,7 +1394,8 @@ 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} or @code{scanf}. The
|
||||
interpreted, and should be either @code{printf}, @code{scanf}, or
|
||||
@code{strftime}. 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
|
||||
@ -1411,7 +1412,7 @@ The @code{format} attribute allows you to identify your own functions
|
||||
which take format strings as arguments, so that GNU CC can check the
|
||||
calls to these functions for errors. The compiler always checks formats
|
||||
for the ANSI library functions @code{printf}, @code{fprintf},
|
||||
@code{sprintf}, @code{scanf}, @code{fscanf}, @code{sscanf},
|
||||
@code{sprintf}, @code{scanf}, @code{fscanf}, @code{sscanf}, @code{strftime},
|
||||
@code{vprintf}, @code{vfprintf} and @code{vsprintf} whenever such
|
||||
warnings are requested (using @samp{-Wformat}), so there is no need to
|
||||
modify the header file @file{stdio.h}.
|
||||
@ -1431,18 +1432,19 @@ my_dgettext (char *my_domain, const char *my_format)
|
||||
|
||||
@noindent
|
||||
causes the compiler to check the arguments in calls to
|
||||
@code{my_dgettext} whose result is passed to a @code{printf} or
|
||||
@code{scanf} type function for consistency with the @code{printf} style
|
||||
format string argument @code{my_format}.
|
||||
@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}.
|
||||
|
||||
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} and @code{scanf} 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.
|
||||
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.
|
||||
|
||||
@item section ("section-name")
|
||||
@cindex @code{section} function attribute
|
||||
|
Loading…
Reference in New Issue
Block a user