Error when testing clang with VC++ RTL and Boost MPL

I am seeing this error when testing Boost MPL with clang using the VC++ RTL:

"bitwise.cpp(40,25) : error: non-type template argument evaluates to 4294967295, which cannot be narrowed to type 'long' [-Wc++11-narrowing]
MPL_ASSERT_RELATION( (bitor_<_0,_ffffffff>::value), ==, 0xffffffff );"

The typedefs are:

typedef integral_c<unsigned int, 0> _0;
typedef integral_c<unsigned int, 0xffffffff> _ffffffff;

The bitor_ in the Boost MPL is evaluating constants at compile time, doing a bitwise or ('|').

Why does clang think that 0xffffffff is a 'long' when used in the comparison ? According to the C++ standard the type of 0xffffffff is the first of int, unsigned int, long, unsigned long, long long, unsigned long long in which its value can fit ( section 2.14.2 ). Is this a clang bug ?

Sorry, the problem is not as I had assumed above. It is actually because the MPL_ASSERT_RELATION macro devolves down to a template class where the values are of type 'long'. Is there something in C++11 which says that implicit conversion of a value from an 'unsigned int' to a 'long' is illegal ? That is what clang is telling me but I can find no such restriction in the C++11 standard regarding this.

I think it’s more likely that on Windows ‘long’ is the same size as ‘int’, and so you have an overflow error. You need to fix the template…which I guess means submitting a patch to Boost.

If you’re just looking for a quick workaround, though, the presence of “-Wc++11-narrowing” in the error message is a hint: you can demote this no a warning using -Wno-error=c++11-narrowing.

Jordan

There's something like this, yes. When you have a template-parameter of
some integral type T, a template-argument for that parameter must be a
converted constant expression of type T. Converted constant expressions
don't allow narrowing conversions in the final implicit conversion from
their value to type T. And the conversion from 4294967295 to type 'long' is
a narrowing conversion, because that value does not fit in the type 'long'.
So the program is ill-formed.

I tried a patch of the test code where I set:

typedef integral_c<int, 0xffffffff> _ffffffff;

but clang still complains that:

bitwise.cpp(23,24) : error: non-type template argument evaluates to 4294967295, which cannot be narrowed to type 'int' [-Wc++11-narrowing]
typedef integral_c<int, 0xffffffff> _ffffffff;

This I do not understand. Why does 0xffffffff evaluate to 4294967295 rather than -1 ? Where in the C++ standard does it say that hex literals are unsigned values by default ?

Nothing to do with hex literals, just literals in general. If they don't
fit in the range of an int, the literal is of unsigned int type so it can
fit the value.

2.14.2/2

In article <CAOfiQq=_WFp2pX4G1tD6=2OZp_HsyYFyW4u34Kv=u4kW7uzMbw@mail.gmail.com>,
    Richard Smith <richard@metafoo.co.uk> writes:

On Wed, Nov 13, 2013 at 1:58 PM, Edward Diener <
> This I do not understand. Why does 0xffffffff evaluate to 4294967295
> rather than -1 ? Where in the C++ standard does it say that hex literals
> are unsigned values by default ?

2.14.2/2

To clarify: it's not the 0x that turns it into unsigned, it's that the
quantity 0xffffffff cannot be represented as a 32-bit signed integer
because it specifies 32-bits worth of 1's, but it does fit into a
32-bit unsigned integer, so that's what the compiler uses.

A more interesting question would be what happens to ~0....

Why is not 0xffffffff equal to -1 as a 32-bit signed integer ? Something seems really strange if that is not the case.

Is not -1 in the range of an 'int' ? Is not 0xffffffff equivalent to -1 as a signed value ? What am I missing here ?

        On Nov 13, 2013, at 11:47 , Edward Diener
        <eldlistmailingz@tropicsoft.__com
        <mailto:eldlistmailingz@tropicsoft.com>
        <mailto:eldlistmailingz@__tropicsoft.com

        <mailto:eldlistmailingz@tropicsoft.com>>>
        wrote:

                I am seeing this error when testing Boost MPL with clang
                using the VC++
                RTL:

                "bitwise.cpp(40,25) : error: non-type template argument
                evaluates to
                4294967295, which cannot be narrowed to type 'long'
                [-Wc++11-narrowing]
                MPL_ASSERT_RELATION( (bitor_<_0,_ffffffff>::value), ==,
                0xffffffff );"

                The typedefs are:

                typedef integral_c<unsigned int, 0> _0;
                typedef integral_c<unsigned int, 0xffffffff> _ffffffff;

                The bitor_ in the Boost MPL is evaluating constants at
                compile time,
                doing a bitwise or ('|').

                Why does clang think that 0xffffffff is a 'long' when
                used in the
                comparison ? According to the C++ standard the type of
                0xffffffff is the
                first of int, unsigned int, long, unsigned long, long
                long, unsigned
                long long in which its value can fit ( section 2.14.2 ).
                Is this a clang
                bug ?

            Sorry, the problem is not as I had assumed above. It is
