c++language-lawyerc++20copy-elisionreturn-by-value

Does an implementation that returns fundamental types by value using registers do "temporary materialization"?


(c++20; Working Draft N4868)

[stmt.return]/2 says that the return statement initializes the glvalue result or prvalue result object by copy initialization

the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization (9.4) from the operand.

For class types, the return statement "invokes" the selected constructor and copy-initialize the variable obj, the result object of the invocation, because the copy-elision (an implementation is the caller to pass the address of the dest, so that the called function initialize the dest by constructor call)

class MyClass {
  int x;
};

MyClass func() {
  return MyClass(); //initializes the result object of the function call
}

int main() {
  MyClass obj {func()}; //obj is the result object of func().
}

[dcl.init.general]/16.6.1 suggests:

If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object

For fundamental types like int, double, etc., the common implementation is the return statement to copy the operand (return expression) to the registers

(gcc 12.1 -std=c++20)

int func() {
  return 2;
}

int main() {
  int myInt {func()}; 
}

func():
        push    rbp
        mov     rbp, rsp
        mov     eax, 2
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        call    func()
        mov     DWORD PTR [rbp-4], eax
        mov     eax, 0
        leave
        ret

In [class.temporary]/1.2, the standard says that is it possible to materialize temporaries if the type is "trivially copyable":

1 Temporary objects are created

[...]

ā€”(1.2) when needed by the implementation to pass or return an object of trivially copyable type (see below),

[...]

Question:


Related

Initialization in return statements of functions that return by-value


Solution

  • Does an implementation that returns fundamental types by value using registers do "temporary materialization"?

    Yes.

    Does implementation like that for fundamental types (int, double, etc.) uses the [class.temporary]/1.2 as source?

    [class.temporary]/(1.2) is a non-normative reference to [class.temporary]/3, and an implementation can not use it for non-class types, which is the subject of CWG2434:

    2434. Mandatory copy elision vs non-class objects

    In the following example,

     int f() {
       X x;
       return 4;
     }
     int a = f();
    

    a must be directly initialized in the return statement of f() because the exception permitting temporaries for function arguments and return types in [class.temporary] paragraph 3 applies only to certain class types.

    This requirement is observable, since the destructor of X in the example could inspect the value of a.

    The permissions in this paragraph should also apply to all non-class types.