-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Full name of submitter (unless configured in github; will be published with the issue): Jim X
Consider this example:
#include <iostream>
struct B
{
B(){std::cout << this << std::endl;}
};
B get(){
return B{};
}
int main(){
B b = get();
std::cout << &b << std::endl;
}For this example, we can observe that two outputs print different addresses.
[expr.call] p14 says:
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
In this case, get() is a prvlaue. Then, according to [dcl.init.general] p16.6
Otherwise, if the destination type is a class type:
- If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same as the destination type, the initializer expression is used to initialize the destination object.
- Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same as or is derived from the class of the destination type, constructors are considered.
The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution ([over.match]).
Then:
For this case, we should first go into the first bullet. That is, the prvalue is guaranteed to initialize the destination object, which is b. However, GCC and Clang don't perform this guaranteed copy elision. I suspect this is because [stmt.return] p2
the return statement initializes the returned reference or prvalue result object of the (explicit or implicit) function call by copy-initialization from the operand.
That is, the intent would be to skip the first bullet and go into the second bullet. However, the first bullet comprises both direct-initialization and copy-initialization.
PS: maybe https://eel.is/c++draft/class.temporary#3 is relevant here
When an object of class type X is passed to or returned from a potentially-evaluated function call, if X is
However, B{} appears in the operand of the return statement is not an object, it's prvalue.