https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77970

            Bug ID: 77970
           Summary: inconsistent and unhelpful -Wformat warning for %lc
           Product: gcc
           Version: 7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

The following snippet compiles with no warnings on popular 64-bit targets
including powerpc64-*-linux, sparc-sun-solaris2.10, and x86_64-*-linux. 
However, on a number of 32-bit targets the same code causes GCC to issue a
warning about one or the other call pedantically complaining about either the
literal zero not having the expected type of wint_t (e.g., where wint_t is an
alias for long) even though the two have the same size and sign, or about the
L'a' argument not having the wint_t type for the same reason (the type of L'a'
is wchar_t).  (This is analogous to warnings issued for %li with an int
argument, or for %i with a long argument, on ILP32.)

  printf ("%lc", 0);
  printf ("%lc", L'a');

Unlike the warnings for ordinary integer directives which is issued
consistently, issuing the warning for %lc inconsistently, based on the
underlying type of wchar_t and wint_t, and only on uncommon targets and not on
mainstream targets where most code is developed is unhelpful for portability
and only serves to cause code to fail to compile when ported (see for example
the thread around https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00993.html for
the effort it took to clean up these warnings in the builtin-sprintf*.c tests).

Issuing the warning when both the sign and the size of the argument are the
same as those expected is useless entirely since objects of the two types are
indistinguishable.  (The warning is not issued when the types only differ in
signedness such as int and unsigned int unless the -Wformat-signedness option
is explicitly specified.)

To be useful for portability, the warning should be issued consistently on all
targets, especially those where most development is done (LP64 targets such
powerpc64-*-linux and x86_64-*-linux.  The warning is also only useful if there
exists a target where wint_t and wchar_t (for the L'a' case) or int (for the
int argument case) are different sizes.  If there is no such target (I don't
know of one and a survey of GCC config files didn't reveal one either) the
warning isn't useful even if wint_t and wchar_t differ in sign because sign
mismatches are handled separately under the -Wformat-signedness option.

As a data point, Clang stopped issuing this warning in 2011 in response to the
following Clang bug:

  https://llvm.org/bugs/show_bug.cgi?id=7981

GCC should do the same and either suppress the warning altogether or issue it
only with -Wpedantic.

Test case:

$ (set -x && cd ~/tmp && cat a.c && for t in i386-rehat-linux
sparc-sun-solaris2.12 x86_64-unknown-solaris2.10 bfin-uclinux m68k-linux
hppa-unknown-linux-gnu; do /build/sysroot/$t/bin/$t-gcc -S -Wall -o/dev/null
a.c; done)
+ cd /home/msebor/tmp
+ cat a.c
typedef __WCHAR_TYPE__ wchar_t;

void f (void)
{
  __builtin_printf ("%lc", 0);
  __builtin_printf ("%lc", L'a');
}
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/i386-rehat-linux/bin/i386-rehat-linux-gcc -S -Wall -o/dev/null
a.c
a.c: In function 'f':
a.c:6:24: warning: format '%lc' expects argument of type 'wint_t', but argument
2 has type 'long int' [-Wformat=]
   __builtin_printf ("%lc", L'a');
                      ~~^
                      %ld
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/sparc-sun-solaris2.12/bin/sparc-sun-solaris2.12-gcc -S -Wall
-o/dev/null a.c
a.c: In function 'f':
a.c:5:24: warning: format '%lc' expects argument of type 'wint_t', but argument
2 has type 'int' [-Wformat=]
   __builtin_printf ("%lc", 0);
                      ~~^
                      %c
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/x86_64-unknown-solaris2.10/bin/x86_64-unknown-solaris2.10-gcc
-S -Wall -o/dev/null a.c
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/bfin-uclinux/bin/bfin-uclinux-gcc -S -Wall -o/dev/null a.c
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/m68k-linux/bin/m68k-linux-gcc -S -Wall -o/dev/null a.c
a.c: In function 'f':
a.c:6:24: warning: format '%lc' expects argument of type 'wint_t', but argument
2 has type 'long int' [-Wformat=]
   __builtin_printf ("%lc", L'a');
                      ~~^
                      %ld
+ for t in i386-rehat-linux sparc-sun-solaris2.12 x86_64-unknown-solaris2.10
bfin-uclinux m68k-linux hppa-unknown-linux-gnu
+ /build/sysroot/hppa-unknown-linux-gnu/bin/hppa-unknown-linux-gnu-gcc -S -Wall
-o/dev/null a.c
a.c: In function 'f':
a.c:6:24: warning: format '%lc' expects argument of type 'wint_t', but argument
2 has type 'long int' [-Wformat=]
   __builtin_printf ("%lc", L'a');
                      ~~^
                      %ld

Reply via email to