Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14? -- >8 -- We crash when dependent_type_p gets a TEMPLATE_TYPE_PARM outside a template. That happens here because in
template <template <typename T, typename T::type TT> typename X> void func() {} template <typename U, int I> struct Y {}; void g() { func<Y>(); } when performing overload resolution for func<Y>() we have to check if U matches T and I matches TT. So we wind up in coerce_template_template_parm/PARM_DECL. TREE_TYPE (arg) is int so we try to substitute TT's type, which is T::type. But we have nothing to substitute T with. And we call make_typename_type where ctx is still T, which checks dependent_scope_p and we trip the assert. It should work to always perform the substitution in a template context. If the result still contains template parameters, we cannot say if they match. While at it, adjust the return type. PR c++/96097 gcc/cp/ChangeLog: * pt.cc (coerce_template_template_parm): Return bool. Increment processing_template_decl before calling tsubst. gcc/testsuite/ChangeLog: * g++.dg/template/ttp44.C: New test. --- gcc/cp/pt.cc | 48 ++++++++++++++++----------- gcc/testsuite/g++.dg/template/ttp44.C | 13 ++++++++ 2 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/ttp44.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 024fa8a5529..aae57164fcc 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -7887,25 +7887,22 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) return convert_from_reference (expr); } -/* Subroutine of coerce_template_template_parms, which returns 1 if - PARM_PARM and ARG_PARM match using the rule for the template - parameters of template template parameters. Both PARM and ARG are - template parameters; the rest of the arguments are the same as for - coerce_template_template_parms. - */ -static int -coerce_template_template_parm (tree parm, - tree arg, - tsubst_flags_t complain, - tree in_decl, - tree outer_args) +/* Subroutine of coerce_template_template_parms, which returns true if + PARM and ARG match using the rule for the template parameters of + template template parameters. Both PARM and ARG are template parameters; + the rest of the arguments are the same as for + coerce_template_template_parms. */ + +static bool +coerce_template_template_parm (tree parm, tree arg, tsubst_flags_t complain, + tree in_decl, tree outer_args) { if (arg == NULL_TREE || error_operand_p (arg) || parm == NULL_TREE || error_operand_p (parm)) - return 0; + return false; if (TREE_CODE (arg) != TREE_CODE (parm)) - return 0; + return false; switch (TREE_CODE (parm)) { @@ -7916,7 +7913,7 @@ coerce_template_template_parm (tree parm, { if (!coerce_template_template_parms (parm, arg, complain, in_decl, outer_args)) - return 0; + return false; } /* Fall through. */ @@ -7924,7 +7921,7 @@ coerce_template_template_parm (tree parm, if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg)) && !TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))) /* Argument is a parameter pack but parameter is not. */ - return 0; + return false; break; case PARM_DECL: @@ -7937,16 +7934,29 @@ coerce_template_template_parm (tree parm, i.e. the parameter list of TT depends on earlier parameters. */ if (!uses_template_parms (TREE_TYPE (arg))) { + /* We can also have: + + template <template <typename T, typename T::type TT> typename X> + void func() {} + template <typename U, int I> + struct Y {}; + void g() { func<Y>(); } + + where we are not in a template, but the type of PARM is T::type + and dependent_type_p doesn't want to see a TEMPLATE_TYPE_PARM + outside a template. */ + ++processing_template_decl; tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl); + --processing_template_decl; if (!uses_template_parms (t) && !same_type_p (t, TREE_TYPE (arg))) - return 0; + return false; } if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg)) && !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))) /* Argument is a parameter pack but parameter is not. */ - return 0; + return false; break; @@ -7954,7 +7964,7 @@ coerce_template_template_parm (tree parm, gcc_unreachable (); } - return 1; + return true; } /* Coerce template argument list ARGLIST for use with template diff --git a/gcc/testsuite/g++.dg/template/ttp44.C b/gcc/testsuite/g++.dg/template/ttp44.C new file mode 100644 index 00000000000..2a412975243 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp44.C @@ -0,0 +1,13 @@ +// PR c++/96097 +// { dg-do compile } + +template <template <typename T, typename T::type TT> class X> +void func() {} + +template <typename U, int I> +struct Y {}; + +void test() +{ + func<Y>(); +} base-commit: 3775f71c8909b3531fe002138814fa2504ec2e8b -- 2.46.0