From 5804a754e51fe8a475bb701a57997ee0cdb51fc0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 21 Aug 2000 20:38:35 +0100 Subject: [PATCH] c-common.c (init_dollar_format_checking, [...]): New functions. * c-common.c (init_dollar_format_checking, maybe_read_dollar_number, finish_dollar_format_checking): New functions. (dollar_arguments_used, dollar_arguments_count, dollar_first_arg_num, dollar_max_arg_used, dollar_format_warned): New variables. (check_format_info): Support $ formats for scanf and printf width and precision. Always increment format_chars to advance past the '*' of precision, not just when the format parameters are available to check. testsuite: * gcc.dg/c90-printf-3.c, gcc.dg/c90-scanf-2.c, gcc.dg/c90-scanf-3.c, gcc.dg/c90-scanf-4.c, gcc.dg/c90-strftime-1.c, gcc.dg/c99-printf-3.c, gcc.dg/c99-scanf-1.c, gcc.dg/c99-scanf-2.c, gcc.dg/c99-scanf-3.c, gcc.dg/format-xopen-1.c: New tests. From-SVN: r35856 --- gcc/ChangeLog | 13 ++ gcc/c-common.c | 268 +++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 8 + gcc/testsuite/gcc.dg/c90-printf-3.c | 60 ++++++ gcc/testsuite/gcc.dg/c90-scanf-2.c | 37 ++++ gcc/testsuite/gcc.dg/c90-scanf-3.c | 21 ++ gcc/testsuite/gcc.dg/c90-scanf-4.c | 51 +++++ gcc/testsuite/gcc.dg/c90-strftime-1.c | 23 +++ gcc/testsuite/gcc.dg/c99-printf-3.c | 56 ++++++ gcc/testsuite/gcc.dg/c99-scanf-1.c | 165 ++++++++++++++++ gcc/testsuite/gcc.dg/c99-scanf-2.c | 27 +++ gcc/testsuite/gcc.dg/c99-scanf-3.c | 49 +++++ gcc/testsuite/gcc.dg/format-xopen-1.c | 118 ++++++++++++ 13 files changed, 864 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c90-printf-3.c create mode 100644 gcc/testsuite/gcc.dg/c90-scanf-2.c create mode 100644 gcc/testsuite/gcc.dg/c90-scanf-3.c create mode 100644 gcc/testsuite/gcc.dg/c90-scanf-4.c create mode 100644 gcc/testsuite/gcc.dg/c90-strftime-1.c create mode 100644 gcc/testsuite/gcc.dg/c99-printf-3.c create mode 100644 gcc/testsuite/gcc.dg/c99-scanf-1.c create mode 100644 gcc/testsuite/gcc.dg/c99-scanf-2.c create mode 100644 gcc/testsuite/gcc.dg/c99-scanf-3.c create mode 100644 gcc/testsuite/gcc.dg/format-xopen-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0f09fa1628c..a800469bff0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2000-08-21 Joseph S. Myers + + * c-common.c (init_dollar_format_checking, + maybe_read_dollar_number, finish_dollar_format_checking): New + functions. + (dollar_arguments_used, dollar_arguments_count, + dollar_first_arg_num, dollar_max_arg_used, dollar_format_warned): + New variables. + (check_format_info): Support $ formats for scanf and printf width + and precision. Always increment format_chars to advance past the + '*' of precision, not just when the format parameters are + available to check. + 2000-08-21 Kaveh R. Ghazi * mips.c (block_move_loop, expand_block_move, diff --git a/gcc/c-common.c b/gcc/c-common.c index c0b9816c301..5e46af0c1c8 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1324,6 +1324,11 @@ static international_format_info *international_format_list = NULL; static void check_format_info PARAMS ((function_format_info *, tree)); +static void init_dollar_format_checking PARAMS ((int, tree)); +static int maybe_read_dollar_number PARAMS ((const char **, int, + tree, tree *)); +static void finish_dollar_format_checking PARAMS ((void)); + /* Initialize the table of functions to perform format checking on. The ISO C functions are always checked (whether is included or not), since it is common to call printf without @@ -1501,6 +1506,169 @@ check_function_format (name, assembler_name, params) } } + +/* Variables used by the checking of $ operand number formats. */ +static char *dollar_arguments_used = NULL; +static int dollar_arguments_alloc = 0; +static int dollar_arguments_count; +static int dollar_first_arg_num; +static int dollar_max_arg_used; +static int dollar_format_warned; + +/* Initialize the checking for a format string that may contain $ + parameter number specifications; we will need to keep track of whether + each parameter has been used. FIRST_ARG_NUM is the number of the first + argument that is a parameter to the format, or 0 for a vprintf-style + function; PARAMS is the list of arguments starting at this argument. */ + +static void +init_dollar_format_checking (first_arg_num, params) + int first_arg_num; + tree params; +{ + dollar_first_arg_num = first_arg_num; + dollar_arguments_count = 0; + dollar_max_arg_used = 0; + dollar_format_warned = 0; + if (first_arg_num > 0) + { + while (params) + { + dollar_arguments_count++; + params = TREE_CHAIN (params); + } + } + if (dollar_arguments_alloc < dollar_arguments_count) + { + if (dollar_arguments_used) + free (dollar_arguments_used); + dollar_arguments_alloc = dollar_arguments_count; + dollar_arguments_used = xmalloc (dollar_arguments_alloc); + } + if (dollar_arguments_alloc) + memset (dollar_arguments_used, 0, dollar_arguments_alloc); +} + + +/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED + is set, it is an error if one is not found; otherwise, it is OK. If + such a number is found, check whether it is within range and mark that + numbered operand as being used for later checking. Returns the operand + number if found and within range, zero if no such number was found and + this is OK, or -1 on error. PARAMS points to the first operand of the + format; PARAM_PTR is made to point to the parameter referred to. If + a $ format is found, *FORMAT is updated to point just after it. */ + +static int +maybe_read_dollar_number (format, dollar_needed, params, param_ptr) + const char **format; + int dollar_needed; + tree params; + tree *param_ptr; +{ + int argnum; + int overflow_flag; + const char *fcp = *format; + if (*fcp < '0' || *fcp > '9') + { + if (dollar_needed) + { + warning ("missing $ operand number in format"); + return -1; + } + else + return 0; + } + argnum = 0; + overflow_flag = 0; + while (*fcp >= '0' && *fcp <= '9') + { + int nargnum; + nargnum = 10 * argnum + (*fcp - '0'); + if (nargnum < 0 || nargnum / 10 != argnum) + overflow_flag = 1; + argnum = nargnum; + fcp++; + } + if (*fcp != '$') + { + if (dollar_needed) + { + warning ("missing $ operand number in format"); + return -1; + } + else + return 0; + } + *format = fcp + 1; + if (pedantic && !dollar_format_warned) + { + warning ("ISO C does not support %%n$ operand number formats"); + dollar_format_warned = 1; + } + if (overflow_flag || argnum == 0 + || (dollar_first_arg_num && argnum > dollar_arguments_count)) + { + warning ("operand number out of range in format"); + return -1; + } + if (argnum > dollar_max_arg_used) + dollar_max_arg_used = argnum; + /* For vprintf-style functions we may need to allocate more memory to + track which arguments are used. */ + while (dollar_arguments_alloc < dollar_max_arg_used) + { + int nalloc; + nalloc = 2 * dollar_arguments_alloc + 16; + dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc); + memset (dollar_arguments_used + dollar_arguments_alloc, 0, + nalloc - dollar_arguments_alloc); + dollar_arguments_alloc = nalloc; + } + dollar_arguments_used[argnum - 1] = 1; + if (dollar_first_arg_num) + { + int i; + *param_ptr = params; + for (i = 1; i < argnum && *param_ptr != 0; i++) + *param_ptr = TREE_CHAIN (*param_ptr); + + if (*param_ptr == 0) + { + /* This case shouldn't be caught here. */ + abort (); + } + } + else + *param_ptr = 0; + return argnum; +} + + +/* Finish the checking for a format string that used $ operand number formats + instead of non-$ formats. We check for unused operands before used ones + (a serious error, since the implementation of the format function + can't know what types to pass to va_arg to find the later arguments). + and for unused operands at the end of the format (if we know how many + arguments the format had, so not for vprintf). If there were operand + numbers out of range on a non-vprintf-style format, we won't have reached + here. */ + +static void +finish_dollar_format_checking () +{ + int i; + for (i = 0; i < dollar_max_arg_used; i++) + { + if (!dollar_arguments_used[i]) + warning ("format argument %d unused before used argument %d in $-style format", + i + 1, dollar_max_arg_used); + } + if (dollar_first_arg_num && dollar_max_arg_used < dollar_arguments_count) + warning ("unused arguments in $-style format"); +} + + /* Check the argument list of a call to printf, scanf, etc. INFO points to the function_format_info structure. PARAMS is the list of argument values. */ @@ -1524,7 +1692,9 @@ check_format_info (info, params) const char *format_chars; format_char_info *fci = NULL; char flag_chars[8]; - int has_operand_number = 0; + /* -1 if no conversions taking an operand have been found; 0 if one has + and it didn't use $; 1 if $ formats are in use. */ + int has_operand_number = -1; /* Skip to format argument. If the argument isn't available, there's no work for us to do; prototype checking will catch the problem. */ @@ -1624,6 +1794,7 @@ check_format_info (info, params) } first_fillin_param = params; + init_dollar_format_checking (info->first_arg_num, first_fillin_param); while (1) { int aflag; @@ -1633,8 +1804,11 @@ check_format_info (info, params) { if (format_chars - TREE_STRING_POINTER (format_tree) != format_length) warning ("embedded `\\0' in format"); - if (info->first_arg_num != 0 && params != 0 && ! has_operand_number) + if (info->first_arg_num != 0 && params != 0 + && has_operand_number <= 0) warning ("too many arguments for format"); + if (has_operand_number > 0) + finish_dollar_format_checking (); return; } if (*format_chars++ != '%') @@ -1657,6 +1831,22 @@ check_format_info (info, params) suppressed = *format_chars == '*'; if (suppressed) ++format_chars; + else if (has_operand_number != 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, ¶ms); + if (opnum == -1) + return; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } while (ISDIGIT (*format_chars)) { wide = TRUE; @@ -1709,35 +1899,21 @@ check_format_info (info, params) } 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. */ - if (*format_chars >= '0' && *format_chars <= '9') + if (has_operand_number != 0) { - const char *p = format_chars; - - while (*p >= '0' && *p++ <= '9') - ; - - if (*p == '$') + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, ¶ms); + if (opnum == -1) + return; + else if (opnum > 0) { - int opnum = atoi (format_chars); - - if (pedantic) - warning ("ISO C does not support printf %%n$"); - - params = first_fillin_param; - format_chars = p + 1; has_operand_number = 1; - - for (i = 1; i < opnum && params != 0; i++) - params = TREE_CHAIN (params); - - if (opnum == 0 || params == 0) - { - warning ("operand number out of range in format"); - return; - } + arg_num = opnum + info->first_arg_num - 1; } + else + has_operand_number = 0; } while (*format_chars != 0 && index (" +#0-'", *format_chars) != 0) @@ -1774,11 +1950,25 @@ check_format_info (info, params) tfaff (); return; } + if (has_operand_number > 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, 1, + first_fillin_param, + ¶ms); + if (opnum <= 0) + return; + else + arg_num = opnum + info->first_arg_num - 1; + } if (info->first_arg_num != 0) { cur_param = TREE_VALUE (params); - params = TREE_CHAIN (params); - ++arg_num; + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } /* size_t is generally not valid here. It will work on most machines, because size_t and int have the same mode. But might as well warn anyway, @@ -1807,17 +1997,31 @@ check_format_info (info, params) In this case, an int argument supplies the...precision." */ if (*format_chars == '*') { + ++format_chars; + if (has_operand_number > 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, 1, + first_fillin_param, + ¶ms); + if (opnum <= 0) + return; + else + arg_num = opnum + info->first_arg_num - 1; + } if (info->first_arg_num != 0) { - ++format_chars; if (params == 0) { tfaff (); return; } cur_param = TREE_VALUE (params); - params = TREE_CHAIN (params); - ++arg_num; + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) != integer_type_node) && diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c94de4dbe9e..1293a6c4c64 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2000-08-21 Joseph S. Myers + + * gcc.dg/c90-printf-3.c, gcc.dg/c90-scanf-2.c, + gcc.dg/c90-scanf-3.c, gcc.dg/c90-scanf-4.c, + gcc.dg/c90-strftime-1.c, gcc.dg/c99-printf-3.c, + gcc.dg/c99-scanf-1.c, gcc.dg/c99-scanf-2.c, gcc.dg/c99-scanf-3.c, + gcc.dg/format-xopen-1.c: New tests. + 2000-08-21 Joseph S. Myers * gcc.dg/c90-scanf-1.c, gcc.dg/c94-scanf-1.c: New tests. diff --git a/gcc/testsuite/gcc.dg/c90-printf-3.c b/gcc/testsuite/gcc.dg/c90-printf-3.c new file mode 100644 index 00000000000..119cdeeffff --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-printf-3.c @@ -0,0 +1,60 @@ +/* Test for printf formats. Test that the C90 functions get their default + attributes in strict C90 mode, but the C99 and gettext functions + do not. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */ + +/* This may not be correct in the particular case, but allows the + prototypes to be declared, and we don't try to link. +*/ +typedef struct _FILE FILE; +extern FILE *stdout; + +typedef __SIZE_TYPE__ size_t; +typedef __builtin_va_list va_list; + +extern int fprintf (FILE *, const char *, ...); +extern int printf (const char *, ...); +extern int sprintf (char *, const char *, ...); +extern int vfprintf (FILE *, const char *, va_list); +extern int vprintf (const char *, va_list); +extern int vsprintf (char *, const char *, va_list); + +extern int snprintf (char *, size_t, const char *, ...); +extern int vsnprintf (char *, size_t, const char *, va_list); + +extern char *gettext (const char *); +extern char *dgettext (const char *, const char *); +extern char *dcgettext (const char *, const char *, int); + +void +foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3, + va_list v4, va_list v5, va_list v6, va_list v7, va_list v8) +{ + fprintf (stdout, "%d", i); + fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */ + printf ("%d", i); + printf ("%ld", i); /* { dg-warning "format" "printf" } */ + sprintf (s, "%d", i); + sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */ + vfprintf (stdout, "%d", v0); + vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */ + vprintf ("%d", v2); + vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */ + /* The following used to give a bogus warning. */ + vprintf ("%*.*d", v8); + vsprintf (s, "%d", v4); + vsprintf (s, "%Y", v5); /* { dg-warning "format" "vsprintf" } */ + snprintf (s, n, "%d", i); + snprintf (s, n, "%ld", i); + vsnprintf (s, n, "%d", v6); + vsnprintf (s, n, "%Y", v7); + printf (gettext ("%d"), i); + printf (gettext ("%ld"), i); + printf (dgettext ("", "%d"), i); + printf (dgettext ("", "%ld"), i); + printf (dcgettext ("", "%d", 0), i); + printf (dcgettext ("", "%ld", 0), i); +} diff --git a/gcc/testsuite/gcc.dg/c90-scanf-2.c b/gcc/testsuite/gcc.dg/c90-scanf-2.c new file mode 100644 index 00000000000..c0a7a702664 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-scanf-2.c @@ -0,0 +1,37 @@ +/* Test for scanf formats. Formats using C99 features should be rejected + outside of C99 mode. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */ + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; + +__extension__ typedef long long int llong; + +/* This next definition is broken. When GCC has a and + an internal understanding of intmax_t, it should be + replaced by an include of or by a definition for internal + macros or typedefs. +*/ +__extension__ typedef long long int intmax_t; + +extern int scanf (const char *, ...); + +void +foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp, + size_t *zp, ptrdiff_t *tp) +{ + /* Some tests already in c90-scanf-1.c. */ + /* The widths hh, ll, j, z, t are new. */ + scanf ("%hhd", hhp); /* { dg-warning "length character|C" "%hh in C90" } */ + scanf ("%lld", llp); /* { dg-warning "length character|C" "%ll in C90" } */ + scanf ("%jd", jp); /* { dg-warning "length character|C" "%j in C90" } */ + scanf ("%zu", zp); /* { dg-warning "length character|C" "%z in C90" } */ + scanf ("%td", tp); /* { dg-warning "length character|C" "%t in C90" } */ + /* The formats F, a, A are new. */ + scanf ("%F", fp); /* { dg-warning "C" "%F in C90" } */ + scanf ("%a", fp); /* { dg-warning "C" "%a in C90" } */ + scanf ("%A", fp); /* { dg-warning "C" "%A in C90" } */ +} diff --git a/gcc/testsuite/gcc.dg/c90-scanf-3.c b/gcc/testsuite/gcc.dg/c90-scanf-3.c new file mode 100644 index 00000000000..147a22254f6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-scanf-3.c @@ -0,0 +1,21 @@ +/* Test for scanf formats. Formats using extensions to the standard + should be rejected in strict pedantic mode. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */ + +typedef __WCHAR_TYPE__ wchar_t; + +extern int scanf (const char *, ...); + +void +foo (char **sp, wchar_t **lsp) +{ + /* %a formats for allocation, only recognised in C90 mode, are a + GNU extension. + */ + scanf ("%as", sp); /* { dg-warning "C" "%as" } */ + scanf ("%aS", lsp); /* { dg-warning "C" "%aS" } */ + scanf ("%a[bcd]", sp); /* { dg-warning "C" "%a[]" } */ +} diff --git a/gcc/testsuite/gcc.dg/c90-scanf-4.c b/gcc/testsuite/gcc.dg/c90-scanf-4.c new file mode 100644 index 00000000000..3bbe66e598b --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-scanf-4.c @@ -0,0 +1,51 @@ +/* Test for scanf formats. Test that the C90 functions get their default + attributes in strict C90 mode, but the C99 and gettext functions + do not. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */ + +/* This may not be correct in the particular case, but allows the + prototypes to be declared, and we don't try to link. +*/ +typedef struct _FILE FILE; +extern FILE *stdin; + +typedef __builtin_va_list va_list; + +extern int fscanf (FILE *, const char *, ...); +extern int scanf (const char *, ...); +extern int sscanf (const char *, const char *, ...); + +extern int vfscanf (FILE *, const char *, va_list); +extern int vscanf (const char *, va_list); +extern int vsscanf (const char *, const char *, va_list); + +extern char *gettext (const char *); +extern char *dgettext (const char *, const char *); +extern char *dcgettext (const char *, const char *, int); + +void +foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3, + va_list v4, va_list v5) +{ + fscanf (stdin, "%d", ip); + fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */ + scanf ("%d", ip); + scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */ + sscanf (s, "%d", ip); + sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */ + vfscanf (stdin, "%d", v0); + vfscanf (stdin, "%Y", v1); + vscanf ("%d", v2); + vscanf ("%Y", v3); + vsscanf (s, "%d", v4); + vsscanf (s, "%Y", v5); + scanf (gettext ("%d"), ip); + scanf (gettext ("%ld"), ip); + scanf (dgettext ("", "%d"), ip); + scanf (dgettext ("", "%ld"), ip); + scanf (dcgettext ("", "%d", 0), ip); + scanf (dcgettext ("", "%ld", 0), ip); +} diff --git a/gcc/testsuite/gcc.dg/c90-strftime-1.c b/gcc/testsuite/gcc.dg/c90-strftime-1.c new file mode 100644 index 00000000000..6a13d5e321e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-strftime-1.c @@ -0,0 +1,23 @@ +/* Test for strftime formats. Formats using C90 features. */ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */ + +typedef __SIZE_TYPE__ size_t; + +struct tm; + +extern size_t strftime (char *, size_t, const char *, const struct tm *); + +void +foo (char *s, size_t m, const struct tm *tp) +{ + /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175). */ + /* Formats which are Y2K-compliant (no 2-digit years). */ + strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp); + /* Formats with 2-digit years. */ + strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */ + /* Formats with 2-digit years in some locales. */ + strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */ + strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */ +} diff --git a/gcc/testsuite/gcc.dg/c99-printf-3.c b/gcc/testsuite/gcc.dg/c99-printf-3.c new file mode 100644 index 00000000000..26f76d7f830 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-printf-3.c @@ -0,0 +1,56 @@ +/* Test for printf formats. Test that the C99 functions get their default + attributes in strict C99 mode, but the gettext functions do not. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */ + +/* This may not be correct in the particular case, but allows the + prototypes to be declared, and we don't try to link. +*/ +typedef struct _FILE FILE; +extern FILE *stdout; + +typedef __SIZE_TYPE__ size_t; +typedef __builtin_va_list va_list; + +extern int fprintf (FILE *restrict, const char *restrict, ...); +extern int printf (const char *restrict, ...); +extern int sprintf (char *restrict, const char *restrict, ...); +extern int vfprintf (FILE *restrict, const char *restrict, va_list); +extern int vprintf (const char *restrict, va_list); +extern int vsprintf (char *restrict, const char *restrict, va_list); +extern int snprintf (char *restrict, size_t, const char *restrict, ...); +extern int vsnprintf (char *restrict, size_t, const char *restrict, va_list); + +extern char *gettext (const char *); +extern char *dgettext (const char *, const char *); +extern char *dcgettext (const char *, const char *, int); + +void +foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3, + va_list v4, va_list v5, va_list v6, va_list v7) +{ + fprintf (stdout, "%d", i); + fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */ + printf ("%d", i); + printf ("%ld", i); /* { dg-warning "format" "printf" } */ + sprintf (s, "%d", i); + sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */ + snprintf (s, n, "%d", i); + snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */ + vfprintf (stdout, "%d", v0); + vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */ + vprintf ("%d", v0); + vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */ + vsprintf (s, "%d", v0); + vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */ + vsnprintf (s, n, "%d", v0); + vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */ + printf (gettext ("%d"), i); + printf (gettext ("%ld"), i); + printf (dgettext ("", "%d"), i); + printf (dgettext ("", "%ld"), i); + printf (dcgettext ("", "%d", 0), i); + printf (dcgettext ("", "%ld", 0), i); +} diff --git a/gcc/testsuite/gcc.dg/c99-scanf-1.c b/gcc/testsuite/gcc.dg/c99-scanf-1.c new file mode 100644 index 00000000000..c0b4c14428e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-scanf-1.c @@ -0,0 +1,165 @@ +/* Test for scanf formats. Formats using C99 features, including cases + where C99 specifies some aspect of the format to be ignored or where + the behaviour is undefined. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */ + +typedef __WCHAR_TYPE__ wchar_t; +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; + +/* Kludges to get types corresponding to size_t and ptrdiff_t. */ +#define unsigned signed +typedef __SIZE_TYPE__ signed_size_t; +#undef unsigned +#define signed /* Type might or might not have explicit 'signed'. */ +typedef unsigned __PTRDIFF_TYPE__ unsigned_ptrdiff_t; +#undef signed + +/* These next definitions are broken. When GCC has a and + an internal understanding of intmax_t and uintmax_t, they should be + replaced by an include of or by definitions for internal + macros or typedefs, and the corresponding xfails removed. +*/ +typedef long long int intmax_t; +typedef unsigned long long int uintmax_t; + +extern int scanf (const char *, ...); + +void +foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp, + signed char *hhp, unsigned char *uhhp, long int *lp, + unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s, + void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls, + short int *hn, signed char *hhn, long int *ln, long long int *lln, + intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp, + signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp, + unsigned_ptrdiff_t *utp, ptrdiff_t *tn) +{ + /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288). + We do not repeat here most of the checks for correct C90 formats + or completely broken formats. + */ + /* Valid, invalid and silly assignment-suppression + and width constructions. + */ + scanf ("%*d%*i%*o%*u%*x%*X%*a%*A%*e%*E%*f%*F%*g%*G%*s%*[abc]%*c%*p"); + scanf ("%*2d%*8s%*3c"); + scanf ("%*n"); /* { dg-warning "suppress" "suppression of %n" } */ + scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */ + scanf ("%2d%3i%4o%5u%6x%7X%8a%9A%10e%11E%12f%13F%14g%15G%16s%3[abc]%4c%5p", + ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, fp, fp, fp, + s, s, s, pp); + scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */ + scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */ + /* Valid and invalid %h, %hh, %l, %ll, %j, %z, %t, %L constructions. */ + scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn); + scanf ("%ha", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hA", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%he", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hE", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hf", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hF", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hg", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hG", fp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hs", s); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%h[ac]", s); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hc", s); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hp", pp); /* { dg-warning "length character" "bad use of %h" } */ + scanf ("%hhd%hhi%hho%hhu%hhx%hhX%hhn", hhp, hhp, uhhp, uhhp, uhhp, uhhp, + hhn); + scanf ("%hha", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhA", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhe", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhE", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhf", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhF", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhg", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhG", fp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhs", s); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hh[ac]", s); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhc", s); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%hhp", pp); /* { dg-warning "length character" "bad use of %hh" } */ + scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln); + scanf ("%la%lA%le%lE%lf%lF%lg%lG", dp, dp, dp, dp, dp, dp, dp, dp); + scanf ("%lp", pp); /* { dg-warning "length character" "bad use of %l" } */ + scanf ("%ls", ls); + scanf ("%l[ac]", ls); + scanf ("%lc", ls); + scanf ("%lld%lli%llo%llu%llx%llX%lln", llp, llp, ullp, ullp, ullp, ullp, + lln); + scanf ("%lla", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llA", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%lle", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llE", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llf", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llF", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llg", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llG", fp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%lls", s); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%ll[ac]", s); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llc", s); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%llp", pp); /* { dg-warning "length character" "bad use of %ll" } */ + scanf ("%jd%ji%jo%ju%jx%jX%jn", jp, jp, ujp, ujp, ujp, ujp, jn); /* { dg-bogus "length character" "bogus %j warning" { xfail *-*-* } } */ + scanf ("%ja", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jA", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%je", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jE", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jf", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jF", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jg", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jG", fp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%js", s); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%j[ac]", s); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jc", s); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%jp", pp); /* { dg-warning "length character" "bad use of %j" } */ + scanf ("%zd%zi%zo%zu%zx%zX%zn", szp, szp, zp, zp, zp, zp, zn); + scanf ("%za", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zA", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%ze", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zE", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zf", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zF", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zg", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zG", fp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zs", s); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%z[ac]", s); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zc", s); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%zp", pp); /* { dg-warning "length character" "bad use of %z" } */ + scanf ("%td%ti%to%tu%tx%tX%tn", tp, tp, utp, utp, utp, utp, tn); + scanf ("%ta", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tA", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%te", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tE", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tf", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tF", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tg", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tG", fp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%ts", s); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%t[ac]", s); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tc", s); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%tp", pp); /* { dg-warning "length character" "bad use of %t" } */ + scanf ("%La%LA%Le%LE%Lf%LF%Lg%LG", ldp, ldp, ldp, ldp, ldp, ldp, ldp, ldp); + scanf ("%Ld", llp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%Li", llp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%Lo", ullp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%Lu", ullp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%Lx", ullp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%LX", ullp); /* { dg-warning "does not support" "bad use of %L" } */ + scanf ("%Ls", s); /* { dg-warning "length character" "bad use of %L" } */ + scanf ("%L[ac]", s); /* { dg-warning "length character" "bad use of %L" } */ + scanf ("%Lc", s); /* { dg-warning "length character" "bad use of %L" } */ + scanf ("%Lp", pp); /* { dg-warning "length character" "bad use of %L" } */ + scanf ("%Ln", n); /* { dg-warning "length character" "bad use of %L" } */ + /* Valid uses of each bare conversion. */ + scanf ("%d%i%o%u%x%X%a%A%e%E%f%F%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip, + uip, fp, fp, fp, fp, fp, fp, fp, fp, s, s, s, pp, n); + /* Assert that %as is not treated as an extension in C99 mode. */ + scanf ("%as", fp); + scanf ("%a[", fp); + /* Tests for bad argument types: pointer target sign with %hh. */ + scanf ("%hhd", uhhp); /* { dg-warning "format" "%hhd sign" } */ + scanf ("%hhu", hhp); /* { dg-warning "format" "%hhu sign" } */ +} diff --git a/gcc/testsuite/gcc.dg/c99-scanf-2.c b/gcc/testsuite/gcc.dg/c99-scanf-2.c new file mode 100644 index 00000000000..c769e6d6611 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-scanf-2.c @@ -0,0 +1,27 @@ +/* Test for scanf formats. Formats using extensions to the standard + should be rejected in strict pedantic mode. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */ + +typedef __SIZE_TYPE__ size_t; +typedef __WCHAR_TYPE__ wchar_t; + +extern int scanf (const char *, ...); + +void +foo (int *ip, long long int *llp, size_t *zp, wchar_t *ls) +{ + /* The length modifiers q, Z and L as applied to integer formats are + extensions. + */ + scanf ("%qd", llp); /* { dg-warning "C" "%q length" } */ + scanf ("%Ld", llp); /* { dg-warning "C" "%L length" } */ + scanf ("%Zu", zp); /* { dg-warning "C" "%Z length" } */ + /* The conversion specifiers C and S are X/Open extensions. */ + scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */ + scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */ + /* The use of operand number $ formats is an X/Open extension. */ + scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */ +} diff --git a/gcc/testsuite/gcc.dg/c99-scanf-3.c b/gcc/testsuite/gcc.dg/c99-scanf-3.c new file mode 100644 index 00000000000..df30c05df46 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-scanf-3.c @@ -0,0 +1,49 @@ +/* Test for scanf formats. Test that the C99 functions get their default + attributes in strict C99 mode, but the gettext functions do not. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */ + +/* This may not be correct in the particular case, but allows the + prototypes to be declared, and we don't try to link. +*/ +typedef struct _FILE FILE; +extern FILE *stdin; + +typedef __builtin_va_list va_list; + +extern int fscanf (FILE *restrict, const char *restrict, ...); +extern int scanf (const char *restrict, ...); +extern int sscanf (const char *restrict, const char *restrict, ...); +extern int vfscanf (FILE *restrict, const char *restrict, va_list); +extern int vscanf (const char *restrict, va_list); +extern int vsscanf (const char *restrict, const char *restrict, va_list); + +extern char *gettext (const char *); +extern char *dgettext (const char *, const char *); +extern char *dcgettext (const char *, const char *, int); + +void +foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3, + va_list v4, va_list v5) +{ + fscanf (stdin, "%d", ip); + fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */ + scanf ("%d", ip); + scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */ + sscanf (s, "%d", ip); + sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */ + vfscanf (stdin, "%d", v0); + vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */ + vscanf ("%d", v2); + vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */ + vsscanf (s, "%d", v4); + vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */ + scanf (gettext ("%d"), ip); + scanf (gettext ("%ld"), ip); + scanf (dgettext ("", "%d"), ip); + scanf (dgettext ("", "%ld"), ip); + scanf (dcgettext ("", "%d", 0), ip); + scanf (dcgettext ("", "%ld", 0), ip); +} diff --git a/gcc/testsuite/gcc.dg/format-xopen-1.c b/gcc/testsuite/gcc.dg/format-xopen-1.c new file mode 100644 index 00000000000..2bfcbfb941a --- /dev/null +++ b/gcc/testsuite/gcc.dg/format-xopen-1.c @@ -0,0 +1,118 @@ +/* Test for X/Open format extensions, as found in the + Single Unix Specification and in Austin Group draft 4, subject to some + Aardvark problem reports submitted. +*/ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -Wformat" } */ + +typedef __WCHAR_TYPE__ wchar_t; +typedef __WINT_TYPE__ wint_t; +typedef __builtin_va_list va_list; + +extern int printf (const char *, ...); +extern int vprintf (const char *, va_list); +extern int scanf (const char *, ...); + +void +foo (int i, unsigned int u, wint_t lc, wchar_t *ls, int *ip, double d, + char *s, void *p, int *n, long int l, int i2, float *fp, long int *lp, + va_list va) +{ + /* The conversion specifiers C and S, for both printf and scanf, + are X/Open extensions. + */ + printf ("%C", lc); + printf ("%3C", lc); + printf ("%.3C", lc); /* { dg-warning "precision" "precision with %C" } */ + printf ("%hC", lc); /* { dg-warning "length character" "bad %hC" } */ + printf ("%hhC", lc); /* { dg-warning "length character" "bad %hhC" } */ + printf ("%lC", lc); /* { dg-warning "length character" "bad %lC" } */ + printf ("%llC", lc); /* { dg-warning "length character" "bad %llC" } */ + printf ("%jC", lc); /* { dg-warning "length character" "bad %jC" } */ + printf ("%zC", lc); /* { dg-warning "length character" "bad %zC" } */ + printf ("%tC", lc); /* { dg-warning "length character" "bad %tC" } */ + printf ("%LC", lc); /* { dg-warning "length character" "bad %LC" } */ + printf ("%-C", lc); + printf ("%+C", lc); /* { dg-warning "flag" "bad %+C" } */ + printf ("% C", lc); /* { dg-warning "flag" "bad % C" } */ + printf ("%#C", lc); /* { dg-warning "flag" "bad %#C" } */ + printf ("%0C", lc); /* { dg-warning "flag" "bad %0C" } */ + printf ("%S", ls); + printf ("%3S", ls); + printf ("%.3S", ls); + printf ("%hS", ls); /* { dg-warning "length character" "bad %hS" } */ + printf ("%hhS", ls); /* { dg-warning "length character" "bad %hhS" } */ + printf ("%lS", ls); /* { dg-warning "length character" "bad %lS" } */ + printf ("%llS", ls); /* { dg-warning "length character" "bad %llS" } */ + printf ("%jS", ls); /* { dg-warning "length character" "bad %jS" } */ + printf ("%zS", ls); /* { dg-warning "length character" "bad %zS" } */ + printf ("%tS", ls); /* { dg-warning "length character" "bad %tS" } */ + printf ("%LS", ls); /* { dg-warning "length character" "bad %LS" } */ + printf ("%-S", ls); + printf ("%+S", ls); /* { dg-warning "flag" "bad %+S" } */ + printf ("% S", ls); /* { dg-warning "flag" "bad % S" } */ + printf ("%#S", ls); /* { dg-warning "flag" "bad %#S" } */ + printf ("%0S", ls); /* { dg-warning "flag" "bad %0S" } */ + scanf ("%C", ls); + scanf ("%S", ls); + scanf ("%*C%*S"); + scanf ("%2C%3S", ls, ls); + scanf ("%hC", ls); /* { dg-warning "length character" "bad %hC" } */ + scanf ("%hhC", ls); /* { dg-warning "length character" "bad %hhC" } */ + scanf ("%lC", ls); /* { dg-warning "length character" "bad %lC" } */ + scanf ("%llC", ls); /* { dg-warning "length character" "bad %llC" } */ + scanf ("%jC", ls); /* { dg-warning "length character" "bad %jC" } */ + scanf ("%zC", ls); /* { dg-warning "length character" "bad %zC" } */ + scanf ("%tC", ls); /* { dg-warning "length character" "bad %tC" } */ + scanf ("%LC", ls); /* { dg-warning "length character" "bad %LC" } */ + scanf ("%hS", ls); /* { dg-warning "length character" "bad %hS" } */ + scanf ("%hhS", ls); /* { dg-warning "length character" "bad %hhS" } */ + scanf ("%lS", ls); /* { dg-warning "length character" "bad %lS" } */ + scanf ("%llS", ls); /* { dg-warning "length character" "bad %llS" } */ + scanf ("%jS", ls); /* { dg-warning "length character" "bad %jS" } */ + scanf ("%zS", ls); /* { dg-warning "length character" "bad %zS" } */ + scanf ("%tS", ls); /* { dg-warning "length character" "bad %tS" } */ + scanf ("%LS", ls); /* { dg-warning "length character" "bad %LS" } */ + /* In C99 mode (even with extensions), %aS is a floating point + format followed by an S. + */ + scanf ("%aS", fp); + /* The printf flag character ' is an X/Open extension. */ + /* Allowing %'F here presumes acceptance of the corresponding Aardvark + report. + */ + printf ("%'d%'i%'u%'f%'F%'g%'G", i, i, u, d, d, d, d); + printf ("%'o", 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 ("%'e", d); /* { dg-warning "flag" "bad use of ' flag" } */ + printf ("%'E", d); /* { dg-warning "flag" "bad use of ' flag" } */ + printf ("%'a", d); /* { dg-warning "flag" "bad use of ' flag" } */ + printf ("%'A", d); /* { 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" } */ + /* The use of operand number $ formats is an X/Open extension. */ + /* Banning gaps in the arguments used with scanf, and not objecting to + multiple use of an argument with scanf, presumes acceptance of the + corresponding Aardvark reports. + */ + scanf ("%1$d", ip); + printf ("%1$d", i); + printf ("%3$*2$.*1$d", i2, i, l); + printf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", i, i, i, l, i, i, l); + scanf ("%4$ld%7$ld%5$d%6$d%3$d%1$d%2$d", ip, ip, ip, lp, ip, ip, lp); + printf ("%1$d%d", i, i); /* { dg-warning "missing" "mixing $ and non-$ formats" } */ + printf ("%%%1$d%%%2$d", i, i); + printf ("%d%2$d", i); /* { dg-warning "type character" "mixing $ and non-$ formats" } */ + printf ("%1$*d", i, i); /* { dg-warning "missing" "mixing $ and non-$ formats" } */ + scanf ("%1$d%d", ip, ip); /* { dg-warning "missing" "mixing $ and non-$ formats" } */ + scanf ("%*f%%%1$d%%%2$d", ip, ip); + printf ("%2$d", i); /* { dg-warning "operand" "$ number too large" } */ + printf ("%0$d", i); /* { dg-warning "operand" "$ number too small" } */ + printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */ + printf ("%2$d%1$d", i, i, i); /* { dg-warning "unused" "unused $ operand" } */ + vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */ +}