[v3] c-format: Add -Wformat-int-precision option [PR80060]

Message ID 20211121145232.159995-1-daniil.stas@posteo.net
State New
Headers
Series [v3] c-format: Add -Wformat-int-precision option [PR80060] |

Commit Message

Daniil Stas Nov. 21, 2021, 2:52 p.m. UTC
  This option is enabled by default when -Wformat option is enabled. A
user can specify -Wno-format-int-precision to disable emitting
warnings when passing an argument of an incompatible integer type to
a 'd', 'i', 'o', 'u', 'x', or 'X' conversion specifier when it has
the same precision as the expected type.

Signed-off-by: Daniil Stas <daniil.stas@posteo.net>

gcc/c-family/ChangeLog:

	* c-format.c (check_format_types): Don't emit warnings when
	passing an argument of an incompatible integer type to
	a 'd', 'i', 'o', 'u', 'x', or 'X' conversion specifier when it has
	the same precision as the expected type if
	-Wno-format-int-precision option is specified.
	* c.opt: Add -Wformat-int-precision option.

gcc/ChangeLog:

	* doc/invoke.texi: Add -Wformat-int-precision option description.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wformat-int-precision-1.c: New test.
	* c-c++-common/Wformat-int-precision-2.c: New test.
---
Changes for v3:
  - Added additional @code{} derictives to the documentation where needed.
  - Changed tests to run on "! long_neq_int" target instead of "lp64".
  - Added a test case to check that gcc still emits warnings for arguments
  with different precision even with -Wno-format-int-precision option enabled.

Changes for v2:
  - Changed the option name to -Wformat-int-precision.
  - Changed the option description as was suggested by Martin.
  - Changed Wformat-int-precision-2.c to use dg-bogus instead of previous
  invalid syntax.

 gcc/c-family/c-format.c                         |  2 +-
 gcc/c-family/c.opt                              |  6 ++++++
 gcc/doc/invoke.texi                             | 17 ++++++++++++++++-
 .../c-c++-common/Wformat-int-precision-1.c      |  7 +++++++
 .../c-c++-common/Wformat-int-precision-2.c      |  8 ++++++++
 5 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wformat-int-precision-1.c
 create mode 100644 gcc/testsuite/c-c++-common/Wformat-int-precision-2.c
  

Comments

Joseph Myers Nov. 22, 2021, 8:35 p.m. UTC | #1
On Sun, 21 Nov 2021, Daniil Stas via Gcc-patches wrote:

> This option is enabled by default when -Wformat option is enabled. A
> user can specify -Wno-format-int-precision to disable emitting
> warnings when passing an argument of an incompatible integer type to
> a 'd', 'i', 'o', 'u', 'x', or 'X' conversion specifier when it has
> the same precision as the expected type.

I'd expect this to apply to 'b' and 'B' as well (affects commit message, 
ChangeLog entry, option help string, documentation).
  
Daniil Stas Nov. 23, 2021, 9:18 a.m. UTC | #2
On Mon, 22 Nov 2021 20:35:03 +0000
Joseph Myers <joseph@codesourcery.com> wrote:

> On Sun, 21 Nov 2021, Daniil Stas via Gcc-patches wrote:
> 
> > This option is enabled by default when -Wformat option is enabled. A
> > user can specify -Wno-format-int-precision to disable emitting
> > warnings when passing an argument of an incompatible integer type to
> > a 'd', 'i', 'o', 'u', 'x', or 'X' conversion specifier when it has
> > the same precision as the expected type.  
> 
> I'd expect this to apply to 'b' and 'B' as well (affects commit
> message, ChangeLog entry, option help string, documentation).
> 

Hi Joseph,

I can't find any description of these specifiers anywhere. And looks
like gcc doesn't recognize them when I try to compile a sample program
with them (I just get %B printed when I run the program).
Do these specifiers actually exist? Can you point me to the
documentation?

Thanks
  
Joseph Myers Nov. 23, 2021, 10:48 p.m. UTC | #3
On Tue, 23 Nov 2021, Daniil Stas via Gcc-patches wrote:

> On Mon, 22 Nov 2021 20:35:03 +0000
> Joseph Myers <joseph@codesourcery.com> wrote:
> 
> > On Sun, 21 Nov 2021, Daniil Stas via Gcc-patches wrote:
> > 
> > > This option is enabled by default when -Wformat option is enabled. A
> > > user can specify -Wno-format-int-precision to disable emitting
> > > warnings when passing an argument of an incompatible integer type to
> > > a 'd', 'i', 'o', 'u', 'x', or 'X' conversion specifier when it has
> > > the same precision as the expected type.  
> > 
> > I'd expect this to apply to 'b' and 'B' as well (affects commit
> > message, ChangeLog entry, option help string, documentation).
> > 
> 
> Hi Joseph,
> 
> I can't find any description of these specifiers anywhere. And looks

They're new specifiers in C23.  See the most recent working draft 
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2731.pdf>.

> like gcc doesn't recognize them when I try to compile a sample program

GCC should recognize them (i.e., not warn about them with -Wformat) if you 
have commit bd6f2c63168e89bede631daf8b673eab16acc747 (12 October).

> with them (I just get %B printed when I run the program).

