Compiling this code (http://goo.gl/aKLau6):
#include <cstdint>#include <type_traits>
int main (){ auto x = std::uint8_t{5}; x += std::uint8_t{1}; static_assert(std::is_same<decltype(x += std::uint8_t{1}), std::uint8_t &>::value, "");
auto y = std::int16_t{6}; y <<= std::int16_t{2}; static_assert(std::is_same<decltype(y <<= std::int16_t{2}), std::int16_t &>::value, "");}
$ g++-5 -Wconversion -std=c++14 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:6:7: warning: conversion to ‘unsigned char’ from ‘int’ may alter its value [-Wconversion]
x += std::uint8_t{1};
^
main.cpp:9:7: warning: conversion to ‘short int’ from ‘int’ may alter its value [-Wconversion]
y <<= std::int16_t{2};
^
Note that even for arithmetic assignment operations the behavior is different from what it would be if the operation were carried out in the operand type, as signed overflow is implementation-defined when the intermediate result is representable in int but not in the operand type; it is only undefined when overflow occurs in int.
The compiler warnings do appear redundant in your case, but compiler warnings are not specified by the standard. Have you contacted your compiler vendor to request that they suppress the warning in the case of arithmetic assignment operations?
std::uint16_t x = 0xFFFF;
x *= x;
The thing with unsigned types being promoted to signed ones has always been a point one ends up having to address when debating others about the design of c++ versus other languages... and it's pretty indefensible. Is there _anything_ good about this silly "feature" rather than promoting to an unsigned int instead?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
The thing with unsigned types being promoted to signed ones has always been a point one ends up having to address when debating others about the design of c++ versus other languages... and it's pretty indefensible. Is there _anything_ good about this silly "feature" rather than promoting to an unsigned int instead?
On Thu, Feb 4, 2016 at 4:52 AM, Nicol Bolas <jmck...@gmail.com> wrote:
>
> If you can find a way to change it without breaking the world, I'd love to hear it. Otherwise, good or bad, it's what we've got.
It might be possible to track "promotedness" through an expression and intervene to prevent UB occurring.
Here's a sketch:
1. Introduce a new expression category, *unsigned-promoted-to-signed expression*.
2. When a prvalue of unsigned integral type is promoted to a signed type, the result is an unsigned-promoted-to-signed expression.
3. When the usual arithmetic conversions are applied to the operands of an arithmetic operation or to the second and third operands of a ternary conditional expression, if one operand is an unsigned-promoted-to-signed expression of the same type as the result type and the other operand either a) is an unsigned-promoted-to-signed expression, b) has type of lesser rank than the result type, or c) is a constant expression having value representable in the unsigned type corresponding to the result type, the result is an unsigned-promoted-to-signed expression.
4. If the operand to a unary arithmetic operation or the left operand to an arithmetic shift operation is an unsigned-promoted-to-signed expression, the result is an unsigned-promoted-to-signed expression.
5. If the operand to a parenthesized expression or the right operand to a comma expression is an unsigned-promoted-to-signed expression, the result is an unsigned-promoted-to-signed expression.
6. When the result of an arithmetic operation is not representable in the result type, if the result is an unsigned-promoted-to-signed expression, the result of the operation is first converted to the unsigned type corresponding to the result type according to the rules of 2^n modulo arithmetic, and from there converted to the result type according to the rules of arithmetic conversion. [Note: - the result may be implementation-defined if the value in the corresponding unsigned type is not representable in the result type, but is never undefined. - end note]
I don't think it quite works for shift operations, but I hope you can see the sort of thing that would be required. The question is whether the additional ugliness and confusion would be worth it; or whether the effort of confirming that a promoted expression is covered by those rules is less than the effort of simply inserting casts to unsigned int.