I read through several very good answers about undefined behaviour and sequence points (e.g. Undefined behavior and sequence points) and I understand, that
a = foo(bar(1), bar(2)); // this is unspecified behaviour
The two function calls can be made in any order, but they remain two different function calls. The machine instructions are not allowed to overlap even if the calls are inlined. In reality, they do overlap quite a bit, but the optimizer is restricted to produce code that behaves strictly as-if the function calls were separate.
a = i + i++; // this is undefined behaviour
With a scalar i, there is no requirement for separation: the cpu instructions that fetch from i, that add, and that postincrement, mix freely, and the optimizer is allowed to pretend it doesn't know that i on the left and i on the right are the same thing. There's no telling what kind of broken assembly it can produce when this precondition is violated. Thus, undefined.