If you want runtime support for those specifiers in printf, you'll need a 
libc implementation with support for them.  In glibc that means commit 
309548bec3b89022bbc81a372ec3e9240211d799 (10 November) or later, for 
example.
  
Daniil Stas Nov. 27, 2021, 10:20 p.m. UTC | #4
On Tue, 23 Nov 2021 22:48:24 +0000
Joseph Myers <joseph@codesourcery.com> wrote:

> On Tue, 23 Nov 2021, Daniil Stas via Gcc-patches wrote:
> 
> > On Mon, 22 Nov 2021 20:35:03 +0000
> > Joseph Myers <joseph@codesourcery.com> wrote:
> >   
> > > On Sun, 21 Nov 2021, Daniil Stas via Gcc-patches wrote:
> > >   
>  [...]  
> > > 
> > > I'd expect this to apply to 'b' and 'B' as well (affects commit
> > > message, ChangeLog entry, option help string, documentation).
> > >   
> > 
> > Hi Joseph,
> > 
> > I can't find any description of these specifiers anywhere. And
> > looks  
> 
> They're new specifiers in C23.  See the most recent working draft 
> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2731.pdf>.
> 

Ah, thank you.
I've sent an updated patch.
  

Patch

diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index e735e092043..c66787f931f 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -4248,7 +4248,7 @@  check_format_types (const substring_loc &fmt_loc,
 	  && (!pedantic || i < 2)
 	  && char_type_flag)
 	continue;
-      if (types->scalar_identity_flag
+      if ((types->scalar_identity_flag || !warn_format_int_precision)
 	  && (TREE_CODE (cur_type) == TREE_CODE (wanted_type)
 	      || (INTEGRAL_TYPE_P (cur_type)
 		  && INTEGRAL_TYPE_P (wanted_type)))
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3976fc368db..0621585a4f9 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -684,6 +684,12 @@  C ObjC C++ LTO ObjC++ Warning Alias(Wformat-overflow=, 1, 0) IntegerRange(0, 2)
 Warn about function calls with format strings that write past the end
 of the destination region.  Same as -Wformat-overflow=1.
 
+Wformat-int-precision
+C ObjC C++ ObjC++ Var(warn_format_int_precision) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=,warn_format >= 1, 0)
+Warn when passing an argument of an incompatible integer type to a 'd', 'i',
+'o', 'u', 'x', or 'X' conversion specifier even when it has the same precision
+as the expected type.
+
 Wformat-security
 C ObjC C++ ObjC++ Var(warn_format_security) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 2, 0)
 Warn about possible security problems with format functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4b1b58318f0..da69d804598 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -351,7 +351,7 @@  Objective-C and Objective-C++ Dialects}.
 -Werror  -Werror=*  -Wexpansion-to-defined  -Wfatal-errors @gol
 -Wfloat-conversion  -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul  -Wno-format-extra-args  @gol
--Wformat-nonliteral  -Wformat-overflow=@var{n} @gol
+-Wformat-nonliteral  -Wformat-overflow=@var{n} -Wformat-int-precision @gol
 -Wformat-security  -Wformat-signedness  -Wformat-truncation=@var{n} @gol
 -Wformat-y2k  -Wframe-address @gol
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object @gol
@@ -6113,6 +6113,21 @@  If @option{-Wformat} is specified, also warn if the format string is not a
 string literal and so cannot be checked, unless the format function
 takes its format arguments as a @code{va_list}.
 
+@item -Wformat-int-precision
+@opindex Wformat-int-precision
+@opindex Wno-format-int-precision
+Warn when passing an argument of an incompatible integer type to
+a @samp{d}, @samp{i}, @samp{o}, @samp{u}, @samp{x}, or @samp{X} conversion
+specifier even when it has the same precision as the expected type.
+For example, on targets where @code{int64_t} is a typedef for @code{long},
+the warning is issued for the @code{printf} call below even when both
+@code{long} and @code{long long} have the same size and precision.
+
+@smallexample
+  extern int64_t n;
+  printf ("%lli", n);
+@end smallexample
+
 @item -Wformat-security
 @opindex Wformat-security
 @opindex Wno-format-security
diff --git a/gcc/testsuite/c-c++-common/Wformat-int-precision-1.c b/gcc/testsuite/c-c++-common/Wformat-int-precision-1.c
new file mode 100644
index 00000000000..a06e047c933
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wformat-int-precision-1.c
@@ -0,0 +1,7 @@ 
+/* { dg-do compile { target { ! long_neq_int } } } */
+/* { dg-options "-Wformat" } */
+
+void test ()
+{
+  __builtin_printf ("%d\n", (long) 1); /* { dg-warning "expects argument of type" } */
+}
diff --git a/gcc/testsuite/c-c++-common/Wformat-int-precision-2.c b/gcc/testsuite/c-c++-common/Wformat-int-precision-2.c
new file mode 100644
index 00000000000..e9b41b4f42e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wformat-int-precision-2.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile { target { ! long_neq_int } } } */
+/* { dg-options "-Wformat -Wno-format-int-precision" } */
+
+void test ()
+{
+  __builtin_printf ("%d\n", (long) 1); /* { dg-bogus "expects argument of type" } */
+  __builtin_printf ("%d\n", (long long) 1); /* { dg-warning "expects argument of type" "" { target int32 } } */
+}