public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH]  PR c++/86943 - wrong code converting lambda to function pointer.
@ 2019-01-30  3:06 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2019-01-30  3:06 UTC (permalink / raw)
  To: gcc-patches

In this PR, instantiating the static thunk returned from the generic lambda
conversion function template was using normal overload resolution, which
meant calling an extra constructor when forwarding its argument.  Fixed by
special-casing thunk calls significantly more.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* lambda.c (maybe_add_lambda_conv_op): Use a template-id in the
	call.  Only forward parms for decltype.
	* pt.c (tsubst_copy_and_build) [CALL_EXPR]: Handle CALL_FROM_THUNK_P
	specially.
	* typeck.c (check_return_expr): Don't mess with a thunk call.
---
 gcc/cp/lambda.c                               | 29 ++++++----
 gcc/cp/pt.c                                   | 58 +++++++++++++++----
 gcc/cp/typeck.c                               |  5 ++
 .../g++.dg/cpp0x/lambda/lambda-conv13.C       | 33 +++++++++++
 gcc/cp/ChangeLog                              |  9 +++
 5 files changed, 111 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv13.C

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 6e6db1fd72e..bc64a4173f9 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -1095,8 +1095,10 @@ maybe_add_lambda_conv_op (tree type)
 	 implementation of the conversion operator.  */
 
       tree instance = cp_build_fold_indirect_ref (thisarg);
-      tree objfn = build_min (COMPONENT_REF, NULL_TREE,
-			      instance, DECL_NAME (callop), NULL_TREE);
+      tree objfn = lookup_template_function (DECL_NAME (callop),
+					     DECL_TI_ARGS (callop));
+      objfn = build_min (COMPONENT_REF, NULL_TREE,
+			 instance, objfn, NULL_TREE);
       int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;
 
       call = prepare_op_call (objfn, nargs);
@@ -1137,18 +1139,21 @@ maybe_add_lambda_conv_op (tree type)
 
 	if (generic_lambda_p)
 	  {
-	    /* Avoid capturing variables in this context.  */
-	    ++cp_unevaluated_operand;
-	    tree a = forward_parm (tgt);
-	    --cp_unevaluated_operand;
-
+	    tree a = tgt;
+	    if (DECL_PACK_P (tgt))
+	      {
+		a = make_pack_expansion (a);
+		PACK_EXPANSION_LOCAL_P (a) = true;
+	      }
 	    CALL_EXPR_ARG (call, ix) = a;
-	    if (decltype_call)
-	      CALL_EXPR_ARG (decltype_call, ix) = unshare_expr (a);
 
-	    if (PACK_EXPANSION_P (a))
-	      /* Set this after unsharing so it's not in decltype_call.  */
-	      PACK_EXPANSION_LOCAL_P (a) = true;
+	    if (decltype_call)
+	      {
+		/* Avoid capturing variables in this context.  */
+		++cp_unevaluated_operand;
+		CALL_EXPR_ARG (decltype_call, ix) = forward_parm (tgt);
+		--cp_unevaluated_operand;
+	      }
 
 	    ++ix;
 	  }
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f8b3054533e..cb06a570d48 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18680,6 +18680,52 @@ tsubst_copy_and_build (tree t,
 	      }
 	  }
 
