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.129.124]) by sourceware.org (Postfix) with ESMTPS id E75663858D1E for ; Mon, 20 Feb 2023 16:58:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E75663858D1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1676912299; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=CA98MP7xrh8gmlFaIceCjZSNi47cmTuMcPFJaiSURKM=; b=R/E4jAICd+FMbDtMhHNSpjTZY8lcP1M/eQdsYPL3slvpDDxiOErdQlvTtgo/qOOnij5mRs wNRE7tRKJs1NyhJydSstngiXEy9wP30BY3H1j6Q/YdWFVZxI92l8TvaeJuuiqtKpHT0BLA k1LzBg100KBUInPztgdkRTvOQF2kSUg= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-489-Hza0JUsCNBCzTUtduyqWpg-1; Mon, 20 Feb 2023 11:58:18 -0500 X-MC-Unique: Hza0JUsCNBCzTUtduyqWpg-1 Received: by mail-qk1-f197.google.com with SMTP id b1-20020a05620a126100b0073b2dc0e161so459507qkl.12 for ; Mon, 20 Feb 2023 08:58:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:references:message-id:in-reply-to:subject:cc:to:date :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CA98MP7xrh8gmlFaIceCjZSNi47cmTuMcPFJaiSURKM=; b=TATFMINsAYjWv9NlPl9cOqToTbZo8BiwEA0YD0fzSfayvBlSmYeYUhd1uIfvk+cNCt ZgUTlfmrnJhZzxkqkPDQaFrsOuz00SeEE02H9PVOG6qh7PeSii004GxD8UXbvnQoA4eQ Y4dEttH1ZZVf+YJaHZXJxJCOK1lFmufJptvMAkpnwjVtDHOimWM4AywH+m74kRZdi6GE M900KcthXpXUj8QakUbELX+ZmQhHu2Wrl+DGFzwFLhGY7vVFv7UBDv8GsXPDZrFC+wOk w4/jbuCtBFt+a8IMYuLRkLxfnU6YOOvu5lXTKLj+h+P/0FCopTMuMNRn3jzH5BxjDD/p beSw== X-Gm-Message-State: AO0yUKU9FLdxd/+et3eUiyYJCXlCemIR0jyHXIPv+4s2ptGcoWOmzabE 9GcgNHKXzp0Mz0OGJOLu4Bd79HNMf3tImaFrPcBKz7qbEVRcUmswdv5LXUyXg0qyluassEPxvWB s8lgw1IPQePPHIagWqA== X-Received: by 2002:ac8:5715:0:b0:3bd:d57:deea with SMTP id 21-20020ac85715000000b003bd0d57deeamr24690651qtw.60.1676912296606; Mon, 20 Feb 2023 08:58:16 -0800 (PST) X-Google-Smtp-Source: AK7set9nlEnfkBfXYS/PYEPT+H2LMIe2AmY/UWE+8wUExSqY5z7rT9dWXLcmMrItl2aSAy5hITC1ww== X-Received: by 2002:ac8:5715:0:b0:3bd:d57:deea with SMTP id 21-20020ac85715000000b003bd0d57deeamr24690623qtw.60.1676912296163; Mon, 20 Feb 2023 08:58:16 -0800 (PST) Received: from [192.168.1.130] (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id v15-20020a05622a188f00b003bd1594af1fsm8188320qtc.69.2023.02.20.08.58.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 Feb 2023 08:58:15 -0800 (PST) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Mon, 20 Feb 2023 11:58:14 -0500 (EST) To: Jason Merrill cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH RFC 1/3] c++: add __is_deducible trait [PR105841] In-Reply-To: <20230218214239.2297623-1-jason@redhat.com> Message-ID: <61a57325-0312-d0d6-5ad0-977551459637@idea> References: <20230218214239.2297623-1-jason@redhat.com> 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=-13.9 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_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Sat, 18 Feb 2023, Jason Merrill via Gcc-patches wrote: > Tested x86_64-pc-linux-gnu. Since this is fixing experimental (C++20) > functionality, I think it's reasonable to apply now; I'm interested in other > opinions, and thoughts about the user-facing functionality. I'm thinking to > make it internal-only for GCC 13 at least by adding a space in the name, but > does this look useful to the library? IIUC this looks like a generalization of an __is_specialization_of trait that returns whether a type is a specialization of a given class template, which seems potentially useful for the library to me. We already define some ad-hoc predicates for testing this, e.g. __is_reverse_view, __is_span etc in as well as a more general __is_specialization_of in for templates that take only type arguments. Using a built-in trait should be more efficient. > > -- 8< -- > > C++20 class template argument deduction for an alias template involves > adding a constraint that the template arguments for the alias template can > be deduced from the return type of the deduction guide for the underlying > class template. In the standard, this is modeled as defining a class > template with a partial specialization, but it's much more efficient to > implement with a trait that directly tries to perform the deduction. > > The first argument to the trait is a template rather than a type, so various > places needed to be adjusted to accommodate that. > > PR c++/105841 > > gcc/ChangeLog: > > * doc/extend.texi (Type Traits):: Document __is_deducible. > > gcc/cp/ChangeLog: > > * cp-trait.def (IS_DEDUCIBLE): New. > * cxx-pretty-print.cc (pp_cxx_trait): Handle non-type. > * parser.cc (cp_parser_trait): Likewise. > * pt.cc (tsubst_copy_and_build): Likewise. > (type_targs_deducible_from): New. > (alias_ctad_tweaks): Use it. > * semantics.cc (trait_expr_value): Handle CPTK_IS_DEDUCIBLE. > (finish_trait_expr): Likewise. > * constraint.cc (diagnose_trait_expr): Likewise. > * cp-tree.h (type_targs_deducible_from): Declare. > > gcc/testsuite/ChangeLog: > > * g++.dg/ext/is_deducible1.C: New test. > --- > gcc/doc/extend.texi | 4 +++ > gcc/cp/cp-tree.h | 1 + > gcc/cp/constraint.cc | 3 ++ > gcc/cp/cxx-pretty-print.cc | 5 +++- > gcc/cp/parser.cc | 20 +++++++++++--- > gcc/cp/pt.cc | 35 +++++++++++++++++------- > gcc/cp/semantics.cc | 11 ++++++++ > gcc/testsuite/g++.dg/ext/is_deducible1.C | 27 ++++++++++++++++++ > gcc/cp/cp-trait.def | 1 + > 9 files changed, 92 insertions(+), 15 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/ext/is_deducible1.C > > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 1ae68b0f20a..898701424ad 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -25207,6 +25207,10 @@ type. A diagnostic is produced if this requirement is not met. > If @code{type} is a cv-qualified class type, and not a union type > ([basic.compound]) the trait is @code{true}, else it is @code{false}. > > +@item __is_deducible (template, type) > +If template arguments for @code{template} can be deduced from > +@code{type} or obtained from default template arguments. > + > @item __is_empty (type) > If @code{__is_class (type)} is @code{false} then the trait is @code{false}. > Otherwise @code{type} is considered empty if and only if: @code{type} > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 5595335bbf7..e79150ca4d8 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -7372,6 +7372,7 @@ extern tree fn_type_unification (tree, tree, tree, > bool, bool); > extern void mark_decl_instantiated (tree, int); > extern int more_specialized_fn (tree, tree, int); > +extern bool type_targs_deducible_from (tree, tree); > extern void do_decl_instantiation (tree, tree); > extern void do_type_instantiation (tree, tree, tsubst_flags_t); > extern bool always_instantiate_p (tree); > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index 9374327008b..a28c85178fe 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args) > inform (loc, " %qT is not a reference that binds to a temporary " > "object of type %qT (copy-initialization)", t1, t2); > break; > + case CPTK_IS_DEDUCIBLE: > + inform (loc, " %qD is not deducible from %qT", t1, t2); > + break; > #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > case CPTK_##CODE: > #include "cp-trait.def" > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > index bea52a608f1..4ebd957decd 100644 > --- a/gcc/cp/cxx-pretty-print.cc > +++ b/gcc/cp/cxx-pretty-print.cc > @@ -2626,7 +2626,10 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > } > > pp_cxx_left_paren (pp); > - pp->type_id (type1); > + if (DECL_P (type1)) > + pp->expression (type1); > + else > + pp->type_id (type1); Since the first argument of a TRAIT_EXPR can now be a TEMPLATE_DECL, I suppose cp_tree_equal needs to be changed too. > if (type2) > { > if (TREE_CODE (type2) != TREE_LIST) > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index 1a124f5395e..68950cace78 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -10960,10 +10960,22 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > matching_parens parens; > parens.require_open (parser); > > - { > - type_id_in_expr_sentinel s (parser); > - type1 = cp_parser_type_id (parser); > - } > + if (kind == CPTK_IS_DEDUCIBLE) > + { > + const cp_token* token = cp_lexer_peek_token (parser->lexer); > + type1 = cp_parser_id_expression (parser, > + /*template_keyword_p=*/false, > + /*check_dependency_p=*/true, > + nullptr, > + /*declarator_p=*/false, > + /*optional_p=*/false); > + type1 = cp_parser_lookup_name_simple (parser, type1, token->location); > + } > + else > + { > + type_id_in_expr_sentinel s (parser); > + type1 = cp_parser_type_id (parser); > + } > > if (type1 == error_mark_node) > return error_mark_node; > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index b1ac7d4beb4..2aa06557b99 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -21577,8 +21577,9 @@ tsubst_copy_and_build (tree t, > > case TRAIT_EXPR: > { > - tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args, > - complain, in_decl); > + tree type1 = TRAIT_EXPR_TYPE1 (t); > + if (TREE_CODE (type1) != TEMPLATE_DECL) > + type1 = tsubst (type1, args, complain, in_decl); > tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args, > complain, in_decl); > RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t), > @@ -29979,7 +29980,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) > /* This implementation differs from the above in two significant ways: > > 1) We include all template parameters of A, not just some. > - 2) The added constraint is same_type instead of deducible. > + 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 > @@ -30079,7 +30080,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) > /* FIXME this should mean they don't compare as equivalent. */ > || dependent_alias_template_spec_p (atype, nt_opaque)) > { > - tree same = finish_trait_expr (loc, CPTK_IS_SAME, atype, ret); > + tree same = finish_trait_expr (loc, CPTK_IS_DEDUCIBLE, tmpl, ret); > ci = append_constraint (ci, same); > } > > @@ -30093,12 +30094,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. */ > - tree targs = make_tree_vec (natparms); > - int err = unify (atparms, targs, utype, ret, UNIFY_ALLOW_NONE, false); > - for (unsigned i = 0; !err && i < natparms; ++i) > - if (TREE_VEC_ELT (targs, i) == NULL_TREE) > - err = true; > - if (err) > + if (!type_targs_deducible_from (tmpl, ret)) > continue; > } > > @@ -30108,6 +30104,25 @@ alias_ctad_tweaks (tree tmpl, tree uguides) > return aguides; > } > > +/* True iff template arguments for TMPL can be deduced from TYPE. > + Used to implement CPTK_IS_DEDUCIBLE for alias CTAD. */ > + > +bool > +type_targs_deducible_from (tree tmpl, tree type) > +{ > + tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl); > + int len = TREE_VEC_LENGTH (tparms); > + tree targs = make_tree_vec (len); > + if (unify (tparms, targs, TREE_TYPE (tmpl), type, > + UNIFY_ALLOW_NONE, false)) > + return false; > + /* Maybe add in default template args. */ > + targs = coerce_template_parms (tparms, targs, tmpl, tf_none); > + if (targs == error_mark_node) > + return false; > + return constraints_satisfied_p (tmpl, targs); > +} For sake of the __is_specialization_of use case, I wonder if it'd be possible to have a "fast path" that avoids deduction/coercion when the given template is a class template? > + > /* Return artificial deduction guides built from the constructors of class > template TMPL. */ > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 79b7cc72f21..9103f5de2f4 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -12048,6 +12048,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) > case CPTK_REF_CONVERTS_FROM_TEMPORARY: > return ref_xes_from_temporary (type1, type2, /*direct_init=*/false); > > + case CPTK_IS_DEDUCIBLE: > + return type_targs_deducible_from (type1, type2); > + > #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > case CPTK_##CODE: > #include "cp-trait.def" > @@ -12205,6 +12208,14 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) > return error_mark_node; > break; > > + case CPTK_IS_DEDUCIBLE: > + if (!DECL_TYPE_TEMPLATE_P (type1)) > + { > + error ("%qD is not a class or alias template", type1); > + return error_mark_node; > + } > + break; > + > #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > case CPTK_##CODE: > #include "cp-trait.def" > diff --git a/gcc/testsuite/g++.dg/ext/is_deducible1.C b/gcc/testsuite/g++.dg/ext/is_deducible1.C > new file mode 100644 > index 00000000000..857f59db4c8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ext/is_deducible1.C > @@ -0,0 +1,27 @@ > +// { dg-do compile { target c++20 } } > + > +template struct A { }; > +template struct B { }; > + > +// Simple forms. > +static_assert (__is_deducible (::A, A)); > +static_assert (__is_deducible (B, B)); > +static_assert (!__is_deducible (A, B)); > +static_assert (!__is_deducible (::B, A)); > + > +// This is the interesting use case for alias CTAD. > +template using AP = A; > +static_assert (__is_deducible (AP, A)); > +static_assert (!__is_deducible (AP, A)); > + > +// Can't deduce a parameter not used on the RHS. > +template using C = void; > +static_assert (!__is_deducible (C, C)); > + > +// But a default template argument counts. > +template using D = void; > +static_assert (__is_deducible (D, D)); > + > +// We don't try to support this. > +template void f(T); > +bool b = __is_deducible (f, void (int)); // { dg-error "class or alias" } > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def > index 823899a26c5..e43fb464f42 100644 > --- a/gcc/cp/cp-trait.def > +++ b/gcc/cp/cp-trait.def > @@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1) > DEFTRAIT_EXPR (IS_UNION, "__is_union", 1) > DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2) > DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2) > +DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible", 2) > > DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) > DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) > > base-commit: 9944ca17c0766623bce260684edc614def7ea761 > -- > 2.31.1 > >