From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 437C5385800A; Thu, 9 Feb 2023 23:01:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 437C5385800A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1675983677; bh=dBAURLSNclOIpXwbDra8SaaGH0Y8I6dYJNw9pE5jSDY=; h=From:To:Subject:Date:From; b=MD3CiQejPi+Bonsnn2O6uctOkv1CmdpSUWtTyw80eJrMrYke7ZpSj08/rsW4bgave o1dpUmjU7UZ+nDHY9eRzQN/Pn5uHdxaHoMT2Yay6eRPX1yzglleBu0TET5eIil3hYK cXnp3m+G3JhzJWTEJtFJ6jkg0TvgcCy6rYrs7C+c= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/jason/heads/alias-ctad)] c++: fix alias CTAD [PR105841] X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/users/jason/heads/alias-ctad X-Git-Oldrev: b0befb1a6f5efd8c5e60f6c976d55b0e14e9c479 X-Git-Newrev: 5bec2588336f2bc70d6d93972c5132b4930c2218 Message-Id: <20230209230117.437C5385800A@sourceware.org> Date: Thu, 9 Feb 2023 23:01:17 +0000 (GMT) List-Id: https://gcc.gnu.org/g:5bec2588336f2bc70d6d93972c5132b4930c2218 commit 5bec2588336f2bc70d6d93972c5132b4930c2218 Author: Jason Merrill Date: Wed Feb 8 22:06:22 2023 -0800 c++: fix alias CTAD [PR105841] In my initial implementation of alias CTAD, I described a couple of differences from the specification that I thought would not have a practical effect; this testcase demonstrates that I was wrong. One difference is resolved by the CPTK_IS_DEDUCIBLE commit; the other (adding too many of the alias template parameters to the new deduction guide) is fixed by this patch. PR c++/105841 gcc/cp/ChangeLog: * pt.cc (corresponding_template_parameter_list): Split out... (corresponding_template_parameter): ...from here. (find_template_parameters): Factor out... (find_template_parameter_info::find_in): ...this function. (find_template_parameter_info::find_in_recursive): New. (find_template_parameter_info::found): New. (alias_ctad_tweaks): Only add parms used in the deduced args. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias14.C: New test. Co-authored-by: Michael Spertus Diff: --- gcc/cp/pt.cc | 133 ++++++++++++++++----- .../g++.dg/cpp2a/class-deduction-alias14.C | 13 ++ 2 files changed, 114 insertions(+), 32 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 497ecd7cbaa..35d8ce709c3 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -10369,7 +10369,7 @@ lookup_and_finish_template_variable (tree templ, tree targs, return NULL_TREE. */ static tree -corresponding_template_parameter (tree parms, int level, int index) +corresponding_template_parameter_list (tree parms, int level, int index) { while (TMPL_PARMS_DEPTH (parms) > level) parms = TREE_CHAIN (parms); @@ -10378,7 +10378,30 @@ corresponding_template_parameter (tree parms, int level, int index) || TREE_VEC_LENGTH (TREE_VALUE (parms)) <= index) return NULL_TREE; - tree t = TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), index)); + return TREE_VEC_ELT (TREE_VALUE (parms), index); +} + +/* Return the TREE_LIST for the template parameter from PARMS that positionally + corresponds to the template parameter PARM, or else return NULL_TREE. */ + +static tree +corresponding_template_parameter_list (tree parms, tree parm) +{ + int level, index; + template_parm_level_and_index (parm, &level, &index); + return corresponding_template_parameter_list (parms, level, index); +} + +/* As above, but pull out the actual parameter. */ + +static tree +corresponding_template_parameter (tree parms, tree parm) +{ + tree list = corresponding_template_parameter_list (parms, parm); + if (!list) + return NULL_TREE; + + tree t = TREE_VALUE (list); /* As in template_parm_to_arg. */ if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == TEMPLATE_DECL) t = TREE_TYPE (t); @@ -10388,18 +10411,6 @@ corresponding_template_parameter (tree parms, int level, int index) gcc_assert (TEMPLATE_PARM_P (t)); return t; } - -/* Return the template parameter from PARMS that positionally corresponds - to the template parameter PARM, or else return NULL_TREE. */ - -static tree -corresponding_template_parameter (tree parms, tree parm) -{ - int level, index; - template_parm_level_and_index (parm, &level, &index); - return corresponding_template_parameter (parms, level, index); -} - struct pair_fn_data { @@ -10672,6 +10683,11 @@ struct find_template_parameter_info tree *parm_list_tail = &parm_list; tree ctx_parms; int max_depth; + + tree find_in (tree); + tree find_in_recursive (tree); + bool found (tree); + unsigned num_found () { return parms.elements (); } }; /* Appends the declaration of T to the list in DATA. */ @@ -10814,6 +10830,52 @@ any_template_parm_r (tree t, void *data) return 0; } +/* Look through T for template parameters. */ + +tree +find_template_parameter_info::find_in (tree t) +{ + return for_each_template_parm (t, keep_template_parm, this, &visited, + /*include_nondeduced*/true, + any_template_parm_r); +} + +/* As above, but also recursively look into the default arguments of template + parameters we found. Used for alias CTAD. */ + +tree +find_template_parameter_info::find_in_recursive (tree t) +{ + if (tree r = find_in (t)) + return r; + /* Since newly found parms are added to the end of the list, we + can just walk it until we reach the end. */ + for (tree pl = parm_list; pl; pl = TREE_CHAIN (pl)) + { + tree parm = TREE_VALUE (pl); + tree list = corresponding_template_parameter_list (ctx_parms, parm); + if (tree r = find_in (TREE_PURPOSE (list))) + return r; + } + return NULL_TREE; +} + +/* True if PARM was found by a previous call to find_in. PARM can be a + TREE_LIST, a DECL_TEMPLATE_PARM_P, or a TEMPLATE_PARM_P. */ + +bool +find_template_parameter_info::found (tree parm) +{ + if (TREE_CODE (parm) == TREE_LIST) + parm = TREE_VALUE (parm); + if (TREE_CODE (parm) == TYPE_DECL) + parm = TREE_TYPE (parm); + else + parm = DECL_INITIAL (parm); + gcc_checking_assert (TEMPLATE_PARM_P (parm)); + return parms.contains (parm); +} + /* Returns a list of unique template parameters found within T, where CTX_PARMS are the template parameters in scope. */ @@ -10824,8 +10886,7 @@ find_template_parameters (tree t, tree ctx_parms) return NULL_TREE; find_template_parameter_info ftpi (ctx_parms); - for_each_template_parm (t, keep_template_parm, &ftpi, &ftpi.visited, - /*include_nondeduced*/true, any_template_parm_r); + ftpi.find_in (t); return ftpi.parm_list; } @@ -29971,22 +30032,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides) * The explicit-specifier of f' is the explicit-specifier of g (if any). */ - /* This implementation differs from the above in two significant ways: - - 1) We include all template parameters of A, not just some. - 2) [fixed] The added constraint is same_type instead of deducible. - - I believe that while it's probably possible to construct a testcase that - behaves differently with this simplification, it should have the same - effect for real uses. Including all template parameters means that we - deduce all parameters of A when resolving the call, so when we're in the - constraint we don't need to deduce them again, we can just check whether - the deduction produced the desired result. */ - tsubst_flags_t complain = tf_warning_or_error; tree atype = TREE_TYPE (tmpl); tree aguides = NULL_TREE; - tree atparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); + tree fullatparms = DECL_TEMPLATE_PARMS (tmpl); + tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms); unsigned natparms = TREE_VEC_LENGTH (atparms); tree utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); for (ovl_iterator iter (uguides); iter; ++iter) @@ -30016,16 +30066,27 @@ alias_ctad_tweaks (tree tmpl, tree uguides) for (unsigned i = 0; i < len; ++i) if (TREE_VEC_ELT (targs, i) == NULL_TREE) ++ndlen; - tree gtparms = make_tree_vec (natparms + ndlen); + find_template_parameter_info ftpi (fullatparms); + ftpi.find_in_recursive (targs); + unsigned nusedatparms = ftpi.num_found (); + unsigned nfparms = nusedatparms + ndlen; + tree gtparms = make_tree_vec (nfparms); /* Set current_template_parms as in build_deduction_guide. */ auto ctp = make_temp_override (current_template_parms); current_template_parms = copy_node (DECL_TEMPLATE_PARMS (tmpl)); TREE_VALUE (current_template_parms) = gtparms; + j = 0; /* First copy over the parms of A. */ - for (j = 0; j < natparms; ++j) - TREE_VEC_ELT (gtparms, j) = TREE_VEC_ELT (atparms, j); + for (unsigned i = 0; i < natparms; ++i) + { + tree elt = TREE_VEC_ELT (atparms, i); + if (ftpi.found (elt)) + TREE_VEC_ELT (gtparms, j++) = elt; + } + gcc_checking_assert (j == nusedatparms); + /* Now rewrite the non-deduced parms of f. */ for (unsigned i = 0; ndlen && i < len; ++i) if (TREE_VEC_ELT (targs, i) == NULL_TREE) @@ -30052,6 +30113,13 @@ alias_ctad_tweaks (tree tmpl, tree uguides) } if (g == error_mark_node) continue; + if (nfparms == 0) + { + /* The targs are all non-dependent, so g isn't a template. */ + fprime = g; + ret = TREE_TYPE (TREE_TYPE (fprime)); + goto non_template; + } DECL_USE_TEMPLATE (g) = 0; fprime = build_template_decl (g, gtparms, false); DECL_TEMPLATE_RESULT (fprime) = g; @@ -30088,6 +30156,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) { /* For a non-template deduction guide, if the arguments of A aren't deducible from the return type, don't add the candidate. */ + non_template: if (!type_targs_deducible_from (tmpl, ret)) continue; } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias14.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias14.C new file mode 100644 index 00000000000..22b96bcd5d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias14.C @@ -0,0 +1,13 @@ +// PR c++/105841 +// { dg-do compile { target c++20 } } + +template +struct A { A(...); }; + +template +A(T, Ts...) -> A; + +template +using B = A; + +B b(0, 0);