https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70792
--- Comment #8 from Matthijs van Duin <matthijsvanduin at gmail dot com> --- (In reply to Matthijs van Duin from comment #4) > return std::pair{ ++i, ++i }.first; My bad! This isn't an exhibit of the bug. I simply forgot that std::pair is not really a struct, and this isn't aggregate initialization: the constructor takes references, so correct code is generated in this case. And in fact, if you do use an aggregate, the test works correctly. However, if you replace std::pair by a class whose constructor takes (int, int), similar to the one used in the existing testcase (g++.dg/cpp0x/initlist86.C) then it fails again. Looking at the disassembly (on ARM since I don't know x86 asm) shows that gcc loads both arguments from the storage allocated for i, after both increments have been done. Effectively it's copy-constructing the first argument too late. The more general issue appears to be that if the arguments are trivially copyable lvalues, then gcc keeps these as lvalues and copy-constructs the actual arguments way too late. If I look at this disassembly of this code: struct Foo { char x[64]; // too big to pass in register Foo( Foo const &other ) = default; // but still trivially copyable Foo &mutate(); }; struct Pair { Pair( Foo x, Foo y ); }; void test( Foo &foo ) { Pair{ foo.mutate(), foo.mutate() }; } Then test() effectively does: Foo &temp1 = foo.mutate(); Foo &temp2 = foo.mutate(); Pair{ temp1, temp2 } // copy-construct arguments and call Pair constructor (Also, interestingly, temp2 is copy-constructed before temp1 is!) If Foo is not trivially copyable, even if merely due to the presence of a destructor, then the problem disappears.