From e2e2f3f2c9400f4ce0dad941bb6c5aa4b799465b Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 5 Jan 2021 13:36:26 -0500 Subject: [PATCH] c++: Fix deduction from the type of an NTTP In the testcase nontype-auto17.C below, the calls to f and g are invalid because neither deduction nor defaulting of the template parameter T yields a valid specialization. Deducing T doesn't work because T is used only in a non-deduced context, and defaulting T doesn't work because its default argument makes the type of M invalid. But with -std=c++17 or later, we incorrectly accept both calls. Starting with C++17 (specifically P0127R2), during deduction we're allowed to try to deduce T from the argument '42' that's been tentatively deduced for M. The problem is that when unify walks into the type of M (a TYPENAME_TYPE), it immediately gives up without performing any new unifications (so the type of M is still unknown) -- and then we go on to unify M with '42' anyway. Later in type_unification_real, we complete the template argument vector using T's default template argument, and end up forming the bogus specializations f and g. This patch fixes this issue by checking whether the type of an NTTP is still dependent after walking into its type during unification. If it is, it means we couldn't deduce all the template parameters used in its type, and so we shouldn't yet unify the NTTP. (The new testcase ttp33.C demonstrates the need for the TEMPLATE_PARM_LEVEL check; without it, we would ICE on this testcase from the call to tsubst.) gcc/cp/ChangeLog: * pt.c (unify) : After walking into the type of the NTTP, substitute into the type again. If the type is still dependent, don't unify the NTTP. gcc/testsuite/ChangeLog: * g++.dg/template/partial5.C: Adjust directives to expect the same errors across all dialects. * g++.dg/cpp1z/nontype-auto17.C: New test. * g++.dg/cpp1z/nontype-auto18.C: New test. * g++.dg/template/ttp33.C: New test. --- gcc/cp/pt.c | 10 +++++++++- gcc/testsuite/g++.dg/cpp1z/nontype-auto17.C | 10 ++++++++++ gcc/testsuite/g++.dg/cpp1z/nontype-auto18.C | 7 +++++++ gcc/testsuite/g++.dg/template/partial5.C | 2 +- gcc/testsuite/g++.dg/template/ttp33.C | 10 ++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto17.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto18.C create mode 100644 gcc/testsuite/g++.dg/template/ttp33.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0d061adc2ed..beabcc4b027 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -23584,13 +23584,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* We haven't deduced the type of this parameter yet. */ if (cxx_dialect >= cxx17 /* We deduce from array bounds in try_array_deduction. */ - && !(strict & UNIFY_ALLOW_INTEGER)) + && !(strict & UNIFY_ALLOW_INTEGER) + && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs)) { /* Deduce it from the non-type argument. */ tree atype = TREE_TYPE (arg); RECUR_AND_CHECK_FAILURE (tparms, targs, tparm, atype, UNIFY_ALLOW_NONE, explain_p); + /* Now check whether the type of this parameter is still + dependent, and give up if so. */ + ++processing_template_decl; + tparm = tsubst (tparm, targs, tf_none, NULL_TREE); + --processing_template_decl; + if (uses_template_parms (tparm)) + return unify_success (explain_p); } else /* Try again later. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto17.C b/gcc/testsuite/g++.dg/cpp1z/nontype-auto17.C new file mode 100644 index 00000000000..509eb0e98e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto17.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++11 } } + +template struct K { }; + +template int f(K); // { dg-error "void" } +int a = f(K<42>{}); // { dg-error "no match" } + +struct S { using type = void; }; +template int g(K); // { dg-message "deduction" } +int b = g(K<42>{}); // { dg-error "no match" } diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto18.C b/gcc/testsuite/g++.dg/cpp1z/nontype-auto18.C new file mode 100644 index 00000000000..936c841ce31 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto18.C @@ -0,0 +1,7 @@ +// { dg-do compile { target c++11 } } + +template struct K { }; + +struct S { using type = int; }; +template int g(K); +int a = g(K<42>{}); diff --git a/gcc/testsuite/g++.dg/template/partial5.C b/gcc/testsuite/g++.dg/template/partial5.C index a56229770f4..40d8c45b087 100644 --- a/gcc/testsuite/g++.dg/template/partial5.C +++ b/gcc/testsuite/g++.dg/template/partial5.C @@ -14,7 +14,7 @@ template struct Y { }; template -struct Y { }; // { dg-error "" "" { target { ! c++17 } } } +struct Y { }; // { dg-error "" } template diff --git a/gcc/testsuite/g++.dg/template/ttp33.C b/gcc/testsuite/g++.dg/template/ttp33.C new file mode 100644 index 00000000000..cd0de8ca641 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp33.C @@ -0,0 +1,10 @@ +// A slight variation of ttp31.C. +// { dg-do compile { target c++11 } } + +template class TTA, TA... VA> +struct A { }; + +template class TTC, TC... VC> +struct C : A { }; -- 2.30.2