If I may add my $.02, I would like to add my experience in targetting (albeit not completely) the 65816 processor, and in particular, the Super Nintendo Entertainment System. In my case (since I provide symbols to users (and those users are primarily myself), rather than macros) refactoring to a = a@v would not be an issue, though it is a bit unwieldy over a@=v (not so much to cause anything more than minor annoyance).
Examples would be useful.
Again, the null hypothesis is that people don't do this; we'll have to show some concrete examples from real codebases in order to provide evidence against the null hypothesis.
Your use of the passive voice in the last sentence hurts you. "Would only be replaced" by whom?— the compiler, or the human programmer? If the human programmer is supposed to replace `x &= y` with `x = x & y` in order to avoid ISR/multithreading bugs, then good, that's exactly what C++20 wants them to do. IOW, I don't understand the thrust of this paragraph.
I would argue that, as the standard is written, both would be equally susceptible to bugs caused by accessing things which are also modified in ISRs (My solution was to save the value of the hardware registers and a number of MMIO registers into a special region of memory as part of the prelude of interrupt handlers). To me, it seems easier to allow x &= y to be in-place, for implementations where this matters, than x = x & y;, which, as written, seems like it would always have to imply a separate read and write to x.
"To me, it seems easier to allow x &= y to be in-place, for implementations where this matters" — Well, that's the thing. If it matters to the programmer, then it should be expressed explicitly in the code — perhaps via inline assembly. Otherwise, you end up in this awkward situation:
x &= y; // Maintainers take note! It matters for business reasons that this is in-place on x86, but on ARM and PPC it is load-modify-store (and that's OK)
How can atomicity "matter" on some platforms, and yet be unimplementable on others?
That level of platform-specificity should be expressed via inline assembly, or at least hidden behind an (inline) helper function.
Oh, and finally, consider the following workaround:
*(int*)myvolatilevar &= 255;
Compound assignments on non-volatile variables aren't deprecated; so if you really need the compound stuff more than any particular semantics provided by the volatile stuff, could you just add the cast?
Isn't accessing a volatile object through a non-volatile lvalue undefined behaviour?
Yes, but in real life I would guess that we don't have a volatile object here; we just have something like
volatile int& myvolatilevar = *(volatile int*)0xDEADBEEF;
Maybe we do have a volatile global variable and use linker directives to put it at the right location? I don't know. Again, the null hypothesis is that this never happens, and we'd have to see some concrete examples from real codebases in order to provide evidence against the null hypothesis.