i = i++, i, i++;
is UB because =
has higher precedence than ,
and so the expression gets parsed as (i = i++), i, i++
where the sub-expression i = i++
invokes UB1).
Even if the code had been written as i = (i++, i, i++);
it would still have been UB, because now there is no sequence point between the right-most i++
and i
, the left operand of =
1).
However, when you remove the i =
part, you remove that ambiguous behavior. return i++, i, i++;
must get sequenced as:
i++, the left one
sequence point from left comma
i
sequence point from right comma
i++, the right one
sequence point before returning
So it is well-defined.
Sources:
1) C11 6.5/2
If a side effect on a scalar object is unsequenced relative to either a different side effect
on the same scalar object or a value computation using the value of the same scalar
object, the behavior is undefined. If there are multiple allowable orderings of the
subexpressions of an expression, the behavior is undefined if such an unsequenced side
effect occurs in any of the orderings.
And then also C11 6.5.16/3
The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
Notable, the above text regarding assignment is different between C11 and C++11.