A testcase in a comment for 67847 led me to realize that our code for
calling the result of a conversion template to pointer-to-function type
was fundamentally broken (and apparently untested). This patch fixes it.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 89411e903d2bfea13933ad1d7f0027e383a3009c
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Oct 22 13:48:01 2015 -1000
* call.c (add_template_conv_candidate): Pass DEDUCE_CALL.
(add_template_candidate_real): Handle it.
(fn_type_unification): Handle it.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 93dd86a..1223dcd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3027,6 +3027,9 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
{
if (first_arg_without_in_chrg != NULL_TREE)
first_arg_without_in_chrg = NULL_TREE;
+ else if (return_type && strict == DEDUCE_CALL)
+ /* We're deducing for a call to the result of a template conversion
+ function, so the args don't contain 'this'; leave them alone. */;
else
++skip_without_in_chrg;
}
@@ -3167,6 +3170,11 @@ add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype,
flags, NULL_TREE, strict, complain);
}
+/* Create an overload candidate for the conversion function template TMPL,
+ returning RETURN_TYPE, which will be invoked for expression OBJ to produce a
+ pointer-to-function which will in turn be called with the argument list
+ ARGLIST, and add it to CANDIDATES. This does not change ARGLIST. FLAGS is
+ passed on to implicit_conversion. */
static struct z_candidate *
add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
@@ -3178,7 +3186,7 @@ add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
return
add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
NULL_TREE, arglist, return_type, access_path,
- conversion_path, 0, obj, DEDUCE_CONV,
+ conversion_path, 0, obj, DEDUCE_CALL,
complain);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 142245a..ffe02da 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17235,7 +17235,9 @@ pack_deducible_p (tree parm, tree fn)
DEDUCE_CALL:
We are deducing arguments for a function call, as in
- [temp.deduct.call].
+ [temp.deduct.call]. If RETURN_TYPE is non-null, we are
+ deducing arguments for a call to the result of a conversion
+ function template, as in [over.call.object].
DEDUCE_CONV:
We are deducing arguments for a conversion function, as in
@@ -17402,7 +17404,15 @@ fn_type_unification (tree fn,
/* Never do unification on the 'this' parameter. */
parms = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (fntype));
- if (return_type)
+ if (return_type && strict == DEDUCE_CALL)
+ {
+ /* We're deducing for a call to the result of a template conversion
+ function. The parms we really want are in return_type. */
+ if (POINTER_TYPE_P (return_type))
+ return_type = TREE_TYPE (return_type);
+ parms = TYPE_ARG_TYPES (return_type);
+ }
+ else if (return_type)
{
tree *new_args;
diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl1.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl1.C
new file mode 100644
index 0000000..7f866da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl1.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+template <class T>
+using Fn = void (*)(T);
+
+struct A
+{
+ template <class T>
+ operator Fn<T>();
+};
+
+int main()
+{
+ A()(42);
+}
commit ee11ebf3960f92d5c36d399fed81a09e7d7c53ed
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Oct 22 13:47:38 2015 -1000
* call.c (add_conv_candidate): Remove first_arg parm.
(add_template_conv_candidate): Likewise.
(add_template_candidate_real): Don't pass it.
(build_op_call_1): Likewise.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index b7cf031..93dd86a 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -178,9 +178,6 @@ static struct z_candidate *add_template_candidate
static struct z_candidate *add_template_candidate_real
(struct z_candidate **, tree, tree, tree, tree, const vec<tree, va_gc> *,
tree, tree, tree, int, tree, unification_kind_t, tsubst_flags_t);
-static struct z_candidate *add_template_conv_candidate
- (struct z_candidate **, tree, tree, tree, const vec<tree, va_gc> *,
- tree, tree, tree, tsubst_flags_t);
static void add_builtin_candidates
(struct z_candidate **, enum tree_code, enum tree_code,
tree, tree *, int, tsubst_flags_t);
@@ -192,7 +189,7 @@ static void build_builtin_candidate
(struct z_candidate **, tree, tree, tree, tree *, tree *,
int, tsubst_flags_t);
static struct z_candidate *add_conv_candidate
- (struct z_candidate **, tree, tree, tree, const vec<tree, va_gc> *, tree,
+ (struct z_candidate **, tree, tree, const vec<tree, va_gc> *, tree,
tree, tsubst_flags_t);
static struct z_candidate *add_function_candidate
(struct z_candidate **, tree, tree, tree, const vec<tree, va_gc> *, tree,
@@ -2176,7 +2173,7 @@ add_function_candidate (struct z_candidate **candidates,
static struct z_candidate *
add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
- tree first_arg, const vec<tree, va_gc> *arglist,
+ const vec<tree, va_gc> *arglist,
tree access_path, tree conversion_path,
tsubst_flags_t complain)
{
@@ -2190,7 +2187,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
parmlist = TREE_TYPE (parmlist);
parmlist = TYPE_ARG_TYPES (parmlist);
- len = vec_safe_length (arglist) + (first_arg != NULL_TREE ? 1 : 0) + 1;
+ len = vec_safe_length (arglist) + 1;
convs = alloc_conversions (len);
parmnode = parmlist;
viable = 1;
@@ -2208,10 +2205,8 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
if (i == 0)
arg = obj;
- else if (i == 1 && first_arg != NULL_TREE)
- arg = first_arg;
else
- arg = (*arglist)[i - (first_arg != NULL_TREE ? 1 : 0) - 1];
+ arg = (*arglist)[i - 1];
argtype = lvalue_type (arg);
if (i == 0)
@@ -2260,7 +2255,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
reason = arity_rejection (NULL_TREE, i + remaining, len);
}
- return add_candidate (candidates, totype, first_arg, arglist, len, convs,
+ return add_candidate (candidates, totype, obj, arglist, len, convs,
access_path, conversion_path, viable, reason, flags);
}
@@ -3122,7 +3117,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
if (obj != NULL_TREE)
/* Aha, this is a conversion function. */
- cand = add_conv_candidate (candidates, fn, obj, first_arg, arglist,
+ cand = add_conv_candidate (candidates, fn, obj, arglist,
access_path, conversion_path, complain);
else
cand = add_function_candidate (candidates, fn, ctype,
@@ -3175,14 +3170,14 @@ add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype,
static struct z_candidate *
add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
- tree obj, tree first_arg,
+ tree obj,
const vec<tree, va_gc> *arglist,
tree return_type, tree access_path,
tree conversion_path, tsubst_flags_t complain)
{
return
add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
- first_arg, arglist, return_type, access_path,
+ NULL_TREE, arglist, return_type, access_path,
conversion_path, 0, obj, DEDUCE_CONV,
complain);
}
@@ -4335,11 +4330,11 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
if (TREE_CODE (fn) == TEMPLATE_DECL)
add_template_conv_candidate
- (&candidates, fn, obj, NULL_TREE, *args, totype,
+ (&candidates, fn, obj, *args, totype,
/*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE, complain);
else
- add_conv_candidate (&candidates, fn, obj, NULL_TREE,
+ add_conv_candidate (&candidates, fn, obj,
*args, /*conversion_path=*/NULL_TREE,
/*access_path=*/NULL_TREE, complain);
}