My explanation on the issue:
Compiler applies integer promotions first and then checks and applies the remaining rules correctly( assuming the final conversion is applied ). However the warning is not correct.
Standard defines that first, integer promotions are performed on both operands, and then the remaining rules are applied:
We start with: foo: unsigned short int and bar: unsigned int
ISO/IEC 9899:201x
6.3.1.8 Usual arithmetic conversions
skip text...
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
Otherwise in this case indicates that we are dealing with integers.
So we get: foo: int and bar: unsigned int
skip text...
Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.
And finally: foo: unsigned int and bar: unsigned int
Compiler warns that the conversion of foo from int to unsigned int might change the sign and wrap. This is correct for the last conversion, but the compiler forgets that foo started with the type unsigned short int, therefore it cannot wrap, and looking at the overall conversion the warning isn't correct.
gcc with appropriate warnings( -conversion,... ) doesn't complain.