c++: Avoid calling const copy ctor on implicit move. [PR91212]

Our implementation of C++11 implicit move was wrong for return; we didn't
actually hit the check for the type of the first parameter of the selected
constructor, because we didn't see LOOKUP_PREFER_RVALUE set properly.

Fixing that to look at the right flags fixed the issue for this testcase,
but broke implicit move for a by-value converting constructor (PR58051).  I
think this was not allowed in C++17, but it is allowed under the implicit
move changes from C++20, and those changes were voted to apply as a DR to
earlier standards as well, so I don't want to break it now.

So after fixing the flags check I changed the test to allow value
parameters.

gcc/cp/ChangeLog:

	PR c++/91212
	* call.c (build_over_call): Don't call a const ref
	overload for implicit move.

gcc/testsuite/ChangeLog:

	PR c++/91212
	* g++.dg/cpp0x/move-return3.C: New test.
This commit is contained in:
Jason Merrill 2020-07-29 00:57:40 -04:00
parent d8140b9ed3
commit 81bc0ec3e9
2 changed files with 29 additions and 3 deletions

View File

@ -8678,15 +8678,18 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
parm = TREE_CHAIN (parm);
}
if (flags & LOOKUP_PREFER_RVALUE)
if (cand->flags & LOOKUP_PREFER_RVALUE)
{
/* The implicit move specified in 15.8.3/3 fails "...if the type of
the first parameter of the selected constructor is not an rvalue
reference to the object's type (possibly cv-qualified)...." */
gcc_assert (!(complain & tf_error));
tree ptype = convs[0]->type;
if (!TYPE_REF_P (ptype)
|| !TYPE_REF_IS_RVALUE (ptype)
/* Allow calling a by-value converting constructor even though it
isn't permitted by the above, because we've allowed it since GCC 5
(PR58051) and it's allowed in C++20. But don't call a copy
constructor. */
if ((TYPE_REF_P (ptype) && !TYPE_REF_IS_RVALUE (ptype))
|| CONVERSION_RANK (convs[0]) > cr_exact)
return error_mark_node;
}

View File

@ -0,0 +1,23 @@
// PR c++/91212
// Test that C++11 implicit move semantics don't call the const copy.
// { dg-do link }
struct T { int i; };
struct X {
X(T&) { } // #1
X(const T&); // #2
};
X
fn ()
{
T buf;
return buf;
}
int
main()
{
X c = fn ();
}