actually
            because the MPL_ASSERT_RELATION macro devolves down to a
            template
            class where the values are of type 'long'. Is there
            something in C++11
            which says that implicit conversion of a value from an
            'unsigned int'
            to a 'long' is illegal ? That is what clang is telling me
            but I can
            find no such restriction in the C++11 standard regarding this.

        I think it’s more likely that on Windows ‘long’ is the same size
as
        ‘int’, and so you have an overflow error. You need to fix the
        template…which I guess means submitting a patch to Boost.

    I tried a patch of the test code where I set:

    typedef integral_c<int, 0xffffffff> _ffffffff;

    but clang still complains that:

    bitwise.cpp(23,24) : error: non-type template argument evaluates to
    4294967295, which cannot be narrowed to type 'int' [-Wc++11-narrowing]
    typedef integral_c<int, 0xffffffff> _ffffffff;

    This I do not understand. Why does 0xffffffff evaluate to 4294967295
    rather than -1 ? Where in the C++ standard does it say that hex
    literals are unsigned values by default ?

Nothing to do with hex literals, just literals in general. If they don't
fit in the range of an int, the literal is of unsigned int type so it
can fit the value.

Is not -1 in the range of an 'int' ?

Yes.

Is not 0xffffffff equivalent to -1 as a
signed value ?

I'm not sure that's even a well-formed question. 0xffffffff (on a
32-bit platform) is _not_ a signed value, so it's not _anything_ "as a
signed value". In a context that requires a converted constant
expression, it's not convertible to a signed int (because its value is
not in the range of int -- its value is 2^31-1, not -1).

-- James

In article <l6109m$4sj$1@ger.gmane.org>,
    Edward Diener <eldlistmailingz@tropicsoft.com> writes:

Why is not 0xffffffff equal to -1 as a 32-bit signed integer ? Something
seems really strange if that is not the case.

A 32-bit signed integer has 31 bits of mantissa and 1 bit of sign.
They are a little comingled together in 2's complement notation, but I
don't think C++ requires 2's complement arithmetic.

0xffffffff specifies 32-bits worth of mantissa.

In article <l610fi$4sj$3@ger.gmane.org>,
    Edward Diener <eldlistmailingz@tropicsoft.com> writes:

Is not -1 in the range of an 'int' ?

Yes, but you didn't write -1 in your source file.

Is not 0xffffffff equivalent to -1
as a signed value ?

No. They are two different integer literals.

What am I missing here ?

Read the mentioned section of the standard carefully. I've read this
part and it isn't particularly confusing or difficult.

I even implemented the requirements of that section as part of a C++
source file tokenizer.

I think you meant 2^32 - 1,

In two's complement notation 0xffffffff is equal to -1 as a signed 32-bit integer and 4294967295 ( 2^32 - 1 ) as an unsigned 32-bit integer. Since an integer comes before an unsigned integer in 2.14.2 paragraph 2 of the C++ standard for the type of a hex literal I would have expected 0xffffffff to be of type 'int' unless otherwise specified. But what you seem to be saying is that the value of a hexadecimal ( or octal ) literal is always calculated as its actual value as a positive amount and only then is a type assigned based on whether that value can fit into the first of the series of types given in 2.14.2 paragraph 2. If that is the case my understanding of how this works is my own confusion, and I am glad to be enlightened. Thanks !

Hello,
My interpretation of this is that 2.14.2 defines how the compiler interprets the
literal. That isn't the problem though. The problem arises, when you attempt to
implicitly convert the compiler's interpretation to a signed integer. And the
error is narrowing. clang emits this error:

hexLiteralsUnsigned.cpp:16:24: error: constant expression evaluates to 4294967295 which cannot be
      narrowed to type 'int' [-Wc++11-narrowing]
    signed int isigned{0xFFFFFFFF};

You can avoid this error by simply using a cast:
signed int isigned{static_cast<signed int>(0xFFFFFFFF)};

FYI, g++-4.8.1 only emits a warning about the narrowing, then successfully completes the
compilation. Based on the standard section 8.5.4, I believe clang is correct to emit the
error. And 5.17.9 declares an assignment, such as 'int i = {0XFFFFFFFF};' to be a narrowing
error as well. I believe clang is correct to emit a narrowing error.

enjoy,
Karen

That is OK, now that I understand it. Interesting enough, however, if I use '0xffffffffL' I still get an error from clang but if I use 'static_cast<long>(0xffffffff)' everything is fine. That is a difference I would never have suspected, but at least I know now it is there.

It helps if you stop thinking about hex constants as bit patterns, because the compiler doesn’t at that point. It interprets a hex constant in the same way your math teacher would. Only when it has to assign a type (including via the ‘L’ suffix) does it then try to truncate/reinterpret that value as signed or unsigned.

One way in which this surfaces is that you can use hex constants in the preprocessor, which doesn’t have types:

#if 0xffffffff > 0
#warning “hex is positive”
#else
#warning “hex is negative"
#endif

Jordan