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 <lh_mouse@126.com> gcc/ChangeLog: * config/i386/msformat-c.c: Add more length modifiers. gcc/testsuite/ChangeLog: * gcc.dg/format/ms_c99-printf-3.c: Update tests.
This commit is contained in:
parent
200c9e865f
commit
c51f1e7427
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue