This is a follow-up question of my previous question.
Consider the following toy code:
#include <iostream>
using namespace std;
class X
{
public:
X() { }
X(X&& x)
{
cout << "move ctor\n";
}
/*X(X& x)
{
cout << "copy ctor\n";
}*/
};
X f()
{
static X x;
X&& y = std::move(x);
X& z = x;
return y;
}
int main()
{
f();
}
From my understanding on my previous question (i.e. class.copy.elision#3), I think it would cause an error (use of deleted function 'constexpr X::X(const X&)'
) in the above code to return y
in f()
.
The thing is, I run the code in Visual Studio on my PC and it compiles and prints move ctor
. So I test the code online using other compilers, and the results are that msvc and clang compile successfully while gcc gives the error that I'm expecting.
May I humbly ask if this is a bug of msvc and clang, and the program ought not to compile?
CodePudding user response:
The code is legal since C 20, according to cppreference.
There's a rule that returning a non-reference non-volatile local variable implicitly moves it. C 20 added the same rule for rvalue references to non-volatile types.
GCC accepts the code with -std=c 20
. I'm unsure why Clang and MSVC accept it in earlier standard revisions, but I don't see this as a problem.
CodePudding user response:
Pre-C 20
The code is ill-formed for Pre-C 20 standard version as it says:
a move operation might be used instead of a copy operation
- if the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function
(emphasis mine)
as you can see there is no mention of rvalue reference in the above quoted statement. And so there seems to be a bug in msvc and clang as they compile it for Pre-C 20.
C 20
But C 20, specifically allows the use of rvalue reference as quoted below:
An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation is first considered before attempting a copy operation:
- If the expression in a return ([stmt.return]) or co_return ([stmt.return.coroutine]) statement is a (possibly parenthesized) id-expression that names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or
(emphasis mine)
Thus the code is legal from C 20 and onwards and the move constructor can be used.