+	/* Stripped-down processing for a call in a thunk.  Specifically, in
+	   the thunk template for a generic lambda.  */
+	if (CALL_FROM_THUNK_P (t))
+	  {
+	    tree thisarg = NULL_TREE;
+	    if (TREE_CODE (function) == COMPONENT_REF)
+	      {
+		thisarg = TREE_OPERAND (function, 0);
+		if (TREE_CODE (thisarg) == INDIRECT_REF)
+		  thisarg = TREE_OPERAND (thisarg, 0);
+		function = TREE_OPERAND (function, 1);
+		if (TREE_CODE (function) == BASELINK)
+		  function = BASELINK_FUNCTIONS (function);
+	      }
+	    /* We aren't going to do normal overload resolution, so force the
+	       template-id to resolve.  */
+	    function = resolve_nondeduced_context (function, complain);
+	    for (unsigned i = 0; i < nargs; ++i)
+	      {
+		/* In a thunk, pass through args directly, without any
+		   conversions.  */
+		tree arg = (*call_args)[i];
+		while (TREE_CODE (arg) != PARM_DECL)
+		  arg = TREE_OPERAND (arg, 0);
+		(*call_args)[i] = arg;
+	      }
+	    if (thisarg)
+	      {
+		/* Shift the other args over to make room.  */
+		vec_safe_push (call_args, (*call_args)[nargs-1]);
+		for (int i = nargs-1; i > 0; --i)
+		  (*call_args)[i] = (*call_args)[i-1];
+		(*call_args)[0] = thisarg;
+	      }
+	    ret = build_call_a (function, call_args->length (),
+				call_args->address ());
+	    /* The thunk location is not interesting.  */
+	    SET_EXPR_LOCATION (ret, UNKNOWN_LOCATION);
+	    CALL_FROM_THUNK_P (ret) = true;
+	    if (CLASS_TYPE_P (TREE_TYPE (ret)))
+	      CALL_EXPR_RETURN_SLOT_OPT (ret) = true;
+
+	    release_tree_vector (call_args);
+	    RETURN (ret);
+	  }
+
 	/* We do not perform argument-dependent lookup if normal
 	   lookup finds a non-function, in accordance with the
 	   expected resolution of DR 218.  */
@@ -18883,22 +18929,12 @@ tsubst_copy_and_build (tree t,
 	    bool op = CALL_EXPR_OPERATOR_SYNTAX (t);
 	    bool ord = CALL_EXPR_ORDERED_ARGS (t);
 	    bool rev = CALL_EXPR_REVERSE_ARGS (t);
-	    bool thk = CALL_FROM_THUNK_P (t);
-	    if (op || ord || rev || thk)
+	    if (op || ord || rev)
 	      {
 		function = extract_call_expr (ret);
 		CALL_EXPR_OPERATOR_SYNTAX (function) = op;
 		CALL_EXPR_ORDERED_ARGS (function) = ord;
 		CALL_EXPR_REVERSE_ARGS (function) = rev;
-		if (thk)
-		  {
-		    if (TREE_CODE (function) == CALL_EXPR)
-		      CALL_FROM_THUNK_P (function) = true;
-		    else
-		      AGGR_INIT_FROM_THUNK_P (function) = true;
-		    /* The thunk location is not interesting.  */
-		    SET_EXPR_LOCATION (function, UNKNOWN_LOCATION);
-		  }
 	      }
 	  }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ec722a36035..70452845529 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9728,6 +9728,11 @@ check_return_expr (tree retval, bool *no_warning)
 	    }
 	}
 
+      /* The call in a (lambda) thunk needs no conversions.  */
+      if (TREE_CODE (retval) == CALL_EXPR
+	  && CALL_FROM_THUNK_P (retval))
+	converted = true;
+
       /* First convert the value to the function's return type, then
 	 to the type of return value's location to handle the
 	 case that functype is smaller than the valtype.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv13.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv13.C
new file mode 100644
index 00000000000..159c4ccd525
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv13.C
@@ -0,0 +1,33 @@
+// 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 = S (*) (S);
+
+F
+foo ()
+{
+  return [] (auto val)->S { if (val.s != 1234) __builtin_abort (); return {}; };
+}
+
+int
+main ()
+{
+  {
+    volatile F f = foo ();
+    S s = f ({});
+    if (s.s != 1234) __builtin_abort ();
+  }
+  if (c[0] + c[1] != c[2])
+    __builtin_abort ();
+}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3cdc7790f43..af4d9c2635e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,12 @@
+2019-01-29  Jason Merrill  <jason@redhat.com>
+
+	PR c++/86943 - wrong code converting lambda to function pointer.
+	* lambda.c (maybe_add_lambda_conv_op): Use a template-id in the
+	call.  Only forward parms for decltype.
+	* pt.c (tsubst_copy_and_build) [CALL_EXPR]: Handle CALL_FROM_THUNK_P
+	specially.
+	* typeck.c (check_return_expr): Don't mess with a thunk call.
+
 2019-01-28  Jason Merrill  <jason@redhat.com>
 
 	PR c++/89089 - ICE with [[no_unique_address]].

base-commit: bd5092043090e89d693cde98c619e8064f393893
-- 
2.20.1

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-01-30  2:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-30  3:06 [C++ PATCH] PR c++/86943 - wrong code converting lambda to function pointer Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).