Patch: add GCC diagnostic framework format checking [part 1/N]
Kaveh R. Ghazi
ghazi@caip.rutgers.edu
Sun Jun 22 04:52:00 GMT 2003
This patch is the first of several which together will activate format
checking on GCC's diagnostic functions. The method used is similar to
what I did for asm_fprintf, i.e. I hardwire custom printf-style
format(s). The diagnostic framework has several quirks which make it
"interesting" to get it working with any kind of format checking. The
first twist is that the "format" isn't static, i.e. each frontend can
register its own extended specifiers and flags. Currently we have
three sets of specifiers. The first is the "generic" set, the second
is the C frontend set and the third is the C++ frontend set.
So this patch adds three new formats corresponding to the definitions
of these three sets. For now I've just added the formats and a
testcase. The format attributes haven't been applied yet to any
functions because I have to clean up a few warnings that the
attributes would expose. I'll do so separately.
I'm submitting this in pieces to make it easier to review. For this
patch I'd like reviews to concentrate on whether I got the three
diagnostic sets correctly defined in the format checking framework.
Tested on sparc-sun-solaris2.7 (minus java) no regressions and the new
testcases passes.
Ok for mainline?
Thanks,
--Kaveh
2003-06-21 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
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.
diff -rup orig/egcc-CVS20030620/gcc/builtin-attrs.def egcc-CVS20030620/gcc/builtin-attrs.def
--- orig/egcc-CVS20030620/gcc/builtin-attrs.def 2003-06-16 15:10:59.000000000 -0400
+++ egcc-CVS20030620/gcc/builtin-attrs.def 2003-06-21 18:59:03.153942089 -0400
@@ -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 -rup orig/egcc-CVS20030620/gcc/c-format.c egcc-CVS20030620/gcc/c-format.c
--- orig/egcc-CVS20030620/gcc/c-format.c 2003-06-20 22:37:06.000000000 -0400
+++ egcc-CVS20030620/gcc/c-format.c 2003-06-21 18:59:03.163941906 -0400
@@ -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,22 @@ static const format_length_info asm_fpri
{ 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, NULL, 0, 0 },
+/* FIXME: the %ll and %w modifiers are expected to be added "soon". */
+#if 0
+ { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 },
+ { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 },
+#endif
+ { 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 +609,32 @@ static const format_flag_pair asm_fprint
{ 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 +799,72 @@ static const format_char_info asm_fprint
{ 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 +934,24 @@ static const format_kind_info format_typ
'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 +2458,26 @@ check_format_types (int *status, format_
}
}
+/* 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 +2539,90 @@ 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;
+
+ if (!loc || !t)
+ {
+ static format_char_info *diag_fci, *cdiag_fci, *cxxdiag_fci;
+ 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)));
+
+ /* Assign the new data for use. */
+
+ /* Handle the __gcc_diag__ format. */
+ 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. */
+ 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. */
+ 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 +2672,12 @@ handle_format_attribute (tree *node, tre
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 +2686,18 @@ handle_format_attribute (tree *node, tre
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 -rup orig/egcc-CVS20030620/gcc/testsuite/gcc.dg/format/gcc_diag-1.c egcc-CVS20030620/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
--- orig/egcc-CVS20030620/gcc/testsuite/gcc.dg/format/gcc_diag-1.c 2003-06-21 18:59:14.332981087 -0400
+++ egcc-CVS20030620/gcc/testsuite/gcc.dg/format/gcc_diag-1.c 2003-06-21 18:59:48.370001448 -0400
@@ -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 ATTRUBUTE_DIAG(F) __attribute__ ((__format__ (F, 1, 2))) __attribute__ ((__nonnull__));
+
+/* Magic identifiers must be set before the attribute is used. */
+
+typedef struct location_s
+{
+ const char *file;
+ int line;
+} location_t;
+
+union tree_node;
+typedef union tree_node *tree;
+
+extern int diag (const char *, ...) ATTRUBUTE_DIAG(__gcc_diag__);
+extern int cdiag (const char *, ...) ATTRUBUTE_DIAG(__gcc_cdiag__);
+extern int cxxdiag (const char *, ...) ATTRUBUTE_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);
+#if 0 /* coming soon */
+ 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);
+#endif
+ 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" } */
+}
More information about the Gcc-patches
mailing list