64-bit enums and left shift operator - invalid code or GCC bug?

Andrew Haley aph@redhat.com
Fri Jun 27 12:17:00 GMT 2008


Jens Kilian wrote:
> Consider the following test program:
> --8<------------------------------------------------8<---
> #include <stdint.h>
> #include <stdio.h>
> 
> typedef enum {
>   FOO = 1LL << 0,
>   BAR = 1LL << 1,
>   BAZ = 1LL << 63
> } Foo;
> 
> int
> main(void)
> {
>   uint64_t zip = (FOO << 32) | BAR;
>   uint64_t qux = ((Foo)FOO << 32) | BAR;
>   printf("%llx %llx\n", zip, qux);
>   return 0;
> }
> --8<------------------------------------------------8<---
> 
> This causes different behavior in GCC 3.2.3 (i386) vs. 4.1.2 (x86_64):
> 
> ~ % gcc -v
> Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
> Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
> Thread model: posix
> gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-54)
> ~ % gcc -o foo foo.c
> ~ % ./foo
> 100000002 100000002
> 
> ~ % gcc -v
> Using built-in specs.
> Target: x86_64-redhat-linux
> Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=x86_64-redhat-linux
> Thread model: posix
> gcc version 4.1.2 20070626 (Red Hat 4.1.2-14)
> ~ % gcc -o foo foo.c
> foo.c: In function 'main':
> foo.c:13: warning: left shift count >= width of type
> ~ % ./foo
> 2 100000002
> 
> Apparently GCC 4.1.2 converts the value of FOO to 32 bits before doing the
> shift; the bizarre thing is that casting to Foo (which should be unnecessary)
> avoids this.
> 
> Is this a GCC bug, or does the standard really require this conversion?

It's a bug.  C99 says an enumerated type shall be large enough to
represent all its members, and that when promoting the rank of the
enumerated type shall equal the rank of the compatible integer type.

Andrew.



More information about the Gcc-help mailing list