This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix wrong-code with generic lambda (PR c++/86943)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>, Nathan Sidwell <nathan at acm dot org>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 23 Nov 2018 22:15:50 +0100
- Subject: [C++ PATCH] Fix wrong-code with generic lambda (PR c++/86943)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
On the following testcase, the call to operator () is marked as
CALL_FROM_THUNK_P and therefore genericization ignores all subtrees thereof.
Unfortunately, one of the arguments is a move ctor call which is not itself
CALL_FROM_THUNK_P and thus we need to genericize its arguments, otherwise
we pass address of a temporary which holds a reference value instead of the
reference itself.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Or should CALL_FROM_THUNK_P not be set in this call (it is set in
maybe_add_lambda_conv_op and then copied over during tsubst*).
Furthermore, clang++ apparently doesn't call the move ctor + dtor at all and
uses just the originally constructed var. Is what GCC does right, or clang?
2018-11-23 Jakub Jelinek <jakub@redhat.com>
PR c++/86943
* cp-gimplify.c (cp_genericize_r): For CALL_FROM_THUNK_P CALL_EXPRs
don't walk just DECL_P arguments, do walk more complex arguments.
* g++.dg/cpp1y/pr86943.C: New test.
--- gcc/cp/cp-gimplify.c.jj 2018-11-17 00:16:41.924381941 +0100
+++ gcc/cp/cp-gimplify.c 2018-11-23 17:29:24.764459373 +0100
@@ -1108,6 +1108,18 @@ cp_genericize_r (tree *stmt_p, int *walk
|| (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt)))
{
*walk_subtrees = 0;
+ /* For CALL_EXPRs, if the arguments aren't decls, recurse into them
+ though. See PR86943. */
+ if (TREE_CODE (stmt) == CALL_EXPR)
+ {
+ unsigned int n = call_expr_nargs (stmt);
+ for (unsigned int i = 0; i < n; i++)
+ {
+ tree &arg = CALL_EXPR_ARG (stmt, i);
+ if (!DECL_P (arg))
+ cp_walk_tree (&arg, cp_genericize_r, data, NULL);
+ }
+ }
return NULL;
}
--- gcc/testsuite/g++.dg/cpp1y/pr86943.C.jj 2018-11-23 18:04:08.260852111 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr86943.C 2018-11-23 18:03:45.798224687 +0100
@@ -0,0 +1,32 @@
+// PR c++/86943
+// { dg-do run { target c++14 } }
+
+int c[3];
+
+struct S
+{
+ S () : s (1234) { c[0]++; }
+ S (const S &) { __builtin_abort (); }
+ S (S &&x) noexcept { if (x.s != 1234) __builtin_abort (); s = 1234; x.s = 2345; c[1]++; }
+ ~S () { if (s != 1234 && s != 2345) __builtin_abort (); c[2]++; }
+ int s;
+};
+
+using F = void (*) (S);
+
+F
+foo ()
+{
+ return [] (auto val) { if (val.s != 1234) __builtin_abort (); };
+}
+
+int
+main ()
+{
+ {
+ volatile F f = foo ();
+ f ({});
+ }
+ if (c[0] + c[1] != c[2])
+ __builtin_abort ();
+}
Jakub