%zd and %td support in attribute format printf
Thank you for this exemplary issue report; I do so wish that all ticket submissions could be so diligently formatted, comprehensively detailed, and complemented by such a well specified, compact, yet complete test case.
I can confirm that your issue is reproduced by my own mingw32-gcc cross-compiler suite, (which FWIW, is the self-same implementation that I used to create the official MinGW.OSDN distribution of GCC-9.2.0):
$ mingw32-gcc -v -Wall -fsyntax-only a.c Using built-in specs. COLLECT_GCC=mingw32-gcc COLLECT_LTO_WRAPPER=/home/keith/mingw32-gcc-9.2.0/bin/../libexec/gcc/mingw32/9.2.0/lto-wrapper Target: mingw32 Configured with: ../src/gcc-9.2.0/configure --target=mingw32 --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-static --enable-shared --enable-threads --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libgomp --disable-libvtv --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --disable-build-format-warnings --prefix=/home/keith/mingw32 --with-sysroot=/home/keith/mingw32 --disable-nls --with-pkgversion='MinGW.org Cross-GCC Build-20200531-1' Thread model: win32 gcc version 9.2.0 (MinGW.org Cross-GCC Build-20200531-1) COLLECT_GCC_OPTIONS='-v' '-Wall' '-fsyntax-only' '-mtune=generic' '-march=i586' /home/keith/mingw32-gcc-9.2.0/bin/../libexec/gcc/mingw32/9.2.0/cc1 -quiet -v -iprefix /home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/ -isysroot /home/keith/mingw32-gcc-9.2.0/bin/../../mingw32 a.c -quiet -dumpbase a.c -mtune=generic -march=i586 -auxbase a -Wall -version -fsyntax-only -o /dev/null GNU C17 (MinGW.org Cross-GCC Build-20200531-1) version 9.2.0 (mingw32) compiled by GNU C version 9.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.21-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 ignoring nonexistent directory "/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/include" ignoring duplicate directory "/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/../../lib/gcc/mingw32/9.2.0/include" ignoring nonexistent directory "/home/keith/mingw32-gcc-9.2.0/bin/../../mingw32/usr/local/include" ignoring duplicate directory "/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/../../lib/gcc/mingw32/9.2.0/include-fixed" ignoring nonexistent directory "/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/../../lib/gcc/mingw32/9.2.0/../../../../mingw32/include" #include "..." search starts here: #include <...> search starts here: /home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/include /home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/include-fixed /home/keith/mingw32-gcc-9.2.0/bin/../../mingw32/mingw/include End of search list. GNU C17 (MinGW.org Cross-GCC Build-20200531-1) version 9.2.0 (mingw32) compiled by GNU C version 9.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.21-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 43d95314bbda36f2d474b814015ff720 a.c: In function 'main': a.c:8:16: warning: unknown conversion type character 'z' in format [-Wformat=] 8 | return foo("%zd\n", f); | ^ a.c:8:14: warning: too many arguments for format [-Wformat-extra-args] 8 | return foo("%zd\n", f); | ^~~~~~~ COMPILER_PATH=/home/keith/mingw32-gcc-9.2.0/bin/../libexec/gcc/mingw32/9.2.0/:/home/keith/mingw32-gcc-9.2.0/bin/../libexec/gcc/:/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ LIBRARY_PATH=/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/:/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/:/home/keith/mingw32-gcc-9.2.0/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/lib/:/home/keith/mingw32-gcc-9.2.0/bin/../../mingw32/lib/ COLLECT_GCC_OPTIONS='-v' '-Wall' '-fsyntax-only' '-mtune=generic' '-march=i586'However, I do feel obliged to point out that the compilers, which you are using, are not products of our MinGW.OSDN Project, and we are unable to support them; consequently, while we may be able to offer generic advice, we can offer no guarantees that such advice will actually apply, in your specific use case. Furthermore, I would like to challenge this assertion, in your original submission:
MS compiler supports %zd as the preferred way to print size_t values
While this may be true of recent versions of the MS compiler, (and likely requires that the application be linked with Microsoft's non-free Universal C Runtime Library, or any the non-free runtime libraries which are distributed as components of the MSVC suite itself), it is not true in the case of applications which are linked (as MinGW applications must be) with MSVCRT.DLL; (note that, although itself technically non-free, MSVCRT.DLL is distributed as a fundamental OS component, and is sufficiently self-contained to let us use it under the GPL exemption for such OS components; unfortunately, although AIUI the UCRT is also provided as an OS component, it is not self-contained, and its dependencies, which are not so distributed, render it fundamentally useless in this context).
Now, I realize that I have not yet actually addressed the issue, which you have raised; in the interests of keeping follow-up comments at a manageable size, I will defer further discussion to a later comment.
In my earlier comment, I indicated that I observe the same behaviour as that described in the original report; for reference, here is the compiler output, without the added noise of GCC version, and configuration information:
$ mingw32-gcc -Wall -fsyntax-only a.c a.c: In function 'main': a.c:8:16: warning: unknown conversion type character 'z' in format [-Wformat=] 8 | return foo("%zd\n", f); | ^ a.c:8:14: warning: too many arguments for format [-Wformat-extra-args] 8 | return foo("%zd\n", f); | ^~~~~~~In addition to this, I also dropped a hint — you may, or may not have noticed it — as to why this may actually be considered to be correct behaviour. Unlike Microsoft's compilers — which use non-free runtime libraries, none of which are legally redistributable without purchase of a Microsoft developer's licence — MinGW compilers produce applications which are linked with MSVCRT.DLL. Although also proprietary, Microsoft distribute this as a component of the Windows operating system, so no redistribution is necessary; however, the stdio implementation in MSVCRT.DLL — and specifically its printf() family of functions — does not support the "%zd" or "%td" format specifications. Since the MinGW compilers — at least those which we distribute — use the MSVCRT.DLL printf() implementation, by default, it seems reasonable that -Wformat should warn that these format specifications are unsupported.
Of course, default behaviour isn't always appropriate ... and it probably isn't, in your particular use case. The intent of my emphasis — of by default — in the preceding paragraph, is to indicate that we are not simply stuck with default behaviour; there are techniques, which we may adopt to work around this issue, and which I will address in a further follow-up comment.
A review of the relevant section of the GCC manual should provide enlightenment ... search for the "format" attribute sub-heading. I kind of suspected that we might arrive at this conclusion: the behaviour here is exactly as documented, so there is no bug to address, (other than user error).
The GCC documentation is rather terse, so some further explanation may be helpful. If we review your original test case (with line numbers inserted):
This should compile fine, (probably) with any target variant of GCC except a MinGW variant. See, a MinGW target GCC implements (at least) two distinct flavours of the "printf" category for the "format" attribute, namely "gnu_printf" and "ms_printf" — whereas most targets comprehend only "gnu_printf" — and for the MinGW target, "printf" is interpreted as "ms_printf". Thus, your test case effectively becomes:
and this leads to a -Wformat anomaly at line 7, because "%zd" is not a valid format specification, within the "ms_printf" category, as specified at line 2. If your function "foo()" interprets format specifications according to "gnu_printf" rules, then you need to specify that explicitly:
FWIW, our MinGW.OSDN builds of GCC, from GCC-6.3.0 onwards, implement a third category of "printf" Wformat checks, namely "mingw_printf"; (other distributions may not support this). Used thus:
this creates a hybrid of both "ms_printf" and "gnu_printf", (with any conflicts resolved in favour of the "gnu_printf" interpretation), and provides correct -Wformat checking for the "printf()" family replacement functions, which we provide in our libmingwex.a, and libmingwex-4.dll libraries.
With either "gnu_printf", or "mingw_printf" specified as the format attribute category, in line 2 of your test case, compilation succeeds without warnings:
$ mingw32-gcc -Wall -fsyntax-only a.c $Consequently, I am closing this ticket, with no further action required.
sample a.c
this simple program, compiled with -Wall warns about unsupported %zd
whereas gcc compiles the snipnet just fine
version info
version info
MS compiler supports %zd as the preferred way to print size_t values
(didn't included in the tests, but %td for ptrdiff_t suffers from the same issues)