I think this is a bug in GCC. Based on [expr.ass]/7, the expression
x |= y
is equivalent to
x = x | y
except that a
is only evaluated once. In a bitwise inclusive OR, like other bitwise operations, as also noted in CoryKramer's comment above, the usual arithmetic conversions will first be performed on both operands [expr.or]/1. Since both our operands are of type std::uint8_t
, the usual arithmetic conversions are simply the integral promotions [expr.arith.conv]/1.5. Integral promotion on std::uint8_t
should mean that both operands are converted to int
[conv.prom]/1. No further conversions of the operands should be required, since the converted types of both operands are the same. Finally, the int
resulting from the |
expression is then converted back to std::uint8_t
and stored in the object referred to by x
[expr.ass]/3. I would assume that this last step is what triggers the warning in some cases. However, there is no way that the result of a bitwise logical OR between two std::uint8_t
could possibly not be representable in an std::uint8_t
, no matter whether we convert to int
(which is guaranteed to be larger) and back along the way. Thus, the warning is unnecessary here, which is probably why it is normally not produced.
The only difference I see between your first and your second version is that a()
is an rvalue while d
is an lvalue. The value category should have no influence on the behavior of the usual arithmetic conversions, however. Thus, the warning—unnecessary or not—should at least be produced consistently. As you have noted yourself, other compilers, such as clang, will not produce a warning here. Furthermore, the issue seems to be oddly-specific to the involvement of function calls in compound assignment. As noted by SergeyA in another comment above, GCC will not produce the warning in the equivalent form of c = c | a()
. Using other kinds of rvalues in place of the function call, such as, for example, the result of casting a literal
c |= static_cast<std::uint8_t>(42);
will also not produce a warning in GCC. But as soon as there is a function call on the right-hand side of the expression, even if the result of the function call is not used at all, e.g., in
c |= (a(), static_cast<std::uint8_t>(5));
the warning appears. Thus, I would conclude that this is a bug in GCC and it would be great if you would write a bug report. …