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!