https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89695

            Bug ID: 89695
           Summary: inappropriate copying of trivially copyable prvalue
                    arguments
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: matthijsvanduin at gmail dot com
  Target Milestone: ---

When a function that has a non-reference parameter of a trivially copyable
class-type is invoked with a prvalue expression as argument, e.g.:

    #include <stdio.h>

    struct Foo {
        int data[32];
        Foo() { printf( "%p (constructor)\n", this ); }
    };

    Foo make_foo() {  return Foo{};  }

    void f( Foo x ) {  printf( "%p (parameter)\n", &x );  }

    int main() {
        f( Foo{} );
        f( make_foo() );
        return 0;
    }

g++ initializes a temporary from this expression and then copy-constructs the
parameter from it:

    0x7fffce1caa80 (constructor)
    0x7fffce1cab00 (parameter)
    0x7fffce1caa80 (constructor)
    0x7fffce1cab00 (parameter)

This appears to happen whenever C++17 permits it and at any optimization level,
even though Foo is large and expensive to copy. For example on armhf at -O2,
g++ produces this particularly silly-looking output:

        mov     r1, r5
        mov     r0, r7
        bl      printf(PLT)
        mov     r2, r8
        mov     r1, r5
        mov     r0, r4
        bl      memcpy(PLT)
        mov     r1, r4
        mov     r0, r6
        bl      printf(PLT)
        mov     r1, r5
        mov     r0, r7
        bl      printf(PLT)
        mov     r2, r8
        mov     r1, r5
        mov     r0, r4
        bl      memcpy(PLT)
        mov     r1, r4
        mov     r0, r6
        bl      printf(PLT)

If a user-provided destructor, copy-constructor, or move-constructor is added
to the class, no copying is done even at -O0 (as expected due to C++17
requirements):

        mov     r3, r7
        mov     r0, r3
        bl      _ZN3FooC1Ev(PLT)
        mov     r3, r7
        mov     r0, r3
        bl      _Z1f3Foo(PLT)
        add     r3, r7, #128
        mov     r0, r3
        bl      _Z8make_foov(PLT)
        add     r3, r7, #128
        mov     r0, r3
        bl      _Z1f3Foo(PLT)

Reply via email to