From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id C2B0F3857036 for ; Wed, 30 Jun 2021 15:58:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C2B0F3857036 Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-550-ev92IuxdM8-XCYOKc_qC9A-1; Wed, 30 Jun 2021 11:58:36 -0400 X-MC-Unique: ev92IuxdM8-XCYOKc_qC9A-1 Received: by mail-qk1-f200.google.com with SMTP id c3-20020a37b3030000b02903ad0001a2e8so2026040qkf.3 for ; Wed, 30 Jun 2021 08:58:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:mime-version; bh=waCi5Gk8icpRFhg7OyyQGju7x0pB4jYqtN4LimP/xJ0=; b=DAhP+sWO4IK75cLIg/utDQLTPglHSnHKjoXMFs6iId3INRHLI78Q5s9sI5nE2htj4a +8kKCENVFuIswoeQeMwRfmJZDWiqZP2jnWWCVJ+2bLTfKSxHLr9vXMQmyIVC7HamsR2/ kYyggVVSVn4ritARum8MhXiqbNRJSFrnHzFA1Gc+RiBXecmM7IV8+oub8P6igTw2eZRs jDkHIlRo/ZzagP50sSMU3LWNaAO/83cNqcAv7ClzNRqyKpdcB0PKLCofTJKhZb87ceBj 4uHcqUVBOJi2WTyyCkKYRFSe+8rxd79KTa+RM7mbcxgk+f1+wxlOMEcQeIXQx8BQJlZJ wsCQ== X-Gm-Message-State: AOAM530CcUyztfgq4hzeVpukWS2Egy0YntauimSy2ORkV4JRoMjF1kNN 9OSgF+P5oEp1lVsdtPgu2FxdfAY88vscBnMhROQKVWwt4tOlz6mjMnSXKMvPS14w7XDMfFhxU2d qDDUKkgT9pXX0g0/eCA== X-Received: by 2002:a0c:f048:: with SMTP id b8mr12315732qvl.56.1625068715466; Wed, 30 Jun 2021 08:58:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzXem+dNHj4mYdQHbZRsvybTICZX57VjVwvy4rh7cf+Vf5UgmAqNDHAP6bdqTl3pGZ9yA5ziQ== X-Received: by 2002:a0c:f048:: with SMTP id b8mr12315705qvl.56.1625068715198; Wed, 30 Jun 2021 08:58:35 -0700 (PDT) Received: from [192.168.1.130] (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id y10sm10298738qta.35.2021.06.30.08.58.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jun 2021 08:58:34 -0700 (PDT) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Wed, 30 Jun 2021 11:58:34 -0400 (EDT) To: Patrick Palka cc: Jason Merrill , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: CTAD within alias template [PR91911] In-Reply-To: <8b6edd86-9db0-f6e2-386f-4693d1692f5f@idea> Message-ID: <67855539-bf99-ac7-a995-35871cd23712@idea> References: <20210624204529.4136660-1-ppalka@redhat.com> <3802ce35-3e48-fb97-8868-d1274ed0a778@redhat.com> <0719adf2-7a17-a8a7-9374-cbfa41846499@redhat.com> <8b6edd86-9db0-f6e2-386f-4693d1692f5f@idea> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-16.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 30 Jun 2021 15:58:40 -0000 On Wed, 30 Jun 2021, Patrick Palka wrote: > On Fri, 25 Jun 2021, Jason Merrill wrote: > > > On 6/25/21 1:11 PM, Patrick Palka wrote: > > > On Fri, 25 Jun 2021, Jason Merrill wrote: > > > > > > > On 6/24/21 4:45 PM, Patrick Palka wrote: > > > > > In the first testcase below, during parsing of the alias template > > > > > ConstSpanType, transparency of alias template specializations means we > > > > > replace SpanType with SpanType's substituted definition. But this > > > > > substitution lowers the level of the CTAD placeholder for span(T()) from > > > > > 2 to 1, and so the later instantiantion 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. > > > > > > > > > > In light of this, it seems we should avoid level lowering when > > > > > substituting through through the type-id of a dependent alias template > > > > > specialization. To that end this patch makes lookup_template_class_1 > > > > > pass tf_partial to tsubst in this situation. > > > > > > > > This makes sense, but what happens if SpanType is a member template, so > > > > that > > > > the levels of it and ConstSpanType don't match? Or the other way around? > > > > > > If SpanType is a member template of say the class template A (and > > > thus its level is greater than ConstSpanType): > > > > > > template > > > struct A { > > > template > > > using SpanType = decltype(span(T())); > > > }; > > > > > > template > > > using ConstSpanType = span > > A::SpanType::value_type>; > > > > > > using type = ConstSpanType; > > > > > > then this case luckily works even without the patch because > > > instantiate_class_template now reuses the specialization A::SpanType > > > that was formed earlier during instantiation of A, where we > > > substitute only a single level of template arguments, so the level of > > > the CTAD placeholder inside the defining-type-id of this specialization > > > dropped from 3 to 2, so still more than the level of ConstSpanType. > > > > > > This luck is short-lived though, because if we replace > > > A::SpanType with say A::SpanType then the testcase > > > breaks again (without the patch) because we no longer can reuse that > > > specialization, so we instead form it on the spot by substituting two > > > levels of template arguments (U=int,T=T) into the defining-type-id, > > > causing the level of the placeholder to drop to 1. I think the patch > > > causes its level to remain 3 (though I guess it should really be 2). > > > > > > > > > For the other way around, if ConstSpanType is a member template of > > > say the class template B (and thus its level is greater than > > > SpanType): > > > > > > template > > > using SpanType = decltype(span(T())); > > > > > > template > > > struct B { > > > template > > > using ConstSpanType = span::value_type>; > > > }; > > > > > > using type = B::ConstSpanType; > > > > > > then tf_partial doesn't help here at all; we end up substituting 'int' > > > for the CTAD placeholder... What it seems we need is to _increase_ the > > > level of the CTAD placeholder from 2 to 3 during the dependent > > > substitution.. > > > > > > Hmm, rather than messing with tf_partial, which is apparently only a > > > partial solution, maybe we should just make tsubst never substitute a > > > CTAD placeholder -- they should always be resolved from do_class_deduction, > > > and their level doesn't really matter otherwise. (But we'd still want > > > to substitute into the CLASS_PLACEHOLDER_TEMPLATE of the placeholder in > > > case it's a template template parm.) Something like: > > > > > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > > > index 5107bfbf9d1..dead651ed84 100644 > > > --- a/gcc/cp/pt.c > > > +++ b/gcc/cp/pt.c > > > @@ -15552,7 +15550,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > > > tree in_decl) > > > levels = TMPL_ARGS_DEPTH (args); > > > if (level <= levels > > > - && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0) > > > + && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0 > > > + && !template_placeholder_p (t)) > > > { > > > arg = TMPL_ARG (args, level, idx); > > > > > > seems to work better. > > > > Makes sense. > > Here's a patch that implements that. I reckon it's good to have both > workarounds in place because the tf_partial workaround is necessary to > accept class-deduction93a.C below, and the tsubst workaround is > necessary to accept class-deduction-92b.C below. Whoops, forgot to git-add class-deduction93a.C: -- >8 -- Subject: [PATCH] c++: CTAD within alias template [PR91911] In the first testcase below, during parsing of the alias template ConstSpanType, transparency of alias template specializations means we replace SpanType with SpanType's substituted definition. But this substitution 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. In light of this, it seems we should avoid level lowering when substituting through the type-id of a dependent alias template specialization. To that end this patch makes lookup_template_class_1 pass tf_partial to tsubst in this situation. Unfortunately, using tf_partial alone isn't sufficient because the template context in which we perform the dependent substitution may have more levels than the substituted alias template and so we end up substituting the CTAD placeholder anyway, as in class-deduction92b.C below. (There, it seems we'd need to _increase_ the level of the placeholder for span{T()} from 2 to 3 during the dependent substitution.) Since we never want to resolve a CTAD placeholder outside of CTAD proper, this patch takes the relatively ad-hoc approach of making tsubst explicitly avoid doing so. This tsubst workaround doesn't obviate the tf_partial workaround because it's still desirable to avoid prematurely level lowering a CTAD placeholder: it's less work for the compiler, and it gives us a chance to substitute a template placeholder that's a template template parameter with a concrete template template argument, as in the last testcase below. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/91911 gcc/cp/ChangeLog: * pt.c (lookup_template_class_1): When looking up a dependent alias template specialization, pass tf_partial to tsubst. (tsubst) : Avoid substituting a CTAD placeholder. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction92.C: New test. * g++.dg/cpp1z/class-deduction92a.C: New test. * g++.dg/cpp1z/class-deduction92b.C: New test. * g++.dg/cpp1z/class-deduction93.C: New test. * g++.dg/cpp1z/class-deduction93a.C: New test. --- gcc/cp/pt.c | 15 +++++++++-- .../g++.dg/cpp1z/class-deduction92.C | 17 ++++++++++++ .../g++.dg/cpp1z/class-deduction92a.C | 22 +++++++++++++++ .../g++.dg/cpp1z/class-deduction92b.C | 22 +++++++++++++++ .../g++.dg/cpp1z/class-deduction93.C | 25 +++++++++++++++++ .../g++.dg/cpp1z/class-deduction93a.C | 27 +++++++++++++++++++ 6 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction92.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction92a.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction92b.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction93.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction93a.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f2039e09cd7..db769d59951 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9954,7 +9954,12 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, template-arguments for the template-parameters in the type-id of the alias template. */ - t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl); + /* When substituting a dependent alias template specialization, + we pass tf_partial to avoid lowering the level of any 'auto's + within its type-id (91911). */ + t = tsubst (TREE_TYPE (gen_tmpl), arglist, + complain | (tf_partial * is_dependent_type), + in_decl); /* Note that the call above (by indirectly calling register_specialization in tsubst_decl) registers the TYPE_DECL representing the specialization of the alias @@ -15544,9 +15549,15 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) gcc_assert (TREE_VEC_LENGTH (args) > 0); template_parm_level_and_index (t, &level, &idx); + /* Retrieve the argument for this template parameter. */ levels = TMPL_ARGS_DEPTH (args); if (level <= levels - && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0) + && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0 + /* Avoid substituting CTAD placeholders; they get + resolved only during CTAD proper. We can get here + after dependent substitution of an alias template + whose defining-type-id uses CTAD (91911). */ + && !template_placeholder_p (t)) { arg = TMPL_ARG (args, level, idx); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C new file mode 100644 index 00000000000..379eb960da6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.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-deduction92a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction92a.C new file mode 100644 index 00000000000..b9aa8f3bbf0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction92a.C @@ -0,0 +1,22 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } +// A variant of class-deduction92.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-deduction92b.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction92b.C new file mode 100644 index 00000000000..0ea0cef0238 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction92b.C @@ -0,0 +1,22 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } +// A variant of class-deduction92.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-deduction93.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C new file mode 100644 index 00000000000..20504780d32 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.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-deduction93a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction93a.C new file mode 100644 index 00000000000..7656e7845fe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction93a.C @@ -0,0 +1,27 @@ +// PR c++/98077 +// { dg-do compile { target c++17 } } +// A variant of class-deduction93.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; -- 2.32.0.93.g670b81a890