From 81bc0ec3e926d7a2c90502847ddaacf3d56d5b75 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 29 Jul 2020 00:57:40 -0400 Subject: [PATCH] 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. --- gcc/cp/call.c | 9 ++++++--- gcc/testsuite/g++.dg/cpp0x/move-return3.C | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/move-return3.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f9508ae3635..e283d635d60 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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; } diff --git a/gcc/testsuite/g++.dg/cpp0x/move-return3.C b/gcc/testsuite/g++.dg/cpp0x/move-return3.C new file mode 100644 index 00000000000..c79f0591936 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/move-return3.C @@ -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 (); +} -- 2.30.2