https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110850
Bug ID: 110850 Summary: Evaluation order of assignment operands Product: gcc Version: 13.2.0 URL: https://godbolt.org/z/89TPG4eaK Status: UNCONFIRMED Keywords: diagnostic, wrong-code Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: bugreport0 at proton dot me Target Milestone: --- In C++17 in assignment expressions the right-hand side evaluation and its side effects are sequenced before the left-hand side evaluation and its side effects, so this snippet struct Trivial { int x; }; int postincrement(int& i) { std::cout << "postincrement\n"; return i++; } int load(int& i) { std::cout << "load\n"; return i; } int main() { Trivial a[1]{}; int i = 0; (std::cout << "LHS\n", a[postincrement(i)]) = (std::cout << "RHS\n", Trivial{load(i)}); std::cout << a->x << '\n'; } should output "RHS load LHS postincrement 0". Instead, it outputs "RHS LHS postincrement load 1". Around gcc 7.1 evaluation order seems to have been fixed in many cases, but not for "aggregate assignment" such as with this Trivial type. The URL associated with this report demonstrates several variations of this example, showing in addition discrepancy between compile- and run-time behaviour and between optimization levels, and inconsistency in warning messages in cases other than "aggregate assignment". Bug report #97288 is related, but it assumes implicit lvalue-to-rvalue conversion to be part of the right operand evaluation, and in later versions described behaviour disappears, reappears and finally disappears.