The following specification:
6.5.6:37 If the types of both operands are integer types, then the shift left expression evaluates to the value of the left operand whose bits are shifted left by the number of positions the right operand evaluates to. Vacated bits are filled with zeros. lhs << rhs evaluates to , casted to the type of the left operand. If the value of the right operand is negative or greater than or equal to the width of the left operand, then the operation results in an arithmetic overflow.
The same problem exists in 6.5.6:42.
The issue in both cases is that these operations are specified to result in arithmetic overflow.
However, arithmetic overflow allows the following behaviors:
6.23:2There are two allowed behaviors for arithmetic overflow:
6.23:3Evaluation of the expression may result in a panic.
6.23:4The resulting value of the expression may be truncated, discarding the most significant bits that do not fit in the target type.
The first is true for Debug, but the second is not true for Release. The value of the operator expression is not truncated. Instead, in performs a masked shift using LLVM semantics, effectively:
shift_amount = right_operand % bit_width
I'm not exactly sure what the actual behavior is, but my theory is that it is implementation defined.
For example:
- left-shifting a 32-bit one by 32 bits yields 0 on ARM and PowerPC, but 1 on x86;
- left-shifting a 32-bit one by 64 bits yields 0 on ARM, but 1 on x86 and PowerPC
If it's not implementation defined, it probably should be. There is no reason to emulate portable behavior in software for such an edge case.
The following specification:
6.5.6:37 If the types of both operands are integer types, then the shift left expression evaluates to the value of the left operand whose bits are shifted left by the number of positions the right operand evaluates to. Vacated bits are filled with zeros. lhs << rhs evaluates to , casted to the type of the left operand. If the value of the right operand is negative or greater than or equal to the width of the left operand, then the operation results in an arithmetic overflow.
The same problem exists in 6.5.6:42.
The issue in both cases is that these operations are specified to result in arithmetic overflow.
However, arithmetic overflow allows the following behaviors:
6.23:2There are two allowed behaviors for arithmetic overflow:
6.23:3Evaluation of the expression may result in a panic.
6.23:4The resulting value of the expression may be truncated, discarding the most significant bits that do not fit in the target type.
The first is true for Debug, but the second is not true for Release. The value of the operator expression is not truncated. Instead, in performs a masked shift using LLVM semantics, effectively:
shift_amount = right_operand % bit_widthI'm not exactly sure what the actual behavior is, but my theory is that it is implementation defined.
For example:
If it's not implementation defined, it probably should be. There is no reason to emulate portable behavior in software for such an edge case.