aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2003-06-30 00:31:21 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2003-06-30 00:31:21 +0000
commit280c1e0d2363f8c7ad25d623123421e9b42f4722 (patch)
tree8a17e7fe4aba72658d0e9aef9464d1878f0b087b /gcc
parent54bbcbd99db9ba3520ceef2912aca9c895e89bf3 (diff)
downloadgcc-280c1e0d2363f8c7ad25d623123421e9b42f4722.zip
gcc-280c1e0d2363f8c7ad25d623123421e9b42f4722.tar.gz
gcc-280c1e0d2363f8c7ad25d623123421e9b42f4722.tar.bz2
builtin-attrs.def (gcc_diag, [...]): New format attributes.
gcc: * builtin-attrs.def (gcc_diag, gcc_cdiag, gcc_cxxdiag): New format attributes. * c-format.c (enum format_type): Add gcc_diag_format_type, gcc_cdiag_format_type, and gcc_cxxdiag_format_type. (gcc_diag_length_specs, gcc_cdiag_length_specs, gcc_cxxdiag_length_specs, gcc_diag_flag_pairs, gcc_cdiag_flag_pairs, gcc_cxxdiag_flag_pairs, gcc_diag_flag_specs, gcc_cdiag_flag_specs, gcc_cxxdiag_flag_specs, gcc_diag_char_table, gcc_cdiag_char_table, gcc_cxxdiag_char_table): New. (format_types_orig): Add new data. (find_char_info_specifier_index, init_dynamic_diag_info): New functions. (handle_format_attribute): Update to handle new format attributes. testsuite: * gcc.dg/format/gcc_diag-1.c: New test. From-SVN: r68689
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/builtin-attrs.def3
-rw-r--r--gcc/c-format.c278
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/format/gcc_diag-1.c185
5 files changed, 482 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 82c6016..77013cc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2003-06-29 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * builtin-attrs.def (gcc_diag, gcc_cdiag, gcc_cxxdiag): New
+ format attributes.
+ * c-format.c (enum format_type): Add gcc_diag_format_type,
+ gcc_cdiag_format_type, and gcc_cxxdiag_format_type.
+ (gcc_diag_length_specs, gcc_cdiag_length_specs,
+ gcc_cxxdiag_length_specs, gcc_diag_flag_pairs,
+ gcc_cdiag_flag_pairs, gcc_cxxdiag_flag_pairs, gcc_diag_flag_specs,
+ gcc_cdiag_flag_specs, gcc_cxxdiag_flag_specs, gcc_diag_char_table,
+ gcc_cdiag_char_table, gcc_cxxdiag_char_table): New.
+ (format_types_orig): Add new data.
+ (find_char_info_specifier_index, init_dynamic_diag_info): New
+ functions.
+ (handle_format_attribute): Update to handle new format attributes.
+
2003-06-29 Aaron W. LaFramboise <awlaframboise@aol.com>
* config/i386/mingw32.h (__GTHREAD_HIDE_WIN32API): Define to 1.
diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index df0bc08..7156fce 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -85,6 +85,9 @@ DEF_ATTR_IDENT (ATTR_NORETURN, "noreturn")
DEF_ATTR_IDENT (ATTR_NOTHROW, "nothrow")
DEF_ATTR_IDENT (ATTR_PRINTF, "printf")
DEF_ATTR_IDENT (ATTR_ASM_FPRINTF, "asm_fprintf")
+DEF_ATTR_IDENT (ATTR_GCC_DIAG, "gcc_diag")
+DEF_ATTR_IDENT (ATTR_GCC_CDIAG, "gcc_cdiag")
+DEF_ATTR_IDENT (ATTR_GCC_CXXDIAG, "gcc_cxxdiag")
DEF_ATTR_IDENT (ATTR_PURE, "pure")
DEF_ATTR_IDENT (ATTR_SCANF, "scanf")
DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
diff --git a/gcc/c-format.c b/gcc/c-format.c
index dc17f0e..b971d32 100644
--- a/gcc/c-format.c
+++ b/gcc/c-format.c
@@ -56,6 +56,8 @@ set_Wformat (int setting)
/* This must be in the same order as format_types, with format_type_error
last. */
enum format_type { printf_format_type, asm_fprintf_format_type,
+ gcc_diag_format_type, gcc_cdiag_format_type,
+ gcc_cxxdiag_format_type,
scanf_format_type, strftime_format_type,
strfmon_format_type, format_type_error };
@@ -523,6 +525,18 @@ static const format_length_info asm_fprintf_length_specs[] =
{ NULL, 0, 0, NULL, 0, 0 }
};
+/* Length specifiers valid for GCC diagnostics. */
+static const format_length_info gcc_diag_length_specs[] =
+{
+ { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 },
+ { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 },
+ { NULL, 0, 0, NULL, 0, 0 }
+};
+
+/* The custom diagnostics all accept the same length specifiers. */
+#define gcc_cdiag_length_specs gcc_diag_length_specs
+#define gcc_cxxdiag_length_specs gcc_diag_length_specs
+
/* This differs from printf_length_specs only in that "Z" is not accepted. */
static const format_length_info scanf_length_specs[] =
{
@@ -591,6 +605,32 @@ static const format_flag_pair asm_fprintf_flag_pairs[] =
{ 0, 0, 0, 0 }
};
+static const format_flag_pair gcc_diag_flag_pairs[] =
+{
+ { 0, 0, 0, 0 }
+};
+
+#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
+#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
+
+static const format_flag_spec gcc_diag_flag_specs[] =
+{
+ { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
+ { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+ { 0, 0, 0, NULL, NULL, 0 }
+};
+
+#define gcc_cdiag_flag_specs gcc_diag_flag_specs
+
+static const format_flag_spec gcc_cxxdiag_flag_specs[] =
+{
+ { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 },
+ { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 },
+ { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
+ { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+ { 0, 0, 0, NULL, NULL, 0 }
+};
+
static const format_flag_spec scanf_flag_specs[] =
{
{ '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
@@ -755,6 +795,72 @@ static const format_char_info asm_fprintf_char_table[] =
{ NULL, 0, 0, NOLENGTHS, NULL, NULL }
};
+static const format_char_info gcc_diag_char_table[] =
+{
+ /* C89 conversion specifiers. */
+ { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" },
+ { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" },
+
+ /* Custom conversion specifiers. */
+
+ /* %H will require "location_t" at runtime. */
+ { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+
+ { "m", 0, STD_C89, NOARGUMENTS, "", "" },
+ { NULL, 0, 0, NOLENGTHS, NULL, NULL }
+};
+
+static const format_char_info gcc_cdiag_char_table[] =
+{
+ /* C89 conversion specifiers. */
+ { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" },
+ { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" },
+
+ /* Custom conversion specifiers. */
+
+ /* %H will require "location_t" at runtime. */
+ { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+
+ /* These will require a "tree" at runtime. */
+ { "DFT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+
+ { "m", 0, STD_C89, NOARGUMENTS, "", "" },
+ { NULL, 0, 0, NOLENGTHS, NULL, NULL }
+};
+
+static const format_char_info gcc_cxxdiag_char_table[] =
+{
+ /* C89 conversion specifiers. */
+ { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+ { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "p", "cR" },
+ { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "c" },
+
+ /* Custom conversion specifiers. */
+
+ /* %H will require "location_t" at runtime. */
+ { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+
+ /* These will require a "tree" at runtime. */
+ { "ADEFTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "+#", "" },
+
+ /* These accept either an `int' or an `enum tree_code' (which is handled as an `int'.) */
+ { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" },
+
+ { "m", 0, STD_C89, NOARGUMENTS, "", "" },
+ { NULL, 0, 0, NOLENGTHS, NULL, NULL }
+};
+
static const format_char_info scan_char_table[] =
{
/* C89 conversion specifiers. */
@@ -824,6 +930,24 @@ static const format_kind_info format_types_orig[] =
'w', 0, 'p', 0, 'L',
NULL, NULL
},
+ { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "", NULL,
+ gcc_diag_flag_specs, gcc_diag_flag_pairs,
+ FMT_FLAG_ARG_CONVERT,
+ 0, 0, 'p', 0, 'L',
+ NULL, &integer_type_node
+ },
+ { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "", NULL,
+ gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
+ FMT_FLAG_ARG_CONVERT,
+ 0, 0, 'p', 0, 'L',
+ NULL, &integer_type_node
+ },
+ { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "+#", NULL,
+ gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs,
+ FMT_FLAG_ARG_CONVERT,
+ 0, 0, 'p', 0, 'L',
+ NULL, &integer_type_node
+ },
{ "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
scanf_flag_specs, scanf_flag_pairs,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
@@ -2330,6 +2454,26 @@ check_format_types (int *status, format_wanted_type *types)
}
}
+/* Given a format_char_info array FCI, and a character C, this function
+ returns the index into the conversion_specs where that specifier's
+ data is located. If the character isn't found it aborts. */
+static unsigned int
+find_char_info_specifier_index (const format_char_info *fci, int c)
+{
+ unsigned int i = 0;
+
+ while (fci->format_chars)
+ {
+ if (strchr (fci->format_chars, c))
+ return i;
+ i++; fci++;
+ }
+
+ /* We shouldn't be looking for a non-existent specifier. */
+ abort ();
+
+}
+
/* Given a format_length_info array FLI, and a character C, this
function returns the index into the conversion_specs where that
modifier's data is located. If the character isn't found it
@@ -2391,6 +2535,118 @@ init_dynamic_asm_fprintf_info (void)
}
}
+/* Determine the types of "tree" and "location_t" in the code being
+ compiled for use in GCC's diagnostic custom format attributes. You
+ must have set dynamic_format_types before calling this function. */
+static void
+init_dynamic_diag_info (void)
+{
+ static tree t, loc, hwi;
+
+ if (!loc || !t || !hwi)
+ {
+ static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci;
+ static format_length_info *diag_ls;
+ unsigned int i;
+
+ /* For the GCC-diagnostics custom format specifiers to work, one
+ must have declared `tree' and/or `location_t' prior to using
+ those attributes. If we haven't seen these declarations then
+ you shouldn't use the specifiers requiring these types.
+ However we don't force a hard ICE because we may see only one
+ or the other type. */
+ if ((loc = maybe_get_identifier ("location_t")))
+ loc = TREE_TYPE (identifier_global_value (loc));
+
+ /* We need to grab the underlying `union tree_node' so peek into
+ an extra type level. */
+ if ((t = maybe_get_identifier ("tree")))
+ t = TREE_TYPE (TREE_TYPE (identifier_global_value (t)));
+
+ /* Find the underlying type for HOST_WIDE_INT. For the %w
+ length modifier to work, one must have issued: "typedef
+ HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
+ prior to using that modifier. */
+ if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__")))
+ hwi = DECL_ORIGINAL_TYPE (identifier_global_value (hwi));
+
+ /* Assign the new data for use. */
+
+ /* All the GCC diag formats use the same length specs. */
+ if (! diag_ls)
+ dynamic_format_types[gcc_diag_format_type].length_char_specs =
+ dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
+ dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
+ diag_ls = xmemdup (gcc_diag_length_specs,
+ sizeof (gcc_diag_length_specs),
+ sizeof (gcc_diag_length_specs));
+ if (hwi)
+ {
+ /* HOST_WIDE_INT must be one of 'long' or 'long long'. */
+ i = find_length_info_modifier_index (diag_ls, 'w');
+ if (hwi == long_integer_type_node)
+ diag_ls[i].index = FMT_LEN_l;
+ else if (hwi == long_long_integer_type_node)
+ diag_ls[i].index = FMT_LEN_ll;
+ else
+ abort ();
+ }
+
+ /* Handle the __gcc_diag__ format specifics. */
+ if (! diag_fci)
+ dynamic_format_types[gcc_diag_format_type].conversion_specs =
+ diag_fci = xmemdup (gcc_diag_char_table,
+ sizeof(gcc_diag_char_table),
+ sizeof(gcc_diag_char_table));
+ if (loc)
+ {
+ i = find_char_info_specifier_index (diag_fci, 'H');
+ diag_fci[i].types[0].type = &loc;
+ diag_fci[i].pointer_count = 1;
+ }
+
+ /* Handle the __gcc_cdiag__ format specifics. */
+ if (! cdiag_fci)
+ dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
+ cdiag_fci = xmemdup (gcc_cdiag_char_table,
+ sizeof(gcc_cdiag_char_table),
+ sizeof(gcc_cdiag_char_table));
+ if (loc)
+ {
+ i = find_char_info_specifier_index (cdiag_fci, 'H');
+ cdiag_fci[i].types[0].type = &loc;
+ cdiag_fci[i].pointer_count = 1;
+ }
+ if (t)
+ {
+ /* All specifiers taking a tree share the same struct. */
+ i = find_char_info_specifier_index (cdiag_fci, 'D');
+ cdiag_fci[i].types[0].type = &t;
+ cdiag_fci[i].pointer_count = 1;
+ }
+
+ /* Handle the __gcc_cxxdiag__ format specifics. */
+ if (! cxxdiag_fci)
+ dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
+ cxxdiag_fci = xmemdup (gcc_cxxdiag_char_table,
+ sizeof(gcc_cxxdiag_char_table),
+ sizeof(gcc_cxxdiag_char_table));
+ if (loc)
+ {
+ i = find_char_info_specifier_index (cxxdiag_fci, 'H');
+ cxxdiag_fci[i].types[0].type = &loc;
+ cxxdiag_fci[i].pointer_count = 1;
+ }
+ if (t)
+ {
+ /* All specifiers taking a tree share the same struct. */
+ i = find_char_info_specifier_index (cxxdiag_fci, 'D');
+ cxxdiag_fci[i].types[0].type = &t;
+ cxxdiag_fci[i].pointer_count = 1;
+ }
+ }
+}
+
/* Handle a "format" attribute; arguments as in
struct attribute_spec.handler. */
tree
@@ -2440,9 +2696,12 @@ handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
return NULL_TREE;
}
- /* If this is format type __asm_fprintf__, we have to initialize
- GCC's notion of HOST_WIDE_INT for checking %wd. */
- if (info.format_type == asm_fprintf_format_type)
+ /* If this is a custom GCC-internal format type, we have to
+ initialize certain bits a runtime. */
+ if (info.format_type == asm_fprintf_format_type
+ || info.format_type == gcc_diag_format_type
+ || info.format_type == gcc_cdiag_format_type
+ || info.format_type == gcc_cxxdiag_format_type)
{
/* Our first time through, we have to make sure that our
format_type data is allocated dynamically and is modifiable. */
@@ -2451,7 +2710,18 @@ handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args,
xmemdup (format_types_orig, sizeof (format_types_orig),
sizeof (format_types_orig));
- init_dynamic_asm_fprintf_info();
+ /* If this is format __asm_fprintf__, we have to initialize
+ GCC's notion of HOST_WIDE_INT for checking %wd. */
+ if (info.format_type == asm_fprintf_format_type)
+ init_dynamic_asm_fprintf_info();
+ /* If this is one of the diagnostic attributes, then we have to
+ intialize `location_t' and `tree' at runtime. */
+ else if (info.format_type == gcc_diag_format_type
+ || info.format_type == gcc_cdiag_format_type
+ || info.format_type == gcc_cxxdiag_format_type)
+ init_dynamic_diag_info();
+ else
+ abort();
}
return NULL_TREE;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5226824..26f239f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2003-06-29 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gcc.dg/format/gcc_diag-1.c: New test.
+
2003-06-28 Ulrich Weigand <uweigand@de.ibm.com>
* gcc.c-torture/execute/multi-ix.c: Fix off-by-one bugs.
diff --git a/gcc/testsuite/gcc.dg/format/gcc_diag-1.c b/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
new file mode 100644
index 0000000..7cf18c1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
@@ -0,0 +1,185 @@
+/* Test for GCC diagnositc formats. */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile } */
+/* { dg-options "-Wformat" } */
+
+#include "format.h"
+
+#define ATTRIBUTE_DIAG(F) __attribute__ ((__format__ (F, 1, 2))) __attribute__ ((__nonnull__));
+
+/* Magic identifiers must be set before the attribute is used. */
+
+typedef long long __gcc_host_wide_int__;
+
+typedef struct location_s
+{
+ const char *file;
+ int line;
+} location_t;
+
+union tree_node;
+typedef union tree_node *tree;
+
+extern int diag (const char *, ...) ATTRIBUTE_DIAG(__gcc_diag__);
+extern int cdiag (const char *, ...) ATTRIBUTE_DIAG(__gcc_cdiag__);
+extern int cxxdiag (const char *, ...) ATTRIBUTE_DIAG(__gcc_cxxdiag__);
+
+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, location_t *loc, tree t1, union tree_node *t2,
+ tree *t3, tree t4[])
+{
+ /* Acceptable C90 specifiers, flags and modifiers. */
+ diag ("%%");
+ cdiag ("%%");
+ cxxdiag ("%%");
+ diag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
+ cdiag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
+ cxxdiag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
+ diag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
+ cdiag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
+ cxxdiag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
+ diag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
+ cdiag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
+ cxxdiag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
+ diag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
+ cdiag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
+ cxxdiag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
+ diag ("%.*s", i, s);
+ cdiag ("%.*s", i, s);
+ cxxdiag ("%.*s", i, s);
+
+ /* Extensions provided in the diagnostic framework. */
+ diag ("%m");
+ cdiag ("%m");
+ cxxdiag ("%m");
+ diag ("%H", loc);
+ cdiag ("%H", loc);
+ cxxdiag ("%H", loc);
+
+ cdiag ("%D%F%T", t1, t1, t1);
+ cdiag ("%D%D%D%D", t1, t2, *t3, t4[5]);
+ cxxdiag ("%A%D%E%F%T%V", t1, t1, t1, t1, t1, t1);
+ cxxdiag ("%D%D%D%D", t1, t2, *t3, t4[5]);
+ cxxdiag ("%#A%#D%#E%#F%#T%#V", t1, t1, t1, t1, t1, t1);
+ cxxdiag ("%+A%+D%+E%+F%+T%+V", t1, t1, t1, t1, t1, t1);
+ cxxdiag ("%+#A%+#D%+#E%+#F%+#T%+#V", t1, t1, t1, t1, t1, t1);
+ cxxdiag ("%C%L%O%P%Q", i, i, i, i, i);
+
+ /* Bad stuff with extensions. */
+ diag ("%m", i); /* { dg-warning "format" "extra arg" } */
+ cdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
+ cxxdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
+ diag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
+ diag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
+ diag ("%H"); /* { dg-warning "format" "missing arg" } */
+ cdiag ("%H"); /* { dg-warning "format" "missing arg" } */
+ cxxdiag ("%H"); /* { dg-warning "format" "missing arg" } */
+ diag ("%H", i); /* { dg-warning "format" "wrong arg" } */
+ cdiag ("%H", i); /* { dg-warning "format" "wrong arg" } */
+ cxxdiag ("%H", i); /* { dg-warning "format" "wrong arg" } */
+ diag ("%H", p); /* { dg-warning "format" "wrong arg" } */
+ cdiag ("%H", p); /* { dg-warning "format" "wrong arg" } */
+ cxxdiag ("%H", p); /* { dg-warning "format" "wrong arg" } */
+ diag ("%#H", loc); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%#H", loc); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%#H", loc); /* { dg-warning "format" "bogus modifier" } */
+ diag ("%+H", loc); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%+H", loc); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%+H", loc); /* { dg-warning "format" "bogus modifier" } */
+ diag ("%D", t1); /* { dg-warning "format" "bogus tree" } */
+ cdiag ("%A", t1); /* { dg-warning "format" "bogus tree" } */
+ cdiag ("%#D", t1); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%+D", t1); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%C"); /* { dg-warning "format" "missing arg" } */
+ cxxdiag ("%C", l); /* { dg-warning "format" "wrong arg" } */
+ cxxdiag ("%C", i, i); /* { dg-warning "format" "extra arg" } */
+ cxxdiag ("%#C", i); /* { dg-warning "format" "bogus modifier" } */
+ cxxdiag ("%+C", i); /* { dg-warning "format" "bogus modifier" } */
+ cdiag ("%D"); /* { dg-warning "format" "missing arg" } */
+ cxxdiag ("%D"); /* { dg-warning "format" "missing arg" } */
+ cdiag ("%D", i); /* { dg-warning "format" "wrong arg" } */
+ cxxdiag ("%D", i); /* { dg-warning "format" "wrong arg" } */
+ cdiag ("%D", t1, t1); /* { dg-warning "format" "extra arg" } */
+ cxxdiag ("%D", t1, t1); /* { dg-warning "format" "extra arg" } */
+
+ /* Standard specifiers not accepted in the diagnostic framework. */
+ diag ("%X\n", u); /* { dg-warning "format" "HEX" } */
+ diag ("%f\n", d); /* { dg-warning "format" "float" } */
+ diag ("%e\n", d); /* { dg-warning "format" "float" } */
+ diag ("%E\n", d); /* { dg-warning "format" "float" } */
+ diag ("%g\n", d); /* { dg-warning "format" "float" } */
+ diag ("%G\n", d); /* { dg-warning "format" "float" } */
+ diag ("%n\n", n); /* { dg-warning "format" "counter" } */
+ diag ("%hd\n", i); /* { dg-warning "format" "conversion" } */
+
+ /* Various tests of bad argument types. */
+ diag ("%-d", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%-d", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%-d", i); /* { dg-warning "format" "bad flag" } */
+ diag ("% d", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("% d", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("% d", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%#o", u); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%#o", u); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%#o", u); /* { dg-warning "format" "bad flag" } */
+ diag ("%0d", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%0d", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%0d", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%08d", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%08d", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%08d", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%+d\n", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%+d\n", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%+d\n", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%3d\n", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%3d\n", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%3d\n", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%-3d\n", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%-3d\n", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%-3d\n", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%.7d\n", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%.7d\n", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%.7d\n", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%+9.4d\n", i); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%+9.4d\n", i); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%+9.4d\n", i); /* { dg-warning "format" "bad flag" } */
+ diag ("%.3ld\n", l); /* { dg-warning "format" "bad flag" } */
+ cdiag ("%.3ld\n", l); /* { dg-warning "format" "bad flag" } */
+ cxxdiag ("%.3ld\n", l); /* { dg-warning "format" "bad flag" } */
+ diag ("%d %lu\n", i, ul);
+ diag ("%d", l); /* { dg-warning "format" "bad argument types" } */
+ diag ("%wd", l); /* { dg-warning "format" "bad argument types" } */
+ diag ("%d", ll); /* { dg-warning "format" "bad argument types" } */
+ diag ("%*s", i, s); /* { dg-warning "format" "bad * argument types" } */
+ diag ("%*.*s", i, i, s); /* { dg-warning "format" "bad * argument types" } */
+ diag ("%*d\n", i1, i); /* { dg-warning "format" "bad * argument types" } */
+ diag ("%.*d\n", i2, i); /* { dg-warning "format" "bad * argument types" } */
+ diag ("%*.*ld\n", i1, i2, l); /* { dg-warning "format" "bad * argument types" } */
+ diag ("%ld", i); /* { dg-warning "format" "bad argument types" } */
+ diag ("%s", n); /* { dg-warning "format" "bad argument types" } */
+
+ /* Wrong number of arguments. */
+ diag ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+ diag ("%d", i, i); /* { dg-warning "arguments" "wrong number of args" } */
+ /* Miscellaneous bogus constructions. */
+ diag (""); /* { dg-warning "zero-length" "warning for empty format" } */
+ diag ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+ diag ("%d\0", i); /* { dg-warning "embedded" "warning for embedded NUL" } */
+ diag ("%d\0%d", i, i); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+ diag (NULL); /* { dg-warning "null" "null format string warning" } */
+ diag ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+ diag ((const char *)L"foo"); /* { dg-warning "wide" "wide string" } */
+ diag ("%s", (char *)0); /* { dg-warning "null" "%s with NULL" } */
+
+ /* Make sure we still get warnings for regular printf. */
+ printf ("%d\n", ll); /* { dg-warning "format" "bad argument types" } */
+}