|= on a write-1-to-clear status register clears more than the bit you named.
#include <stdint.h>
#define UART_SR (*(volatile uint32_t *)0x40004000u)
#define SR_ORE (1u << 3) /* overrun, write 1 to clear */
void clear_overrun_wrong(void) { UART_SR |= SR_ORE; }
void clear_overrun(void) { UART_SR = SR_ORE; }
The overrun flag clears by writing 1 to it. Writing 0 to a flag does nothing. UART_SR |= SR_ORE reads the whole register first. Every write-1-to-clear flag pending at that moment reads back as 1 and gets written back as 1, so all of them clear. A framing error the handler hasn't looked at yet is gone along with it.
At -O2 for Cortex-M the wrong version is ldr, orr, str. The right one is a single str of the mask. volatile keeps both accesses in the program. It says nothing about what the hardware does with the bits you wrote back.