> Therefore, it's quite reasonable to conclude that q has not been changed.
No, that is in fact unreasonable and does not follow at all.
You are completely ignoring any relationships the program might have established between the two at the point at which *(p+1) is written to. [1]
Namely, you are ignoring that the program has already established iq == ip at that point. Which means the program already established (uintptr_t)q == (uintptr_t)(p+1). Which means the program already established q == p + 1. (NOTE: I am not writing C code here. See [1].) Which means *q == *(p + 1). Thus in the last optimization you must assume *q may have been modified. Of course you (the compiler) are welcome to give up on analyzing that chain of logic at any point at which it seems too difficult, but if you break that chain of logic, you cannot make violating assumptions in a subsequent step.