We fail to detect unresolved explicitly-passed auto template args. The first hunk in pt.c, that changes fn_type_unification, arranges for us to regard the template arg list as incomplete, although that's not necessary for any of the testcases I tried. I thought it might be relevant in case the args become part of the type of the function, and for us to continue overload resolution with processing_template_decl nonzero.
The second hunk, that changes type_unification_real, is the actual fix for the testcase in the PR. The other hunks, that change unify, arrange for us to accept and properly update the template arglist, at least when auto stands by itself as a template argument. Without this hunk, the slightly modified testcase pr84979-2.C would fail, although there's no good reason for the deduction to be regarded as a mismatch. We still need some work, however: pr84979-3.C and pr84979-4.C should be accepted, if we are to support non-toplevel auto in explicit parameters (-3), or auto in parms whose index doesn't match the auto's own index. This is probably not good enough for inclusion, although I'm pretty sure it passes regstrap. The problem is the condition in unify() that intends to allow proper uses of auto by do_auto_deduction, and the AFAICT accidentally-working cases of auto deduction in explicit template args: the condition that covers those cases is growing incredibly hairier and fragile, and I'm growing convinced I took a wrong turn somewhere that led me there. I'm almost ready to conclude that I'm either missing something, or that we shouldn't be supporting auto in explicit template args at all, because I can't see that the implementation was ever meant to support that use. Is that so? I could use some advice there. Thanks in advance, for gcc/cp/ChangeLog PR c++/84979 * pt.c (fn_type_unification): Set incomplete if explicit args use auto. (type_unification_real): Do not skip deduction if explicit arg uses auto. (unify): Reject unsupported cases of auto in args. Regard auto as a match, but proceed to update targ. for gcc/testsuite/ChangeLog PR c++/84979 * g++.dg/concepts/pr84979.C: New. * g++.dg/concepts/pr84979-2.C: New. * g++.dg/concepts/pr84979-3.C: New. * g++.dg/concepts/pr84979-4.C: New. --- gcc/cp/pt.c | 56 +++++++++++++++++++++++++++-- gcc/testsuite/g++.dg/concepts/pr84979-2.C | 9 +++++ gcc/testsuite/g++.dg/concepts/pr84979-3.C | 9 +++++ gcc/testsuite/g++.dg/concepts/pr84979-4.C | 9 +++++ gcc/testsuite/g++.dg/concepts/pr84979.C | 9 +++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/pr84979-2.C create mode 100644 gcc/testsuite/g++.dg/concepts/pr84979-3.C create mode 100644 gcc/testsuite/g++.dg/concepts/pr84979-4.C create mode 100644 gcc/testsuite/g++.dg/concepts/pr84979.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5293c2b5491b..2b9e5f1ada45 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19109,7 +19109,10 @@ fn_type_unification (tree fn, parameter_pack = TEMPLATE_PARM_PARAMETER_PACK (parm); } - if (!parameter_pack && targ == NULL_TREE) + if (!parameter_pack + && (targ == NULL_TREE + || (flag_concepts + && type_uses_auto (targ)))) /* No explicit argument for this template parameter. */ incomplete = true; @@ -19891,7 +19894,12 @@ type_unification_real (tree tparms, ARGUMENT_PACK_EXPLICIT_ARGS (targ) = NULL_TREE; } - if (targ || tparm == error_mark_node) + if ((targ + && (!flag_concepts + /* We have to unify explicitly-passed template args + involving auto types. */ + || !type_uses_auto (targ))) + || tparm == error_mark_node) continue; tparm = TREE_VALUE (tparm); @@ -20952,6 +20960,37 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, if (parm == any_targ_node || arg == any_targ_node) return unify_success (explain_p); + /* Concepts allows 'auto' in template arguments, even multiple + 'auto's in a single argument. We don't know how to deal with + them here: see how do_auto_deduction uses extract_autos to + construct a separate template args vec, that such autos index. + Since we don't do any of that, we can only substitute toplevel + auto parameters, and only when their index happens to match their + position in the template argument list. Catch deviations instead + of corrupting targs. */ + if (flag_concepts && is_auto (parm) + && ((TEMPLATE_TYPE_IDX (parm) + >= TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (targs))) + || (TREE_CODE (TREE_VALUE (TREE_VEC_ELT + (tparms, TEMPLATE_TYPE_IDX (parm)))) + != TYPE_DECL) + || (TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), + TEMPLATE_TYPE_IDX (parm)) != parm + /* do_auto_deduction calls us properly, i.e., with the + extra targs level, so don't complain about its uses. + ??? Is there a better/surer way to test for the + proper uses? */ + && TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), + TEMPLATE_TYPE_IDX (parm)) != NULL_TREE + && type_uses_auto (TREE_VEC_ELT + (INNERMOST_TEMPLATE_ARGS (targs), + TEMPLATE_TYPE_IDX (parm)))))) + { + if (complain & tf_error) + sorry ("unsupported use of auto in explicit template parameter list"); + return unify_invalid (explain_p); + } + /* If PARM uses template parameters, then we can't bail out here, even if ARG == PARM, since we won't record unifications for the template parameters. We might need them if we're trying to @@ -21147,8 +21186,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, { /* Deduce template name TT from TT, TT<>, TT<T> and TT<i>. */ + /* Substitute (some) concepts-specified auto parms. + ??? Can autos ever pass the test above? */ + if (targ != NULL_TREE && flag_concepts && parm == targ + && is_auto (parm)) + ; /* Simple cases: Value already set, does match or doesn't. */ - if (targ != NULL_TREE && template_args_equal (targ, arg)) + else if (targ != NULL_TREE && template_args_equal (targ, arg)) return unify_success (explain_p); else if (targ) return unify_inconsistency (explain_p, parm, targ, arg); @@ -21170,8 +21214,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, if (arg == error_mark_node) return unify_invalid (explain_p); + /* Substitute (some) concepts-specified auto parms. */ + if (targ != NULL_TREE && flag_concepts && parm == targ + && is_auto (parm)) + ; /* Simple cases: Value already set, does match or doesn't. */ - if (targ != NULL_TREE && same_type_p (targ, arg)) + else if (targ != NULL_TREE && same_type_p (targ, arg)) return unify_success (explain_p); else if (targ) return unify_inconsistency (explain_p, parm, targ, arg); diff --git a/gcc/testsuite/g++.dg/concepts/pr84979-2.C b/gcc/testsuite/g++.dg/concepts/pr84979-2.C new file mode 100644 index 000000000000..140b051b311e --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr84979-2.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fconcepts" } + +template<typename T, int> void foo(T t) {} + +void bar() +{ + foo<auto, 0>(bar); +} diff --git a/gcc/testsuite/g++.dg/concepts/pr84979-3.C b/gcc/testsuite/g++.dg/concepts/pr84979-3.C new file mode 100644 index 000000000000..93a0140e8390 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr84979-3.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fconcepts" } + +template<typename T, int> void foo(T t) {} + +void bar() +{ + foo<auto (*)(), 0>(bar); // { dg-bogus "unimplemented|no matching function" "" { xfail *-*-* } } +} diff --git a/gcc/testsuite/g++.dg/concepts/pr84979-4.C b/gcc/testsuite/g++.dg/concepts/pr84979-4.C new file mode 100644 index 000000000000..08054d0d832a --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr84979-4.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fconcepts" } + +template<int, typename T> void foo(T t) {} + +void bar() +{ + foo<0, auto>(bar); // { dg-bogus "unimplemented|no matching function" "" { xfail *-*-* } } +} diff --git a/gcc/testsuite/g++.dg/concepts/pr84979.C b/gcc/testsuite/g++.dg/concepts/pr84979.C new file mode 100644 index 000000000000..c70b3756f2b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr84979.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fconcepts" } + +template<typename> void foo() {} + +void bar() +{ + foo<auto>(); // { dg-error "invalid|no match" } +} -- Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ You must be the change you wish to see in the world. -- Gandhi Be Free! -- http://FSFLA.org/ FSF Latin America board member Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer