Subject: Re: cast truncates bits from constant value (8000000000000000 becomes 0)

From: Al Viro <[email-masked]>
Date: Fri, 1 Dec 2006 14:39:40 +0000

On Fri, Dec 01, 2006 at 03:25:08PM +0100, Geert Uytterhoeven wrote:
> On Tue, 21 Nov 2006, Geoff Levand wrote:
> > +enum ps3_vendor_id {
> > +	PS3_VENDOR_ID_NONE = 0,
> > +	PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> > +};
> 
> I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
> and noticed that sparse (cloned from
> git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
> complains about the second value with:
> 
> | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
> 
> Section 6.7.2.2.4 of C99 says:
> 
> | 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.

FWIW, that code is *not* valid C99; note that all enumeration members must
fit the range of int (see 6.7.2.2.2).  What you quote speaks about the
objects of type enum <something>, which is not the same as type of enum
members.  In C99 it's int, plain and simple.  Value outside of the range
of int => undefined behaviour.  Note that with
	enum foo {A, B} x;
you might very well have sizeof(A) != sizeof(x).

IOW, you are using a gccism in an area where gcc is bloody inconsistent
in the set of bugs it shows in different versions.

Generally safe way is to split the anonymous huge enum members into
single-element enums and pray that gcc will at least stay consistent
in handling of those.