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

* [Bug c/66249] -Wformat-signedness should not warn on enums
  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 ` mpolacek at gcc dot gnu.org
  2020-11-06 13:28 ` peter at eisentraut dot org
  1 sibling, 0 replies; 3+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2015-05-21 16:59 UTC (permalink / raw)
  To: gcc-bugs

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

Marek Polacek <mpolacek at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2015-05-21
                 CC|                            |mpolacek at gcc dot gnu.org
     Ever confirmed|0                           |1

--- Comment #1 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
-Wformat-signedness has many issues (which was the reason it's been pulled out
of -Wformat=2).


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

* [Bug c/66249] -Wformat-signedness should not warn on enums
  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
  1 sibling, 0 replies; 3+ messages in thread
From: peter at eisentraut dot org @ 2020-11-06 13:28 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Peter Eisentraut <peter at eisentraut dot org> ---
The GCC documentation on implementation-defined behavior states that enums are
unsigned unless negative values are included.  It says that -fshort-enums is
the default for some ABIs, but there is no indication that signed enums are the
default on some ABIs or platforms or other circumstances.  If that is accurate,
then it would seemingly be okay to use %u for enums in most cases (unless they
are signed by inclusion of a negative value) without worries about platform
differences.

^ 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).