aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2023-07-15 09:50:51 -0400
committerPatrick Palka <ppalka@redhat.com>2023-07-15 09:50:51 -0400
commit0de651db45c758f54e9ed917069795a3835499de (patch)
treef9b45ce6ee7e426c03c884e25973d901e38710ef
parent97ceaa110e1607ec8f4f1223200868e1642f3cc7 (diff)
downloadgcc-0de651db45c758f54e9ed917069795a3835499de.zip
gcc-0de651db45c758f54e9ed917069795a3835499de.tar.gz
gcc-0de651db45c758f54e9ed917069795a3835499de.tar.bz2
c++: copy elision w/ obj arg and static memfn call [PR110441]
Here the call A().f() is represented as a COMPOUND_EXPR whose first operand is the otherwise unused object argument A() and second operand is the call result (both are TARGET_EXPRs). Within the return statement, this outermost COMPOUND_EXPR ends up foiling the copy elision check in build_special_member_call, resulting in us introducing a bogus call to the deleted move constructor. (Within the variable initialization, which goes through ocp_convert instead of convert_for_initialization, we've already been eliding the copy -- despite the outermost COMPOUND_EXPR -- ever since r10-7410-g72809d6fe8e085 made ocp_convert look through COMPOUND_EXPR). In contrast I noticed '(A(), A::f())' (which should be equivalent to the above call) is represented with the COMPOUND_EXPR inside the RHS's TARGET_EXPR initializer thanks to a special case in cp_build_compound_expr. So this patch fixes this by making keep_unused_object_arg use cp_build_compound_expr as well. PR c++/110441 gcc/cp/ChangeLog: * call.cc (keep_unused_object_arg): Use cp_build_compound_expr instead of building a COMPOUND_EXPR directly. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/elide8.C: New test.
-rw-r--r--gcc/cp/call.cc2
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/elide8.C25
2 files changed, 26 insertions, 1 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15a3d6f..976330c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -5216,7 +5216,7 @@ keep_unused_object_arg (tree result, tree obj, tree fn)
if (TREE_THIS_VOLATILE (a))
a = build_this (a);
if (TREE_SIDE_EFFECTS (a))
- return build2 (COMPOUND_EXPR, TREE_TYPE (result), a, result);
+ return cp_build_compound_expr (a, result, tf_error);
return result;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/elide8.C b/gcc/testsuite/g++.dg/cpp1z/elide8.C
new file mode 100644
index 0000000..7d471be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/elide8.C
@@ -0,0 +1,25 @@
+// PR c++/110441
+// { dg-do compile { target c++11 } }
+
+struct immovable {
+ immovable(immovable &&) = delete;
+};
+
+struct A {
+ static immovable f();
+};
+
+immovable f() {
+ immovable m = A().f(); // { dg-error "deleted" "" { target c++14_down } }
+ return A().f(); // { dg-error "deleted" "" { target c++14_down } }
+}
+
+struct B {
+ A* operator->();
+};
+
+immovable g() {
+ B b;
+ immovable m = b->f(); // { dg-error "deleted" "" { target c++14_down } }
+ return b->f(); // { dg-error "deleted" "" { target c++14_down } }
+}