From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id B83553857825; Thu, 20 Jan 2022 14:26:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B83553857825 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-6773] c++: CTAD inside alias template [PR91911, PR103672] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 2cda2bfa3fd0f2a0122433d2d870843633e2a312 X-Git-Newrev: 09845ad7569bac27c3a1dc7b410d9df764d2ca06 Message-Id: <20220120142616.B83553857825@sourceware.org> Date: Thu, 20 Jan 2022 14:26:16 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Jan 2022 14:26:16 -0000 https://gcc.gnu.org/g:09845ad7569bac27c3a1dc7b410d9df764d2ca06 commit r12-6773-g09845ad7569bac27c3a1dc7b410d9df764d2ca06 Author: Patrick Palka Date: Thu Jan 20 09:25:49 2022 -0500 c++: CTAD inside alias template [PR91911, PR103672] In the first testcase below, when processing the alias template ConstSpanType, transparency of alias template specializations means we replace SpanType with its instantiated definition. But this instantiation lowers the level of the CTAD placeholder for span{T()} from 2 to 1, and so the later instantiation of ConstSpanType erroneously substitutes this CTAD placeholder with the template argument at level 1 index 0, i.e. with int, before we get a chance to perform the CTAD. Although we represent CTAD placeholders as template parameters, we never actually want to replace them via tsubst. So this patch adjusts tsubst to handle CTAD placeholders by simply substituting the template and returning a new CTAD placeholder. Moreover, this means that the level of a CTAD placeholder doesn't matter, so we may as well give them all the same level. This patch gives them the special level 0. The change in tsubst_decl removes a likely dead !CHECKING_P safeguard added in 2017, which would otherwise now get triggered for variables with CTAD placeholder types (since their level is 0). PR c++/91911 PR c++/103672 gcc/cp/ChangeLog: * pt.cc (keep_template_parm): Punt on a level 0 template parm. (tsubst_decl) : Remove !CHECKING_P safeguard. (tsubst) : Handle CTAD placeholders specially. (make_auto_1): Add defaulted 'level' parameter. (make_template_placeholder): Pass 0 as 'level' to make_auto_1. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction101.C: New test. * g++.dg/cpp1z/class-deduction101a.C: New test. * g++.dg/cpp1z/class-deduction101b.C: New test. * g++.dg/cpp1z/class-deduction102.C: New test. * g++.dg/cpp1z/class-deduction102a.C: New test. * g++.dg/cpp1z/class-deduction102b.C: New test. * g++.dg/cpp1z/class-deduction103.C: New test. Diff: --- gcc/cp/pt.cc | 60 ++++++++++-------------- gcc/testsuite/g++.dg/cpp1z/class-deduction101.C | 17 +++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C | 22 +++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C | 22 +++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction102.C | 25 ++++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C | 27 +++++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C | 30 ++++++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction103.C | 22 +++++++++ 8 files changed, 191 insertions(+), 34 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 60bc35a8636..5afcb41eccd 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -10660,7 +10660,7 @@ keep_template_parm (tree t, void* data) int level; int index; template_parm_level_and_index (t, &level, &index); - if (level > ftpi->max_depth) + if (level == 0 || level > ftpi->max_depth) return 0; if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) @@ -14799,20 +14799,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) && VAR_HAD_UNKNOWN_BOUND (t) && type != error_mark_node) type = strip_array_domain (type); - tree sub_args = args; - if (tree auto_node = type_uses_auto (type)) - { - /* Mask off any template args past the variable's context so we - don't replace the auto with an unrelated argument. */ - int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1; - int extra = TMPL_ARGS_DEPTH (args) - nouter; - if (extra > 0) - /* This should never happen with the new lambda instantiation - model, but keep the handling just in case. */ - gcc_assert (!CHECKING_P), - sub_args = strip_innermost_template_args (args, extra); - } - type = tsubst (type, sub_args, complain, in_decl); + type = tsubst (type, args, complain, in_decl); /* Substituting the type might have recursively instantiated this same alias (c++/86171). */ if (gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl) @@ -15564,6 +15551,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) } case TEMPLATE_TYPE_PARM: + if (template_placeholder_p (t)) + { + tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t); + tmpl = tsubst_copy (tmpl, args, complain, in_decl); + if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM) + tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl); + + if (tmpl != CLASS_PLACEHOLDER_TEMPLATE (t)) + return make_template_placeholder (tmpl); + else + return t; + } + /* Fall through. */ case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: case TEMPLATE_PARM_INDEX: @@ -15737,7 +15737,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) of a constrained placeholder. */; else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM && !PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t) - && !CLASS_PLACEHOLDER_TEMPLATE (t) && (arg = TEMPLATE_TYPE_PARM_INDEX (t), r = TEMPLATE_PARM_DESCENDANTS (arg)) && (TEMPLATE_PARM_LEVEL (r) @@ -15756,19 +15755,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) TYPE_REFERENCE_TO (r) = NULL_TREE; if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) - { + if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t)) /* Propagate constraints on placeholders since they are only instantiated during satisfaction. */ - if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t)) - PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci; - else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t)) - { - pl = tsubst_copy (pl, args, complain, in_decl); - if (TREE_CODE (pl) == TEMPLATE_TEMPLATE_PARM) - pl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (pl); - CLASS_PLACEHOLDER_TEMPLATE (r) = pl; - } - } + PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci; if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM) /* We have reduced the level of the template @@ -28492,18 +28482,18 @@ make_args_non_dependent (vec *args) } /* Returns a type which represents 'auto' or 'decltype(auto)'. We use a - TEMPLATE_TYPE_PARM with a level one deeper than the actual template - parms. If set_canonical is true, we set TYPE_CANONICAL on it. */ + TEMPLATE_TYPE_PARM with a level one deeper than the actual template parms, + by default. If set_canonical is true, we set TYPE_CANONICAL on it. */ static tree -make_auto_1 (tree name, bool set_canonical) +make_auto_1 (tree name, bool set_canonical, + int level = current_template_depth + 1) { tree au = cxx_make_type (TEMPLATE_TYPE_PARM); TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index - (0, current_template_depth + 1, current_template_depth + 1, - TYPE_NAME (au), NULL_TREE); + (0, level, level, TYPE_NAME (au), NULL_TREE); if (set_canonical) TYPE_CANONICAL (au) = canonical_type_parameter (au); DECL_ARTIFICIAL (TYPE_NAME (au)) = 1; @@ -28526,12 +28516,14 @@ make_auto (void) return make_auto_1 (auto_identifier, true); } -/* Return a C++17 deduction placeholder for class template TMPL. */ +/* Return a C++17 deduction placeholder for class template TMPL. + There are represented as an 'auto' with the special level 0 and + CLASS_PLACEHOLDER_TEMPLATE set. */ tree make_template_placeholder (tree tmpl) { - tree t = make_auto_1 (auto_identifier, false); + tree t = make_auto_1 (auto_identifier, false, /*level=*/0); CLASS_PLACEHOLDER_TEMPLATE (t) = tmpl; /* Our canonical type depends on the placeholder. */ TYPE_CANONICAL (t) = canonical_type_parameter (t); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction101.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101.C new file mode 100644 index 00000000000..379eb960da6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101.C @@ -0,0 +1,17 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } + +template +struct span { + using value_type = T; + span(T); +}; + +template +using SpanType = decltype(span{T()}); + +template +using ConstSpanType = span::value_type>; + +using type = ConstSpanType; +using type = span; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C new file mode 100644 index 00000000000..97869e647cc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C @@ -0,0 +1,22 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } +// A variant of class-deduction101.C where SpanType has more levels than +// ConstSpanType. + +template +struct span { + using value_type = T; + span(T); +}; + +template +struct A { + template + using SpanType = decltype(span{T()}); +}; + +template +using ConstSpanType = span::SpanType::value_type>; + +using type = ConstSpanType; +using type = span; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C new file mode 100644 index 00000000000..a823c9c3816 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C @@ -0,0 +1,22 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } +// A variant of class-deduction101.C where SpanType has fewer levels than +// ConstSpanType. + +template +struct span { + using value_type = T; + span(T); +}; + +template +using SpanType = decltype(span{T()}); + +template +struct B { + template + using ConstSpanType = span::value_type>; +}; + +using type = B::ConstSpanType; +using type = span; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102.C new file mode 100644 index 00000000000..20504780d32 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102.C @@ -0,0 +1,25 @@ +// PR c++/98077 +// { dg-do compile { target c++17 } } + +template +struct function { + template function(T); + using type = R; +}; + +template function(T) -> function; + +template +struct CallableTrait; + +template +struct CallableTrait> { using ReturnType = R; }; + +template +using CallableTraitT = CallableTrait; + +template +using ReturnType = typename CallableTraitT::ReturnType; + +using type = ReturnType; +using type = int; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C new file mode 100644 index 00000000000..7a4b684b7cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C @@ -0,0 +1,27 @@ +// PR c++/98077 +// { dg-do compile { target c++17 } } +// A variant of class-deduction102.C where the template placeholder is a template +// template parameter. + +template +struct function { + template function(T); + using type = R; +}; + +template function(T) -> function; + +template +struct CallableTrait; + +template +struct CallableTrait> { using ReturnType = R; }; + +template class Tmpl> +using CallableTraitT = CallableTrait; + +template class Tmpl> +using ReturnType = typename CallableTraitT::ReturnType; + +using type = ReturnType; +using type = int; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C new file mode 100644 index 00000000000..64e3f8c7ab0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C @@ -0,0 +1,30 @@ +// PR c++/98077 +// { dg-do compile { target c++17 } } +// A variant of class-deduction102.C where the template placeholder is a template +// template parameter and ReturnType has more levels than CallableTraitT. + +template +struct function { + template function(T); + using type = R; +}; + +template function(T) -> function; + +template +struct CallableTrait; + +template +struct CallableTrait> { using ReturnType = R; }; + +template class Tmpl> +using CallableTraitT = CallableTrait; + +template +struct A { + template class Tmpl> + using ReturnType = typename CallableTraitT::ReturnType; +}; + +using type = A::ReturnType; +using type = int; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C new file mode 100644 index 00000000000..a1a3808afdc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C @@ -0,0 +1,22 @@ +// PR c++/103672 +// { dg-do compile { target c++17 } } + +template +struct unique { + template + T* operator()(Args&&... args); +}; + +template class T, class... Args> +using deduced_type = decltype(T{Args{}...}); + +template class F, template class T, class... Args> +auto make(Args&&... args) { + return F>{}(args...); +} + +template +struct Foo { Foo(A,B); }; + +using type = decltype(make(1, 2)); +using type = Foo*;