aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-01-29 21:43:04 -0500
committerJason Merrill <jason@gcc.gnu.org>2019-01-29 21:43:04 -0500
commit538a530848375deb14495fae5a5ccf5ae5daedba (patch)
tree2014ffc7cf9d736a2f0e7a17bddbaa3c9087d660 /gcc
parentdca2770bc073353e621e426d4803b8ea16382b5a (diff)
downloadgcc-538a530848375deb14495fae5a5ccf5ae5daedba.zip
gcc-538a530848375deb14495fae5a5ccf5ae5daedba.tar.gz
gcc-538a530848375deb14495fae5a5ccf5ae5daedba.tar.bz2
PR c++/86943 - wrong code converting lambda to function pointer.
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. * 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. From-SVN: r268377
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/lambda.c29
-rw-r--r--gcc/cp/pt.c58
-rw-r--r--gcc/cp/typeck.c5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv13.C33
5 files changed, 111 insertions, 23 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3cdc779..af4d9c2 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]].
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 6e6db1f..bc64a41 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 f8b3054..cb06a57 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 ec722a3..7045284 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 0000000..159c4ccd
--- /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 ();
+}