In 5 << -4
, both GCC 9.1.0 and Apple LLVM 10.0.1 with clang-1001.0.46.4, targeting x86-64, issue a warning message (“left shift count is negative” for GCC and “shift count is negative” for LLVM-clang). In -4 << 3
, GCC does not issue a warning, but LLVM-clang does (“shifting a negative value is undefined”).
The C standard does not require a diagnostic in either of these cases, so whether a compiler does or not is a quality of implementation issue (or, possibly, that the compiler extends C by defining left shifts of negative values and therefore does not consider it an error).
When an operand is not a constant, as in z << x
and x << 3
, we may surmise the compiler fails to see the operand is negative, so it does not issue a warning. In general, these expressions may have defined behavior: If x
is not negative and is within suitable bounds (is not larger than the width of z
in the former case and is not so large that x << 3
overflows in the latter case), the behavior is defined (excepting the possibility that z << x
may overflow). The C standard does not say that left shifts with types that may have negative values, i.e., signed types, are undefined, just that left shifts with negative values are undefined. Therefore, it would be an error for the compiler to issue a warning message whenever x
were a signed type in an expression such as z << x
or x << 3
.
Of course, given int x = -4
and the lack of any change to x
between that initialization and the expressions z << x
and x << 3
, a compiler could deduce that the shifts are undefined in this specific case and issue a warning. This is not required by the standard, and the failure of the compiler to do so is simply a matter of the quality of the implementation of the compiler.