From c51f1e7427e6a5ae2a6d82b5a790df77a3adc99a Mon Sep 17 00:00:00 2001 From: Liu Hao Date: Thu, 12 Nov 2020 22:20:29 +0800 Subject: [PATCH] gcc: Add `ll` and `L` length modifiers for `ms_printf` Previous code abused `FMT_LEN_L` for the `I` modifier. As `L` is a valid modifier for `f`, `e`, `g`, etc. and `I` has the same semantics as the C99 `z` modifier, `FMT_LEN_z` is now used instead. First, in the Microsoft ABI, type `long double` has the same layout as type `double`, so `%Lg` behaves identically to `%g`. Users should pass in `double`s instead of `long double`s, as GCC uses the 10-byte format. Second, with a CRT that is recent enough (MSVCRT since Vista, MSVCR80, UCRT, or mingw-w64 8.0), `printf`-family functions can handle the `ll` length modifier correctly. This ability is assumed to be available universally. A lot of libraries (such as libgomp) that use the `format(printf, ...)` attribute used to suffer from warnings about unknown format specifiers. Reference: https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/tcxf1dw6(v=vs.90) Reference: https://docs.microsoft.com/en-us/cpp/porting/visual-cpp-what-s-new-2003-through-2015#new-crt-features Signed-off-by: Liu Hao gcc/ChangeLog: * config/i386/msformat-c.c: Add more length modifiers. gcc/testsuite/ChangeLog: * gcc.dg/format/ms_c99-printf-3.c: Update tests. --- gcc/config/i386/msformat-c.c | 53 ++++++++++--------- gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c | 22 +++++++- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/gcc/config/i386/msformat-c.c b/gcc/config/i386/msformat-c.c index 4ceec633a6e..085ac88789a 100644 --- a/gcc/config/i386/msformat-c.c +++ b/gcc/config/i386/msformat-c.c @@ -32,10 +32,11 @@ along with GCC; see the file COPYING3. If not see static format_length_info ms_printf_length_specs[] = { { "h", FMT_LEN_h, STD_C89, NULL, FMT_LEN_none, STD_C89, 0 }, - { "l", FMT_LEN_l, STD_C89, NULL, FMT_LEN_none, STD_C89, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, + { "L", FMT_LEN_L, STD_C89, NULL, FMT_LEN_none, STD_C89, 1 }, { "I32", FMT_LEN_l, STD_EXT, NULL, FMT_LEN_none, STD_C89, 1 }, { "I64", FMT_LEN_ll, STD_EXT, NULL, FMT_LEN_none, STD_C89, 1 }, - { "I", FMT_LEN_L, STD_EXT, NULL, FMT_LEN_none, STD_C89, 1 }, + { "I", FMT_LEN_z, STD_EXT, NULL, FMT_LEN_none, STD_C89, 1 }, { NULL, FMT_LEN_none, STD_C89, NULL, FMT_LEN_none, STD_C89, 0 } }; @@ -90,33 +91,35 @@ static const format_flag_pair ms_strftime_flag_pairs[] = static const format_char_info ms_print_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, T99_SST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +'", "i", NULL }, - { "oxX", 0, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, - { "u", 0, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0'", "i", NULL }, - { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "", NULL }, - { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, - { "c", 0, STD_C89, { T89_I, BADLEN, T89_S, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, - { "n", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + { "di", 0, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +'", "i", NULL }, + { "oxX", 0, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, BADLEN, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, BADLEN, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0'", "i", NULL }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "", NULL }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, T89_S, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, + { "n", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + /* C99 conversion specifiers. */ + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, /* X/Open conversion specifiers. */ - { "C", 0, STD_EXT, { TEX_WI, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, + { "C", 0, STD_EXT, { TEX_WI, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info ms_scan_char_table[] = { /* C89 conversion specifiers. */ - { "di", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, T99_SST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, - { "u", 1, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, - { "oxX", 1, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, - { "c", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL }, - { "s", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL }, - { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL }, - { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, - { "n", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, + { "di", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + { "u", 1, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, BADLEN, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + { "oxX", 1, STD_C89, { T89_UI, BADLEN, T89_US, T89_UL, T9L_ULL, BADLEN, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, + { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + { "c", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, T89_S, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL }, + { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL }, + { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, + { "n", 1, STD_C89, { T89_I, BADLEN, T89_S, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "W", NULL }, /* X/Open conversion specifiers. */ { "C", 1, STD_EXT, { TEX_W, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, { "S", 1, STD_EXT, { TEX_W, BADLEN, T89_S, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W", NULL }, @@ -182,9 +185,9 @@ extern void TARGET_OVERRIDES_FORMAT_INIT (void); void TARGET_OVERRIDES_FORMAT_INIT (void) { - ms_printf_length_specs[2].std = C89_OR_EXT; /* I32 */ - ms_printf_length_specs[3].std = C89_OR_EXT; /* I64 */ - ms_printf_length_specs[4].std = C89_OR_EXT; /* I */ + ms_printf_length_specs[3].std = C89_OR_EXT; /* I32 */ + ms_printf_length_specs[4].std = C89_OR_EXT; /* I64 */ + ms_printf_length_specs[5].std = C89_OR_EXT; /* I */ } #undef C89_OR_EXT diff --git a/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c b/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c index d8c51eaa063..f46f155a0b1 100644 --- a/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c +++ b/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c @@ -9,13 +9,33 @@ #include "format.h" void -foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3, +foo (int i, char *s, size_t n, long l, llong ll, double d, + long double ld, 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" } */ + /* These are accepted since MSVCR80, MSVCRT from Vista, UCRT, + * and mingw-w64 8.0 with C99/C++11. */ + printf ("%lld", i); /* { dg-warning "format" "printf" } */ + printf ("%lld", l); /* { dg-warning "format" "printf" } */ + printf ("%lld", ll); + printf ("%llu", i); /* { dg-warning "format" "printf" } */ + printf ("%llu", l); /* { dg-warning "format" "printf" } */ + printf ("%llu", ll); + printf ("%llx", i); /* { dg-warning "format" "printf" } */ + printf ("%llx", l); /* { dg-warning "format" "printf" } */ + printf ("%llx", ll); + /* As MSABI uses an 8-byte `long double`, `%Lg` matches GCC's + * `double` instead of `long double` which takes 10 bytes. */ + printf ("%Lg", d); + printf ("%Lg", ld); /* { dg-warning "format" "printf" } */ + printf ("%Le", d); + printf ("%Le", ld); /* { dg-warning "format" "printf" } */ + printf ("%Lf", d); + printf ("%Lf", ld); /* { dg-warning "format" "printf" } */ /* The "unlocked" functions shouldn't warn in c99 mode. */ fprintf_unlocked (stdout, "%ld", i); printf_unlocked ("%ld", i); -- 2.30.2