the way you have written it, it is undefined behavior. This is because you are modifying a variable more than once in the same sequence point. However if you rewrite it as follows:
m ^= n;
n ^= m;
m ^= n;
then it is safe. However, "useful" is another question, it is rarely "useful" and sometimes it is actually slower than actually using a temp!
Also you need to be careful with aliasing (pointers/references) because if you try to swap something with itself, then you end up accidentally zeroing your value. For example:
#define SWAP(m, n) { m ^= n; n ^= m; m ^= n; }
int x[] = { 1, 2, 3, 4 };
int i = 0;
int j = 0;
SWAP(x[i], x[j]); // whoops, x[0] == 0 now, not 1!
a more traditional swap implementation doesn't have this issue.