https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89780
Bug ID: 89780 Summary: -Wpessimizing-move is too agressive with templates and recommends pessimization Product: gcc Version: 9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: redbeard0531 at gmail dot com Target Milestone: --- https://godbolt.org/z/JA-0Gq #include <utility> struct Dest { Dest() = default; Dest(Dest&&); Dest(const Dest&); }; struct Source : Dest {}; template <typename T> Dest withMove() { T x; return std::move(x); } template <typename T> Dest noMove() { T x; return x; } template Dest withMove<Dest>(); template Dest withMove<Source>(); template Dest noMove<Dest>(); template Dest noMove<Source>(); > g++ -O3 -Wall -std=c++17 <source>: In instantiation of 'Dest withMove() [with T = Dest]': <source>:24:30: required from here <source>:13:23: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move] 13 | return std::move(x); | ^ <source>:13:23: note: remove 'std::move' call Basically, gcc9 recommends changing withMove, where both Source and Dest are moved from, in to noMove, where Dest is copy-elided but Source is copied. While this is a minor optimization for the Dest instantiation, it is a potentially significant pesimization for the Source one. Amusingly, this code trips a warning in clang that recommends doing the opposite, adding the std::move to turn noMove into withMove: https://godbolt.org/z/WONlMN <source>:20:12: warning: local variable 'x' will be copied despite being returned by name [-Wreturn-std-move] return x; ^ <source>:28:15: note: in instantiation of function template specialization 'noMove<Source>' requested here template Dest noMove<Source>(); ^ <source>:20:12: note: call 'std::move' explicitly to avoid copying return x; ^ std::move(x) There is just no winning!