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 BAF3D3833A37 for ; Thu, 15 Dec 2022 22:36:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BAF3D3833A37 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=1671143785; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nNq9HO1i61HVPQ77rLcUrktD6XibTwehaZnJEH4WGAI=; b=eLEKP+X3oyB9tXZeMSN2SpKD+WjPhRrmXmuW31/OOjgnv0AF3Qx8TCm664oFf1WJ2Z1VcU Y9N9KB8JEviiT+KgS2JxN0HcUAKJhpSz3j6drTorBpB2F534Y+aTKd1jLm/LwY28y9BvsQ UUxI4MSoPHUKvgia21kYRTNBh/djvvo= Received: from mail-ua1-f69.google.com (mail-ua1-f69.google.com [209.85.222.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-491-isAWGgyXOrSr7L8zirop8A-1; Thu, 15 Dec 2022 17:36:24 -0500 X-MC-Unique: isAWGgyXOrSr7L8zirop8A-1 Received: by mail-ua1-f69.google.com with SMTP id r3-20020ab04a43000000b0041168b89479so147120uae.6 for ; Thu, 15 Dec 2022 14:36:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=nNq9HO1i61HVPQ77rLcUrktD6XibTwehaZnJEH4WGAI=; b=f9579zpdXisfnehiFQ9sRPrqLiCFo/ysc7vpbzPCMj3nudV+O68ann+3rN/M+nZTXa q33CY2aKhSjyuhmhxZPHyX+FwLGGQjqJMj4y0GzWzleLaK2S7UNyVqXiLYpLWR0S01LT EB+EbYjVfj2r9GCOc/ShvSCcL3JQc1mq46L0Rsz8RA8zcmS/cZybaA8ZtPBAWliggVLD z6K+JG1qfFemmY3DmAqPSm0NI52sLEKymhUjSXGZDZyiJvF0+YO2WESSFuZGAUHsE4Ta zLtuHZca+5ij1tJputKt30Cfo8MOVvoUW4rBglYa1vICXz5f6M/YdU4snigAzfvwcQET LSaA== X-Gm-Message-State: ANoB5pm/f/fpzieOGucdjoO5pIwbFadqLkeliDjkB3bZIWfS4yAYa3AR 296mK7rBGwIbCYizA8KLzWPE182Cey0npmobdJ9tO5d9WdA0fbHg8VcD2P4Z9wJoUoip1MQ8i24 vfSRrunDV3SszCvWSAQ== X-Received: by 2002:a1f:3f8f:0:b0:3bd:7790:b70e with SMTP id m137-20020a1f3f8f000000b003bd7790b70emr17693341vka.1.1671143783183; Thu, 15 Dec 2022 14:36:23 -0800 (PST) X-Google-Smtp-Source: AA0mqf67cAue7elxeAeUnJhwy6Am/eMGcR0hhnLmyv4UoRN8by3u9mQh/OagvtJUFHdbwZ7N8zhFow== X-Received: by 2002:a1f:3f8f:0:b0:3bd:7790:b70e with SMTP id m137-20020a1f3f8f000000b003bd7790b70emr17693335vka.1.1671143782832; Thu, 15 Dec 2022 14:36:22 -0800 (PST) Received: from [192.168.1.108] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id i17-20020a05620a405100b006fcb77f3bd6sm135563qko.98.2022.12.15.14.36.21 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 15 Dec 2022 14:36:21 -0800 (PST) Message-ID: <86efe1d0-3171-cb8a-de69-0ade0c1f280c@redhat.com> Date: Thu, 15 Dec 2022 17:36:21 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 Subject: Re: [PATCH] c++: variadic using-decl with parm pack in terminal name [PR102104] To: Patrick Palka , gcc-patches@gcc.gnu.org References: <20221215161535.2731182-1-ppalka@redhat.com> From: Jason Merrill In-Reply-To: <20221215161535.2731182-1-ppalka@redhat.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,NICE_REPLY_A,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 12/15/22 11:15, Patrick Palka wrote: > There's a curious corner case with variadic member using-decls: the > terminal name can also contain a parameter pack, and only through naming > a conversion function, e.g. > > using A::operator Ts...; > > We currently only handle parameter packs appearing in the qualifying > scope of a variadic using-decl; this patch adds support for the above > case as well, representing such a using-decl with two pack expansions, > one for the qualifying scope and one for the terminal name (despite > logically there being just one). Then at instantiation time we manually > merge them. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? OK. > PR c++/102104 > PR c++/108090 > > gcc/cp/ChangeLog: > > * error.cc (dump_decl) : Look through a > pack expansion in the name as well. > * parser.c (cp_parser_using_declaration): Handle a parameter > pack appearing in the terminal name of a variadic using-decl. > * pt.c (tsubst_decl) : Likewise. Combine the > handling of variadic and non-variadic using-decls. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp1z/using-variadic1.C: New test. > * g++.dg/cpp1z/using-variadic1a.C: New test. > * g++.dg/cpp1z/using-variadic1b.C: New test. > * g++.dg/cpp1z/using-variadic1c.C: New test. > * g++.dg/cpp1z/using-variadic2.C: New test. > * g++.dg/cpp1z/using-variadic3.C: New test. > --- > gcc/cp/error.cc | 9 ++ > gcc/cp/parser.cc | 33 ++++++- > gcc/cp/pt.cc | 91 ++++++++++++++----- > gcc/testsuite/g++.dg/cpp1z/using-variadic1.C | 29 ++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C | 34 +++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C | 37 ++++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C | 33 +++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic2.C | 24 +++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic3.C | 8 ++ > 9 files changed, 272 insertions(+), 26 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > index 12b28e8ee5b..e7f60335cc0 100644 > --- a/gcc/cp/error.cc > +++ b/gcc/cp/error.cc > @@ -1477,11 +1477,20 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) > if (!(flags & TFF_UNQUALIFIED_NAME)) > { > tree scope = USING_DECL_SCOPE (t); > + tree name = DECL_NAME (t); > if (PACK_EXPANSION_P (scope)) > { > scope = PACK_EXPANSION_PATTERN (scope); > variadic = true; > } > + if (identifier_p (name) > + && IDENTIFIER_CONV_OP_P (name) > + && PACK_EXPANSION_P (TREE_TYPE (name))) > + { > + name = make_conv_op_name (PACK_EXPANSION_PATTERN > + (TREE_TYPE (name))); > + variadic = true; > + } > dump_type (pp, scope, flags); > pp_cxx_colon_colon (pp); > } > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index 03550308365..2e2d81c1316 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -21705,7 +21705,38 @@ cp_parser_using_declaration (cp_parser* parser, > pedwarn (ell->location, OPT_Wc__17_extensions, > "pack expansion in using-declaration only available " > "with %<-std=c++17%> or %<-std=gnu++17%>"); > - qscope = make_pack_expansion (qscope); > + > + /* A parameter pack can appear in the qualifying scope, and/or in the > + terminal name (if naming a conversion function). Logically they're > + part of a single pack expansion of the overall USING_DECL, but we > + express them as separate pack expansions within the USING_DECL since > + we can't create a pack expansion over a USING_DECL. */ > + bool saw_parm_pack = false; > + if (uses_parameter_packs (qscope)) > + { > + qscope = make_pack_expansion (qscope); > + saw_parm_pack = true; > + } > + /* It can also appear in the terminal name (if naming a conversion > + function). */ > + if (identifier_p (identifier) > + && IDENTIFIER_CONV_OP_P (identifier) > + && uses_parameter_packs (TREE_TYPE (identifier))) > + { > + identifier = make_conv_op_name (make_pack_expansion > + (TREE_TYPE (identifier))); > + saw_parm_pack = true; > + } > + if (!saw_parm_pack) > + { > + /* Issue an error in terms using a SCOPE_REF that includes both > + components. */ > + tree name > + = build_qualified_name (NULL_TREE, qscope, identifier, false); > + make_pack_expansion (name); > + gcc_assert (seen_error ()); > + qscope = identifier = error_mark_node; > + } > } > > /* The function we call to handle a using-declaration is different > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 44058d30799..2fb7d6832ea 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -14963,43 +14963,84 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) > if (DECL_DEPENDENT_P (t) > || uses_template_parms (USING_DECL_SCOPE (t))) > { > + /* True iff this using-decl was written as a pack expansion > + (and a pack appeared in its scope or name). If a pack > + appeared in both, we expand the packs separately and > + manually merge them. */ > + bool variadic_p = false; > + > tree scope = USING_DECL_SCOPE (t); > - tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl); > if (PACK_EXPANSION_P (scope)) > { > - tree vec = tsubst_pack_expansion (scope, args, complain, in_decl); > - int len = TREE_VEC_LENGTH (vec); > - r = make_tree_vec (len); > - for (int i = 0; i < len; ++i) > + scope = tsubst_pack_expansion (scope, args, complain, in_decl); > + variadic_p = true; > + } > + else > + scope = tsubst_copy (scope, args, complain, in_decl); > + > + tree name = DECL_NAME (t); > + if (IDENTIFIER_CONV_OP_P (name) > + && PACK_EXPANSION_P (TREE_TYPE (name))) > + { > + name = tsubst_pack_expansion (TREE_TYPE (name), args, > + complain, in_decl); > + if (name == error_mark_node) > { > - tree escope = TREE_VEC_ELT (vec, i); > - tree elt = do_class_using_decl (escope, name); > - if (!elt) > - { > - r = error_mark_node; > - break; > - } > - else > - { > - TREE_PROTECTED (elt) = TREE_PROTECTED (t); > - TREE_PRIVATE (elt) = TREE_PRIVATE (t); > - } > - TREE_VEC_ELT (r, i) = elt; > + r = error_mark_node; > + break; > } > + for (int i = 0; i < TREE_VEC_LENGTH (name); i++) > + TREE_VEC_ELT (name, i) > + = make_conv_op_name (TREE_VEC_ELT (name, i)); > + variadic_p = true; > } > else > + name = tsubst_copy (name, args, complain, in_decl); > + > + int len; > + if (!variadic_p) > + len = 1; > + else if (TREE_CODE (scope) == TREE_VEC > + && TREE_CODE (name) == TREE_VEC) > { > - tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args, > - complain, in_decl); > - r = do_class_using_decl (inst_scope, name); > - if (!r) > - r = error_mark_node; > + if (TREE_VEC_LENGTH (scope) != TREE_VEC_LENGTH (name)) > + { > + error ("mismatched argument pack lengths"); > + r = error_mark_node; > + break; > + } > + len = TREE_VEC_LENGTH (scope); > + } > + else if (TREE_CODE (scope) == TREE_VEC) > + len = TREE_VEC_LENGTH (scope); > + else /* TREE_CODE (name) == TREE_VEC */ > + len = TREE_VEC_LENGTH (name); > + > + r = make_tree_vec (len); > + for (int i = 0; i < len; ++i) > + { > + tree escope = (TREE_CODE (scope) == TREE_VEC > + ? TREE_VEC_ELT (scope, i) > + : scope); > + tree ename = (TREE_CODE (name) == TREE_VEC > + ? TREE_VEC_ELT (name, i) > + : name); > + tree elt = do_class_using_decl (escope, ename); > + if (!elt) > + { > + r = error_mark_node; > + break; > + } > else > { > - TREE_PROTECTED (r) = TREE_PROTECTED (t); > - TREE_PRIVATE (r) = TREE_PRIVATE (t); > + TREE_PROTECTED (elt) = TREE_PROTECTED (t); > + TREE_PRIVATE (elt) = TREE_PRIVATE (t); > } > + TREE_VEC_ELT (r, i) = elt; > } > + > + if (!variadic_p && r != error_mark_node) > + r = TREE_VEC_ELT (r, 0); > } > else > { > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > new file mode 100644 > index 00000000000..7a8bcbbe372 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > @@ -0,0 +1,29 @@ > +// PR c++/102104 > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template > +struct cls : private Bases... { > + using Bases::operator typename Bases::target_type...; > +}; > + > +cls v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls v2; > +bool* a2 = v2; // { dg-error "cannot convert" } > +long* b2 = v2; > + > +cls v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "cannot convert" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > new file mode 100644 > index 00000000000..0393cab6ace > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > @@ -0,0 +1,34 @@ > +// PR c++/102104 > +// A version of using-variadic1.C where the qualifying scope and the > +// terminal name of the using-declaration use different parameter packs. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template > +struct cls { > + template > + struct nested : private Bases... { > + using Bases::operator typename Ts::target_type...; > + }; > +}; > + > +cls::nested v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls::nested v2; > +bool* a2 = v2; // { dg-error "cannot convert" } > +long* b2 = v2; > + > +cls::nested v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "cannot convert" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > new file mode 100644 > index 00000000000..fd3a41718b6 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > @@ -0,0 +1,37 @@ > +// PR c++/102104 > +// A version of using-variadic1.C where only the qualifying scope > +// uses a parameter pack. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > +}; > + > +struct B { > + using target_type = long*; > +}; > + > +struct C { > + operator bool*(); > + operator long*(); > +}; > + > +template > +struct cls { > + template > + struct nested : private Base { > + using Base::operator typename Ts::target_type...; > + }; > +}; > + > +cls::nested v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls::nested v2; > +bool* a2 = v2; // { dg-error "inaccessible|not an accessible" } > +long* b2 = v2; > + > +cls::nested v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "inaccessible|not an accessible" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > new file mode 100644 > index 00000000000..aa86b28fd2e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > @@ -0,0 +1,33 @@ > +// PR c++/102104 > +// A version of of using-variadic1.C where only the terminal name > +// uses a parameter pack. > +// { dg-do compile { target c++17 } } > + > +struct A { > + operator bool*(); > +}; > + > +struct B { > + operator bool*(); > +}; > + > +struct C { > + using target_type = bool*; > +}; > + > +template > +struct cls { > + template > + struct nested : private Bases... { > + using Bases::operator typename T::target_type...; > + }; > +}; > + > +cls::nested v1; > +bool* a1 = v1; // { dg-error "ambiguous" } > + > +cls::nested v2; > +bool* a2 = v2; > + > +cls::nested v3; > +bool* a3 = v3; > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > new file mode 100644 > index 00000000000..1d68ceece8a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > @@ -0,0 +1,24 @@ > +// PR c++/102104 > +// A version of using-variadic1a.C where the argument packs have > +// different lengths. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template > +struct cls { > + template > + struct nested : private Bases... { > + using Bases::operator typename Ts::target_type...; // { dg-error "lengths" } > + }; > +}; > + > +cls::nested v1; // { dg-message "required from here" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > new file mode 100644 > index 00000000000..4e1d6894e56 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > @@ -0,0 +1,8 @@ > +// PR c++/108090 > +// { dg-do compile { target c++17 } } > + > +template struct As { operator T(); }; > +template struct AsAll : As... { > + using As::operator T...; > +}; > +AsAll x;