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.