https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89251
Bug ID: 89251 Summary: [2018-q4m] Wrong datatype optimization on bitfield Product: gcc Version: 8.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: david.koch at libertysurf dot fr Target Milestone: --- (probably related to #83784) The setting : STM32L476 / Cortex-M4 GCC 8.2.1 from ARM (https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) 1- Created several union structures to describe cpu/mcu registers 2- Base type of each is uint32_t 3- Filling in the bitfields of used bits 4- Stuffing with unused bits to keep bits at the right place 5- Access one register, bit 0 to clear the bit 6- Immediate crash with HardFault typedef union MyRegDef { struct { uint32_t enable:1; } uint32_t raw; }; ((*MyRegDef) ADDR)->enable = 0; [BUG] It generates : LDRH R0, [R3, #0] <- CRASH BFC R0, #0, #1 STRH R0, [R3, #0] You cannot access a hardware register on a 2 bytes boundary. If I change the structure to : { struct { uint32_t enable:1; uint32_t _1:30; } [OK] It generates : LDR R0, [R3, #0] <- NO PROBLEM BFC R0, #0, #1 STR R0, [R3, #0] Possible explanation : The compiler detected that only 1 bit was used and "wanted" to save byte accesses, hence reducing the size of the load/store to a halfword. It probably works in memory (provided you have the right alignment), but it doesn't work on hardware registers. Possible correction : rely on the base datatype. If I REALLY wanted it to be on 16 bits, I would have used uint16_t instead. Don't make some assumptions or at least provide a flag to allow this "optimization", but don't use it by default.