https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59926
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- See Also| |https://gcc.gnu.org/bugzill | |a/show_bug.cgi?id=57176 Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED --- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Patrick Arnoux from comment #2) > Derived f(Derived d) { return (d) ; } > Derived g(Derived& d) { Derived e = d ; return (e) ; } > Derived h(Derived d) { Derived e = d ; return (e) ; } > > > Derived r ; > Derived u ; > u = f(r) ; // (A) Move Ctor to TmpObj, then Move Assign to u. > u = g(r) ; // (B) Move Assign to u (No move ctor) > u = h(r) ; // (C) Move Assign to u > Derived v = h(r) ; // (D) straight up 'rvo' > > I would have expected case A to behave like B and C and I would ask I don't think the standard allows that. The initial copy of 'r' has to happen in the caller's scope, not inside the function. And so it can't be constructed in the return slot, because the caller doesn't know that the body of 'f' returns its parameter, rather than returning some other object. If the functions are defined inline and your objects don't have silly side effects like printing messages to standard output for every member function (or other side effects with observable behaviour that can't be optimized away), then the compiler _will_ optimize it to more efficient code. > if case D could eliminate rvo and do a Move Ctor instead, would that > simplify the code generation. That's not possible, for the same reason as above. The call to h(r) has to make a copy in the caller's frame, and that obviously can't be a move because 'r' can't be modified by calling h(r). Then in the body of h you make another copy, which can't be changed to a move because the compiler isn't allowed to do that to arbitrary copies (except in a return statement). If you want it to be a move, write it as a move: Derived h(Derived d) { Derived e = std::move(d) ; return (e) ; } Of course that 'h' function is still unnecessarily inefficient, using 'f' with RVO does what you want: Derived w = f(r) ; 0x7ffd118b2cbf Derived copy 0x7ffd118b2cb7 Derived move 0x7ffd118b2cbf Derived dtor This copies 'r' to initialize the argument 'd' and then moves that directly into 'w'. The standard doesn't permit us to do anything different here, so I'm closing this.