aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.cc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2022-08-31 17:37:59 -0400
committerMarek Polacek <polacek@redhat.com>2022-09-27 18:49:25 -0400
commit772d532e0ba1e4b22c2b7d576e14b34ee929c093 (patch)
tree06f8f5a94dddbd674053f1fb22087696f2fc8f23 /gcc/cp/pt.cc
parent78bc6497fc61bbdacfb416ee0246a775360d9af6 (diff)
downloadgcc-772d532e0ba1e4b22c2b7d576e14b34ee929c093.zip
gcc-772d532e0ba1e4b22c2b7d576e14b34ee929c093.tar.gz
gcc-772d532e0ba1e4b22c2b7d576e14b34ee929c093.tar.bz2
c++: Implement C++23 P2266R1, Simpler implicit move [PR101165]
This patch implements https://wg21.link/p2266, which, once again, changes the implicit move rules. Here's a brief summary of various changes in this area: r125211: Introduced moving from certain lvalues when returning them r171071: CWG 1148, enable move from value parameter on return r212099: CWG 1579, it's OK to call a converting ctor taking an rvalue r251035: CWG 1579, do maybe-rvalue overload resolution twice r11-2411: Avoid calling const copy ctor on implicit move r11-2412: C++20 implicit move changes, remove the fallback overload resolution, allow move on throw of parameters and implicit move of rvalue references P2266 enables the implicit move even for functions that return references. That is, we will now perform a move in X&& foo (X&& x) { return x; } P2266 also removes the fallback overload resolution, but this was resolved by r11-2412: we only do convert_for_initialization with LOOKUP_PREFER_RVALUE in C++17 and older. P2266 also says that a returned move-eligible id-expression is always an xvalue. This required some further short, but nontrivial changes, especially when it comes to deduction, because we have to pay attention to whether we have auto, auto&& (which is like T&&), or decltype(auto) with (un)parenthesized argument. In C++23, decltype(auto) f(int&& x) { return (x); } auto&& f(int x) { return x; } both should deduce to 'int&&' but decltype(auto) f(int x) { return x; } should deduce to 'int'. A cornucopia of tests attached. I've also verified that we behave like clang++. xvalue_p seemed to be broken: since the introduction of clk_implicit_rval, it cannot use '==' when checking for clk_rvalueref. Since this change breaks code, it's only enabled in C++23. In particular, this code will not compile in C++23: int& g(int&& x) { return x; } because x is now treated as an rvalue, and you can't bind a non-const lvalue reference to an rvalue. This patch also fixes PR106882 (the check_return_expr changes). PR c++/101165 PR c++/106882 gcc/c-family/ChangeLog: * c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_implicit_move. gcc/cp/ChangeLog: * call.cc (reference_binding): Check clk_implicit_rval in C++20 only. * cp-tree.h (unparenthesized_id_or_class_member_access_p): Declare. * pt.cc (unparenthesized_id_or_class_member_access_p): New function, broken out of... (do_auto_deduction): ...here. Use it. In C++23, maybe call treat_lvalue_as_rvalue_p. * tree.cc (xvalue_p): Check & clk_rvalueref, not == clk_rvalueref. * typeck.cc (check_return_expr): Allow implicit move for functions returning a reference as well, or when the return value type is not a scalar type. gcc/testsuite/ChangeLog: * g++.dg/conversion/pr41426.C: Add dg-error for C++23. * g++.dg/cpp0x/elision_weak.C: Likewise. * g++.dg/cpp0x/move-return3.C: Only link in c++20_down. * g++.dg/cpp1y/decltype-auto2.C: Add dg-error for C++23. * g++.dg/cpp1y/lambda-generic-89419.C: Likewise. * g++.dg/cpp23/feat-cxx2b.C: Test __cpp_implicit_move. * g++.dg/gomp/pr56217.C: Only compile in c++20_down. * g++.dg/warn/Wno-return-local-addr.C: Add dg-error for C++23. * g++.dg/warn/Wreturn-local-addr.C: Adjust dg-error. * g++.old-deja/g++.brendan/crash55.C: Add dg-error for C++23. * g++.old-deja/g++.jason/temporary2.C: Likewise. * g++.old-deja/g++.mike/p2846b.C: Adjust. * g++.dg/cpp1y/decltype-auto6.C: New test. * g++.dg/cpp23/decltype1.C: New test. * g++.dg/cpp23/decltype2.C: New test. * g++.dg/cpp23/elision1.C: New test. * g++.dg/cpp23/elision2.C: New test. * g++.dg/cpp23/elision3.C: New test. * g++.dg/cpp23/elision4.C: New test. * g++.dg/cpp23/elision5.C: New test. * g++.dg/cpp23/elision6.C: New test. * g++.dg/cpp23/elision7.C: New test.
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r--gcc/cp/pt.cc50
1 files changed, 38 insertions, 12 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1c1e573..2d83dfd 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30408,6 +30408,26 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
cp_type_quals (ptype));
}
+/* Return true if INIT is an unparenthesized id-expression or an
+ unparenthesized class member access. Used for the argument of
+ decltype(auto). */
+
+bool
+unparenthesized_id_or_class_member_access_p (tree init)
+{
+ STRIP_ANY_LOCATION_WRAPPER (init);
+
+ /* We need to be able to tell '(r)' and 'r' apart (when it's of
+ reference type). Only the latter is an id-expression. */
+ if (REFERENCE_REF_P (init)
+ && !REF_PARENTHESIZED_P (init))
+ init = TREE_OPERAND (init, 0);
+ return (DECL_P (init)
+ || ((TREE_CODE (init) == COMPONENT_REF
+ || TREE_CODE (init) == SCOPE_REF)
+ && !REF_PARENTHESIZED_P (init)));
+}
+
/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE.
The CONTEXT determines the context in which auto deduction is performed
@@ -30443,6 +30463,23 @@ do_auto_deduction (tree type, tree init, tree auto_node,
auto_node. */
complain &= ~tf_partial;
+ /* In C++23, we must deduce the type to int&& for code like
+ decltype(auto) f(int&& x) { return (x); }
+ or
+ auto&& f(int x) { return x; }
+ so we use treat_lvalue_as_rvalue_p. But don't do it for
+ decltype(auto) f(int x) { return x; }
+ where we should deduce 'int' rather than 'int&&'; transmogrifying
+ INIT to an rvalue would break that. */
+ tree r;
+ if (cxx_dialect >= cxx23
+ && context == adc_return_type
+ && (!AUTO_IS_DECLTYPE (auto_node)
+ || !unparenthesized_id_or_class_member_access_p (init))
+ && (r = treat_lvalue_as_rvalue_p (maybe_undo_parenthesized_ref (init),
+ /*return*/true)))
+ init = r;
+
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
/* C++17 class template argument deduction. */
return do_class_deduction (type, tmpl, init, flags, complain);
@@ -30504,18 +30541,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
}
else if (AUTO_IS_DECLTYPE (auto_node))
{
- /* Figure out if INIT is an unparenthesized id-expression or an
- unparenthesized class member access. */
- tree stripped_init = tree_strip_any_location_wrapper (init);
- /* We need to be able to tell '(r)' and 'r' apart (when it's of
- reference type). Only the latter is an id-expression. */
- if (REFERENCE_REF_P (stripped_init)
- && !REF_PARENTHESIZED_P (stripped_init))
- stripped_init = TREE_OPERAND (stripped_init, 0);
- const bool id = (DECL_P (stripped_init)
- || ((TREE_CODE (stripped_init) == COMPONENT_REF
- || TREE_CODE (stripped_init) == SCOPE_REF)
- && !REF_PARENTHESIZED_P (stripped_init)));
+ const bool id = unparenthesized_id_or_class_member_access_p (init);
tree deduced = finish_decltype_type (init, id, complain);
deduced = canonicalize_type_argument (deduced, complain);
if (deduced == error_mark_node)