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)