c-family: Support format checking C2X %b, %B formats
C2X adds a %b printf format to print integers in binary (analogous to %x, including %#b printing a leading 0b on nonzero integers), with recommended practice for a corresponding %B (where %#B uses 0B instead of 0b) where that doesn't conflict with existing implementation extensions. See N2630 for details (accepted for C2X, not yet in the latest working draft). There is also a scanf %b format. Add corresponding format checking support (%b accepted by -std=c2x -Wformat -pedantic, %B considered an extension to be diagnosed with -Wformat -pedantic). glibc support for the printf formats has been proposed at <https://sourceware.org/pipermail/libc-alpha/2021-October/131764.html> (scanf support to be done in a separate patch). Note that this does not add any support for these formats to the code for bounding the amount of output produces by a printf function, although that would also be useful. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c-family/ * c-format.c (print_char_table): Add %b and %B formats. (scan_char_table): Add %b format. * c-format.h (T2X_UI, T2X_UL, T2X_ULL, T2X_US, T2X_UC, T2X_ST) (T2X_UPD, T2X_UIM): New macros. gcc/testsuite/ * gcc.dg/format/c11-printf-1.c, gcc.dg/format/c11-scanf-1.c, gcc.dg/format/c2x-printf-1.c, gcc.dg/format/c2x-scanf-1.c, gcc.dg/format/ext-9.c, gcc.dg/format/ext-10.c: New tests.
This commit is contained in:
parent
76ba473b99
commit
bd6f2c6316
8 changed files with 122 additions and 0 deletions
|
@ -712,11 +712,14 @@ static const format_char_info print_char_table[] =
|
|||
/* C99 conversion specifiers. */
|
||||
{ "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL },
|
||||
{ "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#", "", NULL },
|
||||
/* C2X conversion specifiers. */
|
||||
{ "b", 0, STD_C2X, { T2X_UI, T2X_UC, T2X_US, T2X_UL, T2X_ULL, TEX_ULL, T2X_ST, T2X_UPD, T2X_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL },
|
||||
/* X/Open conversion specifiers. */
|
||||
{ "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
|
||||
{ "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL },
|
||||
/* GNU conversion specifiers. */
|
||||
{ "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL },
|
||||
{ "B", 0, STD_EXT, { T2X_UI, T2X_UC, T2X_US, T2X_UL, T2X_ULL, TEX_ULL, T2X_ST, T2X_UPD, T2X_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL },
|
||||
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -876,6 +879,8 @@ static const format_char_info scan_char_table[] =
|
|||
/* C99 conversion specifiers. */
|
||||
{ "F", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL },
|
||||
{ "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "*w'", "W", NULL },
|
||||
/* C2X conversion specifiers. */
|
||||
{ "b", 1, STD_C2X, { T2X_UI, T2X_UC, T2X_US, T2X_UL, T2X_ULL, TEX_ULL, T2X_ST, T2X_UPD, T2X_UIM, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL },
|
||||
/* X/Open conversion specifiers. */
|
||||
{ "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "W", NULL },
|
||||
{ "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "W", NULL },
|
||||
|
|
|
@ -278,13 +278,17 @@ struct format_kind_info
|
|||
#define T89_S { STD_C89, NULL, T_S }
|
||||
#define T_UI &unsigned_type_node
|
||||
#define T89_UI { STD_C89, NULL, T_UI }
|
||||
#define T2X_UI { STD_C2X, NULL, T_UI }
|
||||
#define T_UL &long_unsigned_type_node
|
||||
#define T89_UL { STD_C89, NULL, T_UL }
|
||||
#define T2X_UL { STD_C2X, NULL, T_UL }
|
||||
#define T_ULL &long_long_unsigned_type_node
|
||||
#define T9L_ULL { STD_C9L, NULL, T_ULL }
|
||||
#define T2X_ULL { STD_C2X, NULL, T_ULL }
|
||||
#define TEX_ULL { STD_EXT, NULL, T_ULL }
|
||||
#define T_US &short_unsigned_type_node
|
||||
#define T89_US { STD_C89, NULL, T_US }
|
||||
#define T2X_US { STD_C2X, NULL, T_US }
|
||||
#define T_F &float_type_node
|
||||
#define T89_F { STD_C89, NULL, T_F }
|
||||
#define T99_F { STD_C99, NULL, T_F }
|
||||
|
@ -300,6 +304,7 @@ struct format_kind_info
|
|||
#define T99_SC { STD_C99, NULL, T_SC }
|
||||
#define T_UC &unsigned_char_type_node
|
||||
#define T99_UC { STD_C99, NULL, T_UC }
|
||||
#define T2X_UC { STD_C2X, NULL, T_UC }
|
||||
#define T_V &void_type_node
|
||||
#define T89_G { STD_C89, NULL, &local_gimple_ptr_node }
|
||||
#define T_CGRAPH_NODE { STD_C89, NULL, &local_cgraph_node_ptr_node }
|
||||
|
@ -314,16 +319,19 @@ struct format_kind_info
|
|||
#define TEX_WI { STD_EXT, "wint_t", T_WI }
|
||||
#define T_ST &size_type_node
|
||||
#define T99_ST { STD_C99, "size_t", T_ST }
|
||||
#define T2X_ST { STD_C2X, "size_t", T_ST }
|
||||
#define T_SST &signed_size_type_node
|
||||
#define T99_SST { STD_C99, "signed size_t", T_SST }
|
||||
#define T_PD &ptrdiff_type_node
|
||||
#define T99_PD { STD_C99, "ptrdiff_t", T_PD }
|
||||
#define T_UPD &unsigned_ptrdiff_type_node
|
||||
#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD }
|
||||
#define T2X_UPD { STD_C2X, "unsigned ptrdiff_t", T_UPD }
|
||||
#define T_IM &intmax_type_node
|
||||
#define T99_IM { STD_C99, "intmax_t", T_IM }
|
||||
#define T_UIM &uintmax_type_node
|
||||
#define T99_UIM { STD_C99, "uintmax_t", T_UIM }
|
||||
#define T2X_UIM { STD_C2X, "uintmax_t", T_UIM }
|
||||
#define T_D32 &dfloat32_type_node
|
||||
#define TEX_D32 { STD_EXT, "_Decimal32", T_D32 }
|
||||
#define T_D64 &dfloat64_type_node
|
||||
|
|
13
gcc/testsuite/gcc.dg/format/c11-printf-1.c
Normal file
13
gcc/testsuite/gcc.dg/format/c11-printf-1.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* Test for printf formats: rejection of C2X (and C2X-recommended) formats in
|
||||
pedantic mode. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c11 -pedantic -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (int i)
|
||||
{
|
||||
printf ("%b", i); /* { dg-warning "C" } */
|
||||
printf ("%B", i); /* { dg-warning "C" } */
|
||||
}
|
11
gcc/testsuite/gcc.dg/format/c11-scanf-1.c
Normal file
11
gcc/testsuite/gcc.dg/format/c11-scanf-1.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* Test for printf formats: rejection of C2X formats in pedantic mode. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c11 -pedantic -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (unsigned int *uip)
|
||||
{
|
||||
scanf ("%b", uip); /* { dg-warning "C" } */
|
||||
}
|
26
gcc/testsuite/gcc.dg/format/c2x-printf-1.c
Normal file
26
gcc/testsuite/gcc.dg/format/c2x-printf-1.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* Test for printf formats. Formats using C2X features. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c2x -pedantic -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (unsigned int u, unsigned short us, unsigned char uc, unsigned long ul,
|
||||
unsigned long long ull, uintmax_t uj, size_t z, unsigned_ptrdiff_t ut)
|
||||
{
|
||||
/* Use of %b with each length modifier and other valid features. */
|
||||
printf ("%b %hb %hhb %lb %llb %jb %zb %tb\n", u, us, uc, ul, ull, uj, z, ut);
|
||||
printf ("%*.*llb\n", 1, 2, ull);
|
||||
printf ("%-b\n", u);
|
||||
printf ("%#b\n", u);
|
||||
printf ("%08b\n", u);
|
||||
/* Flags valid on signed conversions only. */
|
||||
printf ("%+b\n", u); /* { dg-warning "flag" } */
|
||||
printf ("% b\n", u); /* { dg-warning "flag" } */
|
||||
/* Flags ignored in certain combinations. */
|
||||
printf ("%-08b\n", u); /* { dg-warning "ignored" } */
|
||||
printf ("%08.5b\n", u); /* { dg-warning "ignored" } */
|
||||
/* Use of 'L' and 'q' for long long is an extension. */
|
||||
printf ("%Lb", ull); /* { dg-warning "does not support" } */
|
||||
printf ("%qb", ull); /* { dg-warning "does not support" } */
|
||||
}
|
17
gcc/testsuite/gcc.dg/format/c2x-scanf-1.c
Normal file
17
gcc/testsuite/gcc.dg/format/c2x-scanf-1.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* Test for scanf formats. Formats using C2X features. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c2x -pedantic -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (unsigned int *uip, unsigned short int *uhp, unsigned char *uhhp,
|
||||
unsigned long int *ulp, unsigned long long *ullp, uintmax_t *ujp,
|
||||
size_t *zp, unsigned_ptrdiff_t *utp)
|
||||
{
|
||||
scanf ("%*b");
|
||||
scanf ("%2b", uip);
|
||||
scanf ("%hb%hhb%lb%llb%jb%zb%tb", uhp, uhhp, ulp, ullp, ujp, zp, utp);
|
||||
scanf ("%Lb", ullp); /* { dg-warning "does not support" } */
|
||||
scanf ("%qb", ullp); /* { dg-warning "does not support" } */
|
||||
}
|
13
gcc/testsuite/gcc.dg/format/ext-10.c
Normal file
13
gcc/testsuite/gcc.dg/format/ext-10.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* Test for scanf format extensions using formats from C2X. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=gnu2x -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (u_quad_t *uqp, unsigned long long int *ullp)
|
||||
{
|
||||
/* Deprecated length modifiers with %b. */
|
||||
scanf ("%qb", uqp);
|
||||
scanf ("%Lb", ullp);
|
||||
}
|
29
gcc/testsuite/gcc.dg/format/ext-9.c
Normal file
29
gcc/testsuite/gcc.dg/format/ext-9.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* Test for printf format extensions using formats from or recommended by
|
||||
C2X. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=gnu2x -Wformat" } */
|
||||
|
||||
#include "format.h"
|
||||
|
||||
void
|
||||
foo (u_quad_t uq, unsigned int u, unsigned short us, unsigned char uc,
|
||||
unsigned long ul, unsigned long long ull, uintmax_t uj, size_t z,
|
||||
unsigned_ptrdiff_t ut)
|
||||
{
|
||||
/* Deprecated length modifiers with %b and %B. */
|
||||
printf ("%qb%qB", uq, uq);
|
||||
printf ("%Lb%LB", ull, ull);
|
||||
printf ("%Zb%ZB", z, z);
|
||||
/* Use of %B in cases valid for %b. */
|
||||
printf ("%B %hB %hhB %lB %llB %jB %zB %tB\n", u, us, uc, ul, ull, uj, z, ut);
|
||||
printf ("%*.*llB\n", 1, 2, ull);
|
||||
printf ("%-B\n", u);
|
||||
printf ("%#B\n", u);
|
||||
printf ("%08B\n", u);
|
||||
/* Flags valid on signed conversions only. */
|
||||
printf ("%+B\n", u); /* { dg-warning "flag" } */
|
||||
printf ("% B\n", u); /* { dg-warning "flag" } */
|
||||
/* Flags ignored in certain combinations. */
|
||||
printf ("%-08B\n", u); /* { dg-warning "ignored" } */
|
||||
printf ("%08.5B\n", u); /* { dg-warning "ignored" } */
|
||||
}
|
Loading…
Add table
Reference in a new issue