On 10/05/2016 05:54 PM, Joseph Myers wrote:
On Wed, 5 Oct 2016, Martin Sebor wrote:

On 10/05/2016 05:11 PM, Joseph Myers wrote:
On Wed, 5 Oct 2016, Martin Sebor wrote:

may have been subjected to.  Issuing a warning for a safe piece
of code only on the basis that there might be some other piece
of code in the program that does something wrong makes no sense.
Suggesting to the user to change the safe piece of code is
misleading and counterproductive.

It's warning because it's *bad code*.

Why?  What can go wrong and on what system?  Please name at least
one specific example.

It's bad because getting types wrong (more generally than just in this
case) is a careless coding practice.  It's a code smell.

There are lots of other "smells" that GCC doesn't warn about by
default even though it easily could, including -Wformat-signedness.

The problem is that extracting via an integer of the opposite signedness
is *not* defined unless the argument has a value representable in both
types - both as a matter of ISO C rules on variadic functions, and as a
practical matter of what various ABIs say about how sub-word arguments are
extended when passed as function arguments.

No, sign mismatch is not the problem we're discussing.  GCC doesn't
warn for %lc when wchar_t and wint_t differ in signedness except
with -Wformat-signedness.  The cause of the warning is that wchar_t
is a distinct type from wint_t such as long from int (irrespective
of their sign), even if the two have the same size, and the checker
doesn't distinguish the typedefs from the underlying types.

My position is that when int and long have the same size, although
warning for objects of those types is appropriate because their
sizes often do differ from one target to the next, the %lc warning
is unhelpful because, unlike the underlying types, wchar_t and
wint_t are specifically designed to be interoperable and the same
propensity for a difference in size doesn't apply to them.

I did say, however, that the warning might have some merit even
in this case if there also were a target to which the code could
be ported where wchar_t and wint_t had different sizes (i.e., as
a portability warning).  But for such a portability warning to
be useful it would need to be issued by all GCC compilers, not
just when compiling for the target with that property.  (But
since neither of us knows(*) of such a target this is a moot
point.)

But my basic point is: if something can lead to analysis in this level of
detail of whether the code is or is not safe in a particular context,
while there is a trivial fix to the code that would short-circuit all that
analysis, that by itself is enough evidence that the code deserves a
warning and should be cleaned up to make it more obviously safe.

The premise that "it's trivial to fix" is wrong and at the core
of my objection to the warning (by default; I would have no issue
with it being issued under a separate option or under -Wpedantic).

The text of the warning itself indicates that even suggesting how
to fix it isn't trivial.  GCC warns for just for the %lc directive
(not for the sign mismatch) and suggests to fix it by replacing
the %lc directive with %ld.  That's clearly wrong.  Printing
a hint with fix you're looking for (i.e., casting the argument
to wint_t) may be difficult because of the lack of location
information for local variables.

  $ cat a.c && gcc -S -Wall -m32 a.c
  typedef __WCHAR_TYPE__ wchar_t;

  void f (int x, unsigned y)
  {
    extern wchar_t w;

    __builtin_printf ("%lc", w);
    __builtin_printf ("%lc", x);
    __builtin_printf ("%lc", y);
  }
  a.c: In function ‘f’:
a.c:7:24: warning: format ‘%lc’ expects argument of type ‘wint_t’, but argument 2 has type ‘wchar_t {aka long int}’ [-Wformat=]
     __builtin_printf ("%lc", w);
                        ~~^
                        %ld

But I think we're both starting to repeat ourselves without making
any headway.  I spent more time on this discussion (and the research
I did for it) than I should have an I don't view this as serious
enough of a problem to be worth spending more time on, just a minor
wart in GCC.  There are plenty others with a much better ROI.

Martin

[*] Since you've persistently dodged the question about the target
where this might be a problem I surveyed the GCC config files to
see if I could find one.  All but two of the operating systems GCC
apparently knows about define wint_t to be an alias for signed int.
The two exceptions are Ming32 and VxWorks both of which define both
wint_t and wchar_t to be unsigned short, and so those two targets
can be ruled out.

Besides these, the are a bunch of back ends that define wchar_t
to be long where, if long were wider than int, calling
printf("%lc", L'x') would be a problem.  But based on a closer
review of some of these targets it looks like they define both
int and long as 32-bit types and so there is no issue there.
I didn't look at all of them but defining wint_t to be narrower
than wchar_t would make no sense because then the former wouldn't
be able to represent all the values of the latter, which it is
specifically intended to do.  So while I can't definitively say
that no such target exists, it seems exceedingly unlikely.
Given that, it's pretty conclusive that issuing the warning is
not necessary or helpful on any target.

Reply via email to