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.

Reply via email to