Andrew Haley wrote:
ISO/IEC 14882:1998(E)
5 Expressions
9
That's _chapter_ 5 [expr], para 9 over here.
vs. 4.7 "Integral conversions" as in the subject of the OP.
Right, and you have now had the exact language quoted to you.
Which, surprise, makes no mention of integral conversions nor
references to section 4.7 [conv.integral]. There, para 7 deserves
special attention:
"The conversions allowed as integral promotions are excluded from
the set of integral conversions."
That was the whole point of the OP (Did you read the subject ?).
But back to the original example:
Your first example was
int64_t a;
uint32_t b = 8;
a = -(b * 2u);
So, the last section of Para 9 applies: b is promoted to unsigned
int,
According to the OP b is of type uint32_t which coincidentally in
this particular example on a 32 bit machine, is a typedef from
unsigned int. Contrary to what the specifier may suggest, we all
know that ``typedef'' actually only introduces another name or
_alias_ for the name of the type that is given in a typedef
declaration. The literal constant 2u is, again, of type unsigned
int. According to 5.6 [expr.mul], (b * 2u) then yields a result
that is of type unsigned int. Where was there integral promotion
applied again ?
int64_t a;
uint32_t b = 8;
a = -((int64_t )(b * 2u));
the unsigned int result of (b * 2u) is converted to int64_t and
that is negated.
As already stated elsewhere, this only _happens_ to be the correct
result. If b = 0xffffffff, then the above version yields the
negated value of (b * 2u), the latter being not closed over
the set that uint32_t represents producing a modulo 2^32 result.
If, as already assumed elsewhere, the 32 bit machine in question
provided a 32 unsigned integer multiplication that produces a 64
bit unsigned integer result, the compiler will _never_ emit code
using this instruction based on information withheld by a standard
conforming frontend that the type of the result _must_ be that
of the operands and precluding the conversion to a type large
enough such that the multiplication is closed. A 64 bit unsigned
int can then be negated yielding a _negative_ number as the correct
result. The latter can be enforced by a statement like
a = -(((uint64_t )b) * 2u);
which, however, requests a 64 bit unsigned integer multiplication
which may be non existent or abysmally slow on the target. This
is the problem that _can_ precisely be avoided by integral conversion
applied during the multiplication operation.
Cheers,
Christian