https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79101
Bug ID: 79101
Summary: Registers aren't used for passing and returning
objects when there is a move constructor
Product: gcc
Version: 6.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: o_kniemeyer at maxon dot net
Target Milestone: ---
According to the calling conventions of System V AMD64 ABI (e.g.
https://www.uclibc.org/docs/psABI-x86_64.pdf) a simple class with trivial copy
constructor and trivial destructor is passed and returned in a register, no
matter if there is a non-trivial move constructor or not. However this code:
struct X
{
X(char* p = nullptr) : ptr(p) { }
X(const X& src) = default;
X(X&& src) : ptr(src.ptr) { src.ptr = nullptr; }
X& operator=(const X&) = default;
char* ptr;
};
X Test(X x)
{
return x.ptr+1;
}
is (wrongly) compiled to
Test(X):
mov rdx, QWORD PTR [rsi]
mov rax, rdi
add rdx, 1
mov QWORD PTR [rdi], rdx
ret
whereas the code without move constructor is correctly compiled to
Test(X):
lea rax, [rdi+1]
ret
I checked this with all GCC versions on http://gcc.godbolt.org. Clang correctly
compiles the code to the two-liner with or without the move constructor.