From: Kaveh R. Ghazi Date: Mon, 30 Jun 2003 00:31:21 +0000 (+0000) Subject: builtin-attrs.def (gcc_diag, [...]): New format attributes. X-Git-Tag: releases/gcc-3.4.0~5333 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=280c1e0d2363f8c7ad25d623123421e9b42f4722;p=thirdparty%2Fgcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 82c6016a25df..77013cc00dec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2003-06-29 Kaveh R. Ghazi + + * 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 * config/i386/mingw32.h (__GTHREAD_HIDE_WIN32API): Define to 1. diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def index df0bc08d86f7..7156fcef9943 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 dc17f0e9f8b4..b971d3258aad 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 5226824c06be..26f239f93584 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-06-29 Kaveh R. Ghazi + + * gcc.dg/format/gcc_diag-1.c: New test. + 2003-06-28 Ulrich Weigand * 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 000000000000..7cf18c1b15f6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format/gcc_diag-1.c @@ -0,0 +1,185 @@ +/* Test for GCC diagnositc formats. */ +/* Origin: Kaveh Ghazi */ +/* { 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" } */ +}