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.

Reply via email to