public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/66249] New: -Wformat-signedness should not warn on enums
@ 2015-05-21 16:56 eblake at redhat dot com
  2015-05-21 16:59 ` [Bug c/66249] " mpolacek at gcc dot gnu.org
  2020-11-06 13:28 ` peter at eisentraut dot org
  0 siblings, 2 replies; 3+ messages in thread
From: eblake at redhat dot com @ 2015-05-21 16:56 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 66249
           Summary: -Wformat-signedness should not warn on enums
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: eblake at redhat dot com
  Target Milestone: ---

The standard is clear that enums have implementation-defined signedness (C99
6.7.2.2P4 "Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined, but shall be capable of representing the values of all
the members of the enumeration.").  However, while there is a way to force gcc
to use a smaller or larger type (-fshort-enums), I don't know how to force gcc
to use a signed or unsigned type for enums whose members could fit in either. 
As such, since I cannot guarantee that compiling on some other platform will
want to use a different signedness, I'm forced to add casts any time I want to
print an enum, when using the new -Wformat-signedness (implied by -Wformat=2).

Here's a demonstration of what I mean (testing on Fedora rawhide):

$ gcc --version | head -n1
gcc (GCC) 5.1.1 20150422 (Red Hat 5.1.1-1)
$ cat foo.c
#include <stdio.h>
int main(void) {
  int i = 0;
  unsigned u = 0;
  enum e_signed { as, bs = -1 } es = as;
  enum e_unsigned { au, bu = 0xffffffff } eu = au;
  enum e_implementation { ai } ei = ai;
  printf ("%u %d %u %d %u %d %u %d\n", i, u, es, es, eu, eu, ei, ei);
  return 0;
}
$ gcc -Wformat -Wformat-signedness foo.c -o foo
foo.c: In function ‘main’:
foo.c:8:11: warning: format ‘%u’ expects argument of type ‘unsigned int’, but
argument 2 has type ‘int’ [-Wformat=]
   printf ("%u %d %u %d %u %d %u %d\n", i, u, es, es, eu, eu, ei, ei);
           ^
foo.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 3
has type ‘unsigned int’ [-Wformat=]
foo.c:8:11: warning: format ‘%u’ expects argument of type ‘unsigned int’, but
argument 4 has type ‘int’ [-Wformat=]
foo.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 7
has type ‘unsigned int’ [-Wformat=]
foo.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 9
has type ‘unsigned int’ [-Wformat=]
[dummy@rawhide64 ~]$ 

The warning for arguments 2, 3, 4, and 7 are expected (2 and 3 to show the
normal usage of the warning, 4/5 to show that I can force an enum to be signed
by including negative members, 6/7 to show that I can force an enum to be
unsigned by including members larger than INT_MAX); and the lack of warning for
arguments 5 and 6 is good.  I can squelch the warning for the first four
problematic arguments by either using the correct %d vs. %u counterpart, or by
changing the signedness of the variable that I'm printing.

However, argument 8/9 is problematic.  From the compiler warning on argument 9,
it looks like gcc defaults to unsigned, at least on my platform.  But I
_cannot_ know whether the compiler will pick a signed or unsigned
representation for the enum on other platforms (since all members would fit in
either type, and since the platform ABI may demand a particular signedness), so
I cannot know whether %u or %d would trigger a warning because I picked the
wrong type.  My only recourse is to add a cast (such as "%d",(int)ei); but that
is ugly.

And look what happens when I add -fshort-enums to the mix:

$ gcc -fshort-enums -Wformat -Wformat-signedness foo.c -o foo
foo.c: In function ‘main’:
foo.c:8:11: warning: format ‘%u’ expects argument of type ‘unsigned int’, but
argument 2 has type ‘int’ [-Wformat=]
   printf ("%u %d %u %d %u %d %u %d\n", i, u, es, es, eu, eu, ei, ei);
           ^
foo.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 3
has type ‘unsigned int’ [-Wformat=]
foo.c:8:11: warning: format ‘%u’ expects argument of type ‘unsigned int’, but
argument 4 has type ‘int’ [-Wformat=]
foo.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 7
has type ‘unsigned int’ [-Wformat=]
[dummy@rawhide64 ~]$ 

Here, arguments 4/5 are still signed, arguments 6/7 are still unsigned; but
arguments 8/9 are now a type compatible with 'char', and promotes to 'int'
(whether the enum's underlying type is signed or unsigned).  Oddly enough, the
compiler did not warn for EITHER 8 or 9, but by the technical argument, "%u"
should have warned for argument 8.  And consider what happens from a promotion
standpoint: if gcc picked 'char' (rather than 'signed char' or unsigned char')
as the underlying type when -fshort-enums is in effect, and my enum contained a
value in the range [128-255], then I am now dependent on whether 'char' is
signed or unsigned for whether %d will print 128 or -128 (and %u would print
128 or 4294967168).

Conversely, we should be able to reason that if the compiler was able to pick a
smaller type when -fshort-enums is in effect, and particularly if that smaller
type is unsigned, then it doesn't matter whether I use %u or %d - every value
of the enum will print to the same representation, and therefore, squelching
the warning was the right thing to do.  But if that is the case, then omitting
-fshort-enums should _also_ squelch the warning - again, if I have an enum that
has no members that require the use of 'int' (for an unsigned member) or
'unsigned' (for a member larger than INT_MAX), then we KNOW that the range of
the enum is such that both %u and %d will print it identically, regardless of
what type is actually assigned to the enum.

So I'm arguing that -Wformat-signedness has a bug, and should NOT print a
warning about a %d vs 'unsigned' mismatch when it is compared against an enum
value whose range could be reduced were -fshort-enums were in effect.

See also bug 65446 where -Wformat-signedness has issues when integer promotion
of smaller unsigned types is involved.
>From gcc-bugs-return-486987-listarch-gcc-bugs=gcc.gnu.org@gcc.gnu.org Thu May 21 16:58:38 2015
Return-Path: <gcc-bugs-return-486987-listarch-gcc-bugs=gcc.gnu.org@gcc.gnu.org>
Delivered-To: listarch-gcc-bugs@gcc.gnu.org
Received: (qmail 73547 invoked by alias); 21 May 2015 16:58:38 -0000
Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm
Precedence: bulk
List-Id: <gcc-bugs.gcc.gnu.org>
List-Archive: <http://gcc.gnu.org/ml/gcc-bugs/>
List-Post: <mailto:gcc-bugs@gcc.gnu.org>
List-Help: <mailto:gcc-bugs-help@gcc.gnu.org>
Sender: gcc-bugs-owner@gcc.gnu.org
Delivered-To: mailing list gcc-bugs@gcc.gnu.org
Received: (qmail 73517 invoked by uid 48); 21 May 2015 16:58:34 -0000
From: "eblake at redhat dot com" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug c/65446] Improve -Wformat-signedness
Date: Thu, 21 May 2015 16:58:00 -0000
X-Bugzilla-Reason: CC
X-Bugzilla-Type: changed
X-Bugzilla-Watch-Reason: None
X-Bugzilla-Product: gcc
X-Bugzilla-Component: c
X-Bugzilla-Version: 5.0
X-Bugzilla-Keywords: diagnostic
X-Bugzilla-Severity: normal
X-Bugzilla-Who: eblake at redhat dot com
X-Bugzilla-Status: UNCONFIRMED
X-Bugzilla-Resolution:
X-Bugzilla-Priority: P3
X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org
X-Bugzilla-Target-Milestone: ---
X-Bugzilla-Flags:
X-Bugzilla-Changed-Fields:
Message-ID: <bug-65446-4-NqeHJpCyfg@http.gcc.gnu.org/bugzilla/>
In-Reply-To: <bug-65446-4@http.gcc.gnu.org/bugzilla/>
References: <bug-65446-4@http.gcc.gnu.org/bugzilla/>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit
X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/
Auto-Submitted: auto-generated
MIME-Version: 1.0
X-SW-Source: 2015-05/txt/msg01827.txt.bz2
Content-length: 380

https://gcc.gnu.org/bugzilla/show_bug.cgi?ide446

--- Comment #3 from Eric Blake <eblake at redhat dot com> ---
see also bug 66249 where the implementation-defined signedness of enums comes
into play, and where I argue that neither %d nor %u should warn when an enum
type is passed through varargs where the range of the enum is identical through
either format representation.


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-11-06 13:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-21 16:56 [Bug c/66249] New: -Wformat-signedness should not warn on enums eblake at redhat dot com
2015-05-21 16:59 ` [Bug c/66249] " mpolacek at gcc dot gnu.org
2020-11-06 13:28 ` peter at eisentraut dot org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).