c-common.h (flag_isoc94): Declare.

* c-common.h (flag_isoc94): Declare.
	* c-decl.c (flag_isoc94): Define.
	(c_decode_option): Set flag_isoc94 as appropriate.
	* c-common.c (T_PD, T_IM, T_UIM): Define.
	(format_char_info): Add tlen and jlen.
	(print_char_table): Add entries for %t and %j.  Allow %zn.  Allow
	%F.  Allow %lf.
	(scan_char_table): Add entries for %t and %j.  Allow %F.  Allow
	%l[.
	(time_char_table): Add NULL entries for %t and %j.
	(check_format_info): Allow for %t and %j.  Warn for %F if pedantic
	and not C99.  Warn for %lc, %ls and %l[ if pedantic and not C94.
	Warn for printf %lf if pedantic and not C99.  Don't warn for empty
	precision.  Allow precision argument to be unsigned int.  If
	pedantic, warn for %p passed an argument not a pointer to possibly
	qualified void or a possibly qualified character type, and for
	pointer targets of the wrong sign, except for character pointers.

cp:
	* decl.c (flag_isoc94): New variable.

testsuite:
	* gcc.dg/c90-printf-1.c, gcc.dg/c94-printf-1.c: New tests.

From-SVN: r35482
This commit is contained in:
Joseph Myers 2000-08-04 17:10:14 +01:00 committed by Joseph Myers
parent c5ab7f9110
commit b8458e3e8b
9 changed files with 415 additions and 48 deletions

View File

@ -1,3 +1,23 @@
2000-08-04 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.h (flag_isoc94): Declare.
* c-decl.c (flag_isoc94): Define.
(c_decode_option): Set flag_isoc94 as appropriate.
* c-common.c (T_PD, T_IM, T_UIM): Define.
(format_char_info): Add tlen and jlen.
(print_char_table): Add entries for %t and %j. Allow %zn. Allow
%F. Allow %lf.
(scan_char_table): Add entries for %t and %j. Allow %F. Allow
%l[.
(time_char_table): Add NULL entries for %t and %j.
(check_format_info): Allow for %t and %j. Warn for %F if pedantic
and not C99. Warn for %lc, %ls and %l[ if pedantic and not C94.
Warn for printf %lf if pedantic and not C99. Don't warn for empty
precision. Allow precision argument to be unsigned int. If
pedantic, warn for %p passed an argument not a pointer to possibly
qualified void or a possibly qualified character type, and for
pointer targets of the wrong sign, except for character pointers.
2000-08-04 Joseph S. Myers <jsm28@cam.ac.uk>
* ginclude/stddef.h: Don't declare wint_t unless __need_wint_t.

View File

@ -1195,6 +1195,9 @@ strip_attrs (specs_attrs)
#define T_W &wchar_type_node
#define T_WI &wint_type_node
#define T_ST &sizetype
#define T_PD &ptrdiff_type_node
#define T_IM NULL /* intmax_t not yet implemented. */
#define T_UIM NULL /* uintmax_t not yet implemented. */
typedef struct {
const char *format_chars;
@ -1219,38 +1222,44 @@ typedef struct {
/* Type of argument if length modifiers 'z' or `Z' is used.
If NULL, then this modifier is not allowed. */
tree *zlen;
/* Type of argument if length modifier 't' is used.
If NULL, then this modifier is not allowed. */
tree *tlen;
/* Type of argument if length modifier 'j' is used.
If NULL, then this modifier is not allowed. */
tree *jlen;
/* List of other modifier characters allowed with these options. */
const char *flag_chars;
} format_char_info;
static format_char_info print_char_table[] = {
{ "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" },
{ "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" },
{ "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" },
{ "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, T_PD, T_IM, "-wp0 +" },
{ "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, T_PD, T_UIM, "-wp0#" },
{ "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, T_PD, T_UIM, "-wp0" },
/* A GNU extension. */
{ "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "feEgGaA", 0, T_D, NULL, NULL, NULL, NULL, T_LD, NULL, "-wp0 +#" },
{ "c", 0, T_I, NULL, NULL, T_WI, NULL, NULL, NULL, "-w" },
{ "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "-wp" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
{ "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "fFeEgGaA", 0, T_D, NULL, NULL, T_D, NULL, T_LD, NULL, NULL, NULL, "-wp0 +#" },
{ "c", 0, T_I, NULL, NULL, T_WI, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
{ "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
{ "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, T_ST, T_PD, T_IM, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
static format_char_info scan_char_table[] = {
{ "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, T_ST, "*" },
{ "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, T_ST, "*" },
{ "efgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, "*" },
{ "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*a" },
{ "[", 1, T_C, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, T_ST, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
{ "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, T_ST, T_PD, T_IM, "*" },
{ "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, T_ST, T_PD, T_UIM, "*" },
{ "efFgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, NULL, NULL, "*" },
{ "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, NULL, NULL, "*" },
{ "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "[", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
{ "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
{ "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, T_ST, T_PD, T_IM, "" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
/* Handle format characters recognized by glibc's strftime.c.
@ -1262,20 +1271,20 @@ static format_char_info scan_char_table[] = {
'G' - other GNU extensions */
static format_char_info time_char_table[] = {
{ "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" },
{ "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" },
{ "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" },
{ "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" },
{ "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" },
{ "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" },
{ "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" },
{ "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" },
{ "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" },
{ "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" },
{ "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
{ "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
{ "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
{ "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" },
{ "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" },
{ "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" },
{ "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" },
{ "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" },
{ "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" },
{ "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" },
{ "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" },
{ "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" },
{ "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" },
{ "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
{ "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
{ "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
typedef struct function_format_info
@ -1595,6 +1604,7 @@ check_format_info (info, params)
while (1)
{
int aflag;
int char_type_flag = 0;
if (*format_chars == 0)
{
if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
@ -1756,8 +1766,6 @@ check_format_info (info, params)
{
precise = TRUE;
++format_chars;
if (*format_chars != '*' && !ISDIGIT (*format_chars))
warning ("`.' not followed by `*' or digit in format");
/* "...a...precision...may be indicated by an asterisk.
In this case, an int argument supplies the...precision." */
if (*format_chars == '*')
@ -1773,9 +1781,12 @@ check_format_info (info, params)
cur_param = TREE_VALUE (params);
params = TREE_CHAIN (params);
++arg_num;
if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= integer_type_node)
warning ("field width is not type int (arg %d)",
if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= integer_type_node)
&&
(TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= unsigned_type_node))
warning ("field precision is not type int (arg %d)",
arg_num);
}
}
@ -1807,6 +1818,13 @@ check_format_info (info, params)
warning ("ANSI C does not support the `%c' length modifier",
length_char);
}
else if (*format_chars == 't' || *format_chars == 'j')
{
length_char = *format_chars++;
if (pedantic && !flag_isoc99)
warning ("ANSI C does not support the `%c' length modifier",
length_char);
}
else
length_char = 0;
if (length_char == 'l' && *format_chars == 'l')
@ -1845,9 +1863,9 @@ check_format_info (info, params)
if (pedantic && info->format_type != strftime_format_type
&& (format_char == 'm' || format_char == 'C' || format_char == 'S'))
warning ("ANSI C does not support the `%c' format", format_char);
/* The a and A formats are C99 extensions. */
/* The a, A and F formats are C99 extensions. */
if (pedantic && info->format_type != strftime_format_type
&& (format_char == 'a' || format_char == 'A')
&& (format_char == 'a' || format_char == 'A' || format_char == 'F')
&& !flag_isoc99)
warning ("ANSI C does not support the `%c' format", format_char);
format_chars++;
@ -1952,6 +1970,8 @@ check_format_info (info, params)
? TYPE_DOMAIN (*fci->zlen)
: *fci->zlen)
: 0); break;
case 't': wanted_type = fci->tlen ? *(fci->tlen) : 0; break;
case 'j': wanted_type = fci->jlen ? *(fci->jlen) : 0; break;
}
if (wanted_type == 0)
warning ("use of `%c' length character with `%c' type character",
@ -1963,6 +1983,19 @@ check_format_info (info, params)
|| format_char == 'g' || format_char == 'G'))
warning ("ANSI C does not support the `L' length modifier with the `%c' type character",
format_char);
else if (length_char == 'l'
&& (format_char == 'c' || format_char == 's'
|| format_char == '[')
&& pedantic && !flag_isoc94)
warning ("ANSI C89 does not support the `l' length modifier with the `%c' type character",
format_char);
else if (info->format_type == printf_format_type && pedantic
&& !flag_isoc99 && length_char == 'l'
&& (format_char == 'f' || format_char == 'e'
|| format_char == 'E' || format_char == 'g'
|| format_char == 'G'))
warning ("ANSI C does not support the `l' length modifier with the `%c' type character",
format_char);
/* Finally. . .check type of argument against desired type! */
if (info->first_arg_num == 0)
@ -2021,23 +2054,41 @@ check_format_info (info, params)
|| (DECL_P (cur_param) && TREE_READONLY (cur_param))))))
warning ("writing into constant object (arg %d)", arg_num);
/* Check whether the argument type is a character type. */
if (TREE_CODE (cur_type) != ERROR_MARK)
char_type_flag = (TYPE_MAIN_VARIANT (cur_type) == char_type_node
|| TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
|| TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node);
/* Check the type of the "real" argument, if there's a type we want. */
if (i == fci->pointer_count + aflag && wanted_type != 0
&& TREE_CODE (cur_type) != ERROR_MARK
&& wanted_type != TYPE_MAIN_VARIANT (cur_type)
/* If we want `void *', allow any pointer type.
(Anything else would already have got a warning.) */
(Anything else would already have got a warning.)
With -pedantic, only allow pointers to void and to character
types.
*/
&& ! (wanted_type == void_type_node
&& fci->pointer_count > 0)
/* Don't warn about differences merely in signedness. */
&& fci->pointer_count > 0
&& (! pedantic
|| TYPE_MAIN_VARIANT (cur_type) == void_type_node
|| char_type_flag))
/* Don't warn about differences merely in signedness, unless
-pedantic. With -pedantic, warn if the type is a pointer
target and not a character type, and for character types at
a second level of indirection.
*/
&& !(TREE_CODE (wanted_type) == INTEGER_TYPE
&& TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE
&& (! pedantic || i == 0 || (i == 1 && char_type_flag))
&& (TREE_UNSIGNED (wanted_type)
? wanted_type == (cur_type = unsigned_type (cur_type))
: wanted_type == (cur_type = signed_type (cur_type))))
/* Likewise, "signed char", "unsigned char" and "char" are
equivalent but the above test won't consider them equivalent. */
&& ! (wanted_type == char_type_node
&& (! pedantic || i < 2)
&& (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
|| TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node)))
{

View File

@ -179,6 +179,10 @@ extern int warn_format;
extern int flag_traditional;
/* Nonzero means enable C89 Amendment 1 features, other than digraphs. */
extern int flag_isoc94;
/* Nonzero means use the ISO C99 dialect of C. */
extern int flag_isoc99;

View File

@ -330,6 +330,10 @@ int flag_no_nonansi_builtin;
int flag_traditional;
/* Nonzero means enable C89 Amendment 1 features, other than digraphs. */
int flag_isoc94 = 0;
/* Nonzero means use the ISO C99 dialect of C. */
int flag_isoc99 = 0;
@ -541,6 +545,7 @@ c_decode_option (argc, argv)
{
iso_1990:
flag_digraphs = 0;
flag_isoc94 = 0;
iso_1990_digraphs:
flag_traditional = 0;
flag_writable_strings = 0;
@ -551,7 +556,7 @@ c_decode_option (argc, argv)
else if (!strcmp (argstart, "iso9899:199409"))
{
flag_digraphs = 1;
/* ??? The other changes since ISO C 1990 are not supported. */
flag_isoc94 = 1;
goto iso_1990_digraphs;
}
else if (!strcmp (argstart, "iso9899:199x")
@ -565,6 +570,7 @@ c_decode_option (argc, argv)
flag_no_nonansi_builtin = 1;
flag_isoc99 = 1;
flag_digraphs = 1;
flag_isoc94 = 1;
}
else if (!strcmp (argstart, "gnu89"))
{
@ -574,6 +580,7 @@ c_decode_option (argc, argv)
flag_no_nonansi_builtin = 0;
flag_isoc99 = 0;
flag_digraphs = 1;
flag_isoc94 = 0;
}
else if (!strcmp (argstart, "gnu9x") || !strcmp (argstart, "gnu99"))
{
@ -583,6 +590,7 @@ c_decode_option (argc, argv)
flag_no_nonansi_builtin = 0;
flag_isoc99 = 1;
flag_digraphs = 1;
flag_isoc94 = 1;
}
else
error ("unknown C standard `%s'", argstart);

View File

@ -1,3 +1,7 @@
2000-08-04 Joseph S. Myers <jsm28@cam.ac.uk>
* decl.c (flag_isoc94): New variable.
2000-08-02 Jason Merrill <jason@redhat.com>
* pt.c (do_type_instantiation): Add complain parm; don't complain

View File

@ -337,6 +337,10 @@ struct named_label_list
tree current_function_return_value;
/* Nonzero means use the ISO C94 dialect of C. */
int flag_isoc94;
/* Nonzero means use the ISO C99 dialect of C. */
int flag_isoc99;

View File

@ -1,3 +1,7 @@
2000-08-04 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/c90-printf-1.c, gcc.dg/c94-printf-1.c: New tests.
2000-08-03 Zack Weinberg <zack@wolery.cumb.org>
* gcc.dg/cpp/20000625-2.c: Don't expect a warning on line 4.

View File

@ -0,0 +1,247 @@
/* Test for printf formats. Formats using C90 features, including cases
where C90 specifies some aspect of the format to be ignored or where
the behaviour is undefined.
*/
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
typedef __WCHAR_TYPE__ wchar_t;
#ifndef __WINT_TYPE__
#define __WINT_TYPE__ unsigned int
#endif
typedef __WINT_TYPE__ wint_t;
__extension__ typedef long long int llong;
__extension__ typedef unsigned long long int ullong;
extern int printf (const char *, ...);
#define NULL ((void *)0)
void
foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
int *n, short int *hn, long int l, unsigned long int ul,
long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
ullong ull, unsigned int *un, const int *cn, signed char *ss,
unsigned char *us, const signed char *css, unsigned int u1,
unsigned int u2)
{
/* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134). */
/* Basic sanity checks for the different components of a format. */
printf ("%d\n", i);
printf ("%+d\n", i);
printf ("%3d\n", i);
printf ("%-3d\n", i);
printf ("%.7d\n", i);
printf ("%+9.4d\n", i);
printf ("%.3ld\n", l);
printf ("%*d\n", i1, i);
printf ("%.*d\n", i2, i);
printf ("%*.*ld\n", i1, i2, l);
printf ("%d %lu\n", i, ul);
/* GCC has objected to the next one in the past, but it is a valid way
of specifying zero precision.
*/
printf ("%.e\n", d); /* { dg-bogus "precision" "bogus precision warning" } */
/* Bogus use of width. */
printf ("%5n\n", n); /* { dg-warning "width" "width with %n" } */
/* Erroneous, ignored or pointless constructs with precision. */
/* Whether negative values for precision may be included in the format
string is not entirely clear; presume not, following Clive Feather's
proposed resolution to DR#220 against C99. In any case, such a
construct should be warned about.
*/
printf ("%.-5d\n", i); /* { dg-warning "format|precision" "negative precision warning" } */
printf ("%.-*d\n", i); /* { dg-warning "format" "broken %.-*d format" } */
printf ("%.3c\n", i); /* { dg-warning "precision" "precision with %c" } */
printf ("%.3p\n", p); /* { dg-warning "precision" "precision with %p" } */
printf ("%.3n\n", n); /* { dg-warning "precision" "precision with %n" } */
/* Valid and invalid %% constructions. Some of the warning messages
are non-optimal, but they do detect the errorneous nature of the
format string.
*/
printf ("%%");
printf ("%.3%"); /* { dg-warning "format" "bogus %%" } */
printf ("%-%"); /* { dg-warning "format" "bogus %%" } */
printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
printf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
/* Valid and invalid %h, %l, %L constructions. */
printf ("%hd", i);
printf ("%hi", i);
/* Strictly, these parameters should be int or unsigned int according to
what unsigned short promotes to. However, GCC ignores sign
differences in format checking here, and this is relied on to get the
correct checking without print_char_table needing to know whether
int and short are the same size.
*/
printf ("%ho%hu%hx%hX", u, u, u, u);
printf ("%hn", hn);
printf ("%hf", d); /* { dg-warning "length character" "bad use of %h" } */
printf ("%he", d); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hE", d); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hg", d); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hG", d); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hc", i); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hs", s); /* { dg-warning "length character" "bad use of %h" } */
printf ("%hp", p); /* { dg-warning "length character" "bad use of %h" } */
printf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
printf ("%h."); /* { dg-warning "conversion" "bogus %h." } */
printf ("%ld%li%lo%lu%lx%lX", l, l, ul, ul, ul, ul);
printf ("%ln", ln);
printf ("%lf", d); /* { dg-warning "length character|C" "bad use of %l" } */
printf ("%le", d); /* { dg-warning "length character|C" "bad use of %l" } */
printf ("%lE", d); /* { dg-warning "length character|C" "bad use of %l" } */
printf ("%lg", d); /* { dg-warning "length character|C" "bad use of %l" } */
printf ("%lG", d); /* { dg-warning "length character|C" "bad use of %l" } */
printf ("%lp", p); /* { dg-warning "length character|C" "bad use of %l" } */
/* These next two were added in C94, but should be objected to in C90.
For the first one, GCC has wanted wchar_t instead of the correct C94
and C99 wint_t.
*/
printf ("%lc", lc); /* { dg-warning "length character|C" "C90 bad use of %l" } */
printf ("%ls", ls); /* { dg-warning "length character|C" "C90 bad use of %l" } */
/* These uses of %L are legitimate, though GCC has wrongly warned for
them in the past.
*/
printf ("%Le%LE%Lf%Lg%LG", ld, ld, ld, ld, ld);
/* These next six are accepted by GCC as referring to long long,
but -pedantic correctly warns.
*/
printf ("%Ld", ll); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%Li", ll); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%Lo", ull); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%Lu", ull); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%Lx", ull); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%LX", ull); /* { dg-warning "does not support" "bad use of %L" } */
printf ("%Lc", i); /* { dg-warning "length character" "bad use of %L" } */
printf ("%Ls", s); /* { dg-warning "length character" "bad use of %L" } */
printf ("%Lp", p); /* { dg-warning "length character" "bad use of %L" } */
printf ("%Ln", n); /* { dg-warning "length character" "bad use of %L" } */
/* Valid uses of each bare conversion. */
printf ("%d%i%o%u%x%X%f%e%E%g%G%c%s%p%n%%", i, i, u, u, u, u, d, d, d, d, d,
i, s, p, n);
/* Uses of the - flag (valid on all non-%, non-n conversions). */
printf ("%-d%-i%-o%-u%-x%-X%-f%-e%-E%-g%-G%-c%-s%-p", i, i, u, u, u, u,
d, d, d, d, d, i, s, p);
printf ("%-n", n); /* { dg-warning "flag" "bad use of %-n" } */
/* Uses of the + flag (valid on signed conversions only). */
printf ("%+d%+i%+f%+e%+E%+g%+G\n", i, i, d, d, d, d, d);
printf ("%+o", u); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+u", u); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+x", u); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+X", u); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+c", i); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+s", s); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+p", p); /* { dg-warning "flag" "bad use of + flag" } */
printf ("%+n", n); /* { dg-warning "flag" "bad use of + flag" } */
/* Uses of the space flag (valid on signed conversions only, and ignored
with +).
*/
printf ("% +d", i); /* { dg-warning "use of both" "use of space and + flags" } */
printf ("%+ d", i); /* { dg-warning "use of both" "use of space and + flags" } */
printf ("% d% i% f% e% E% g% G\n", i, i, d, d, d, d, d);
printf ("% o", u); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% u", u); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% x", u); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% X", u); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% c", i); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% s", s); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% p", p); /* { dg-warning "flag" "bad use of space flag" } */
printf ("% n", n); /* { dg-warning "flag" "bad use of space flag" } */
/* Uses of the # flag. */
printf ("%#o%#x%#X%#e%#E%#f%#g%#G", u, u, u, d, d, d, d, d);
printf ("%#d", i); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#i", i); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#u", u); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#c", i); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#s", s); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#p", p); /* { dg-warning "flag" "bad use of # flag" } */
printf ("%#n", n); /* { dg-warning "flag" "bad use of # flag" } */
/* Uses of the 0 flag. */
printf ("%08d%08i%08o%08u%08x%08X%08e%08E%08f%08g%08G", i, i, u, u, u, u,
d, d, d, d, d);
printf ("%0c", i); /* { dg-warning "flag" "bad use of 0 flag" } */
printf ("%0s", s); /* { dg-warning "flag" "bad use of 0 flag" } */
printf ("%0p", p); /* { dg-warning "flag" "bad use of 0 flag" } */
printf ("%0n", n); /* { dg-warning "flag" "bad use of 0 flag" } */
/* 0 flag ignored with precision for certain types, not others. */
printf ("%08.5d", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5i", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5o", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5u", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5x", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5X", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
printf ("%08.5f%08.5e%08.5E%08.5g%08.5G", d, d, d, d, d);
/* 0 flag ignored with - flag. */
printf ("%-08d", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08i", i); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08o", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08u", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08x", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08X", u); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08e", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08E", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08f", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08g", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
printf ("%-08G", d); /* { dg-warning "flags" "0 flag ignored with - flag" } */
/* Various tests of bad argument types. */
printf ("%d", l); /* { dg-warning "format" "bad argument types" } */
printf ("%*.*d", l, i2, i); /* { dg-warning "field" "bad * argument types" } */
printf ("%*.*d", i1, l, i); /* { dg-warning "field" "bad * argument types" } */
printf ("%ld", i); /* { dg-warning "format" "bad argument types" } */
printf ("%s", n); /* { dg-warning "format" "bad argument types" } */
printf ("%p", i); /* { dg-warning "format" "bad argument types" } */
printf ("%n", p); /* { dg-warning "format" "bad argument types" } */
/* With -pedantic, we want some further checks for pointer targets:
%p should allow only pointers to void (possibly qualified) and
to character types (possibly qualified), but not function pointers
or pointers to other types. (Whether, in fact, character types are
allowed here is unclear; see thread on comp.std.c, July 2000 for
discussion of the requirements of rules on identical representation,
and of the application of the as if rule with the new va_arg
allowances in C99 to printf.) Likewise, we should warn if
pointer targets differ in signedness, except in some circumstances
for character pointers. (In C99 we should consider warning for
char * or unsigned char * being passed to %hhn, even if strictly
legitimate by the standard.)
*/
printf ("%p", foo); /* { dg-warning "format" "bad argument types" } */
printf ("%n", un); /* { dg-warning "format" "bad argument types" } */
printf ("%p", n); /* { dg-warning "format" "bad argument types" } */
/* Allow character pointers with %p. */
printf ("%p%p%p%p", s, ss, us, css);
/* %s allows any character type. */
printf ("%s%s%s%s", s, ss, us, css);
/* Warning for void * arguments for %s is GCC's historical behaviour,
and seems useful to keep, even if some standard versions might be
read to permit it.
*/
printf ("%s", p); /* { dg-warning "format" "bad argument types" } */
/* The historical behaviour is to allow signed / unsigned types
interchangably as arguments. For values representable in both types,
such usage may be correct. For now preserve the behaviour of GCC
in such cases.
*/
printf ("%d", u);
/* Also allow the same for width and precision arguments. In the past,
GCC has been inconsistent and allowed unsigned for width but not
precision.
*/
printf ("%*.*d", u1, u2, i);
/* Wrong number of arguments. */
printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
printf ("%d", i, i); /* { dg-warning "arguments" "wrong number of args" } */
/* Miscellaneous bogus constructions. */
printf (""); /* { dg-warning "zero-length" "warning for empty format" } */
printf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
printf ("%d\0", i); /* { dg-warning "embedded" "warning for embedded NUL" } */
printf ("%d\0%d", i, i); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
printf (NULL); /* { dg-warning "null" "null format string warning" } */
printf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
printf ("%++d", i); /* { dg-warning "repeated" "repeated flag warning" } */
printf ("%n", cn); /* { dg-warning "constant" "%n with const" } */
/* Can we test for the warning for unterminated string formats? */
}

View File

@ -0,0 +1,25 @@
/* Test for printf formats. Changes in C94 to C90. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
typedef __WCHAR_TYPE__ wchar_t;
#ifndef __WINT_TYPE__
#define __WINT_TYPE__ unsigned int
#endif
typedef __WINT_TYPE__ wint_t;
extern int printf (const char *, ...);
void
foo (wint_t lc, wchar_t *ls)
{
/* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
We do not repeat here all the C90 format checks, but just verify
that %ls and %lc are accepted without warning.
*/
printf ("%lc", lc);
printf ("%ls", ls);
}