I know that in the following situation that the compiler is free to move-construct the return value from makeA
(but is also free to elide the copy or move altog
The rule for this situation changed between 2011 and 2014. The compiler should now treat localB
as an rvalue.
The applicable rule for return
statements is found in §12.8 [class.copy]/p32, which reads in C++14 (quoting N3936, emphasis mine):
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when 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 or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.
The bolded clause was added by CWG issue 1579, expressly to require the converting move constructor A::A(B&&)
to be called here. This is implemented in GCC 5 and Clang 3.9.
Back in 2011, this "try rvalue first" rule was closely tied to the criteria for copy elision (quoting N3337):
When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
Since copy elision necessarily requires the two to have the same type, this paragraph didn't apply, and the compiler had to use the A::A(B&)
constructor.
Note that as CWG 1579 is considered a DR against C++11, compilers should implement its resolution even in C++11 mode.