When using some implementations or configurations, such constructs will be safe. When using clang or gcc with optimizations enabled but without -fwrapv
, such constructs may cause code elsewhere to be processed nonsensically in ways that aren't bound by ordinary laws of causality.
The code is, in the words of the C Standard, non-portable or erroneous. From the published Rationale, it is clear that the Standard intended that phrase to include constructs that were non-portable but correct when used to perform low-level tasks on implementations that were intended to be suitable for low-level programming. The Standard, however, gives compiler writers whose customers wouldn't deliberately use such constructs for low-level programming the freedom to treat them as "erroneous" in cases where that would be more useful than presuming they were deliberate but non-portable. People wishing to sell their compilers to programmers who would be using them would be better placed than the Committee to know which constructs their customers would use deliberately, and thus there was no need to have the Standard itself make such distinctions.
Some compilers that are not subject to such market pressures, however, operate under a different philosophy, where the phrase "non-portable or erroneous" means "non-portable, and therefore erroneous". Thus, even on platforms where integer overflow would never have any side effects at the machine-code level, such compilers may sometimes go out of their way not to behave meaningfully in situations where they determine that integer overflow would be inevitable, even if no aspect of program behavior would otherwise have any causal dependency upon the results of the calculations.