From: Patrick Palka Date: Wed, 26 Jul 2023 21:21:43 +0000 (-0400) Subject: c++: passing partially inst ttp as ttp [PR110566] X-Git-Tag: basepoints/gcc-15~7329 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8218eb2266811991b8163f36d5c1d974cb50b93;p=thirdparty%2Fgcc.git c++: passing partially inst ttp as ttp [PR110566] The previous fix doesn't work for partially instantiated ttps mainly because most_general_template is a no-op for them. This patch fixes this by giving such ttps a DECL_TEMPLATE_INFO (extending the r11-734-g2fb595f8348e16 fix) with which most_general_template can obtain the original, unlowered ttp. This patch additionally makes coerce_template_template_parms use the correct amount of levels from the scope of a ttp argument. PR c++/110566 PR c++/108179 gcc/cp/ChangeLog: * pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO on the DECL_TEMPLATE_RESULT of the new ttp. (add_defaults_to_ttp): Make a copy of the original ttp's DECL_TEMPLATE_RESULT, and update this copy's DECL_TEMPLATE_INFO as well. (coerce_template_template_parms): Make sure 'scope_args' has the right amount of levels for the ttp argument. (most_general_template): Handle template template parameters. (rewrite_template_parm): Set DECL_TEMPLATE_RESULT on the DECL_TEMPLATE_RESULT of the new ttp. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction115.C: New test. * g++.dg/template/ttp39.C: New test. --- diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 210d6222ef12..9e39fe91986f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -4566,12 +4566,17 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, tree inner = decl; if (TREE_CODE (decl) == TEMPLATE_DECL) { - inner = build_decl (DECL_SOURCE_LOCATION (decl), - TYPE_DECL, DECL_NAME (decl), type); + inner = build_lang_decl_loc (DECL_SOURCE_LOCATION (decl), + TYPE_DECL, DECL_NAME (decl), type); DECL_TEMPLATE_RESULT (decl) = inner; DECL_ARTIFICIAL (inner) = true; - DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms - (DECL_TEMPLATE_PARMS (orig_decl), args, complain); + tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl), + args, complain); + DECL_TEMPLATE_PARMS (decl) = parms; + tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl); + DECL_TEMPLATE_INFO (inner) + = build_template_info (DECL_TI_TEMPLATE (orig_inner), + template_parms_to_args (parms)); } /* Attach the TPI to the decl. */ @@ -7936,6 +7941,19 @@ add_defaults_to_ttp (tree otmpl) } } + tree oresult = DECL_TEMPLATE_RESULT (otmpl); + tree gen_otmpl = DECL_TI_TEMPLATE (oresult); + tree gen_ntmpl; + if (gen_otmpl == otmpl) + gen_ntmpl = ntmpl; + else + gen_ntmpl = add_defaults_to_ttp (gen_otmpl); + + tree nresult = copy_decl (oresult); + DECL_TEMPLATE_INFO (nresult) + = build_template_info (gen_ntmpl, TI_ARGS (DECL_TEMPLATE_INFO (oresult))); + DECL_TEMPLATE_RESULT (ntmpl) = nresult; + hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl); return ntmpl; } @@ -8121,18 +8139,40 @@ coerce_template_template_parms (tree parm_tmpl, OUTER_ARGS are not the right outer levels in this case, as they are the args we're building up for PARM, and for the coercion we want the args for ARG. If DECL_CONTEXT isn't set for a template template - parameter, we can assume that it's in the current scope. In that case - we might end up adding more levels than needed, but that shouldn't be - a problem; any args we need to refer to are at the right level. */ + parameter, we can assume that it's in the current scope. */ tree ctx = DECL_CONTEXT (arg_tmpl); if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl)) ctx = current_scope (); tree scope_args = NULL_TREE; if (tree tinfo = get_template_info (ctx)) scope_args = TI_ARGS (tinfo); - pargs = add_to_template_args (scope_args, pargs); + if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl)) + { + int level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (gen_arg_tmpl)); + int scope_depth = TMPL_ARGS_DEPTH (scope_args); + tree full_pargs = make_tree_vec (level + 1); + + /* Only use as many levels from the scope as needed + (excluding the level of ARG). */ + for (int i = 0; i < level - 1; ++i) + if (i < scope_depth) + TREE_VEC_ELT (full_pargs, i) = TMPL_ARGS_LEVEL (scope_args, i + 1); + else + TREE_VEC_ELT (full_pargs, i) = make_tree_vec (0); - pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none); + /* Add the arguments that appear at the levels of ARG. */ + tree adjacent = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (arg_tmpl)); + adjacent = TMPL_ARGS_LEVEL (adjacent, TMPL_ARGS_DEPTH (adjacent) - 1); + TREE_VEC_ELT (full_pargs, level - 1) = adjacent; + + TREE_VEC_ELT (full_pargs, level) = pargs; + pargs = full_pargs; + } + else + pargs = add_to_template_args (scope_args, pargs); + + pargs = coerce_template_parms (gen_arg_parms, pargs, + NULL_TREE, tf_none); if (pargs != error_mark_node) { tree targs = make_tree_vec (nargs); @@ -25988,6 +26028,9 @@ most_general_template (tree decl) return NULL_TREE; } + if (DECL_TEMPLATE_TEMPLATE_PARM_P (decl)) + return DECL_TI_TEMPLATE (DECL_TEMPLATE_RESULT (decl)); + /* Look for more and more general templates. */ while (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) { @@ -29703,10 +29746,11 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, if (TREE_CODE (olddecl) == TEMPLATE_DECL) { - DECL_TEMPLATE_RESULT (newdecl) - = build_decl (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL, - DECL_NAME (olddecl), newtype); - DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (newdecl)) = true; + tree newresult + = build_lang_decl_loc (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL, + DECL_NAME (olddecl), newtype); + DECL_ARTIFICIAL (newresult) = true; + DECL_TEMPLATE_RESULT (newdecl) = newresult; // First create a copy (ttargs) of tsubst_args with an // additional level for the template template parameter's own // template parameters (ttparms). @@ -29740,6 +29784,8 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, TREE_VALUE (TREE_CHAIN (ttparms)) = make_tree_vec (0); // All done. DECL_TEMPLATE_PARMS (newdecl) = ttparms; + DECL_TEMPLATE_INFO (newresult) + = build_template_info (newdecl, template_parms_to_args (ttparms)); } if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (olddecl))) diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction115.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction115.C new file mode 100644 index 000000000000..5c9aa83b9d8b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction115.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++17 } } + +template class> +struct A { }; + +template +struct B { + template class TT, A* = nullptr> + B(TT); +}; + +template +struct C { }; + +using type = decltype(B{C{}}); +using type = B; diff --git a/gcc/testsuite/g++.dg/template/ttp39.C b/gcc/testsuite/g++.dg/template/ttp39.C new file mode 100644 index 000000000000..03d7c505c4a2 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp39.C @@ -0,0 +1,16 @@ +// PR c++/110566 +// { dg-do compile { target c++20 } } + +template class> +struct A; + +template +struct B { + template + struct C { + template class TT> + using type = A; + }; +}; + +template struct B::C;