From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by sourceware.org (Postfix) with ESMTP id ED44E385DC34 for ; Tue, 7 Apr 2020 17:40:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org ED44E385DC34 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-218-MyTrJ1xuP-6Inny12EI7ug-1; Tue, 07 Apr 2020 13:40:26 -0400 X-MC-Unique: MyTrJ1xuP-6Inny12EI7ug-1 Received: by mail-qt1-f200.google.com with SMTP id w1so3750258qte.6 for ; Tue, 07 Apr 2020 10:40:26 -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:user-agent:mime-version; bh=m86iI5Ge3yJZ0rwiVaGeChQVP697f3hOvAcbk0gN7gU=; b=MxyiZ/1yTwOh0uQt3XSCk3dCtCPk9pv0gSFrZGtUz9k500p9hVHY20PBLRafmBJyhM cJP6EUe3LqfIP4QprBmcnR2w1LSPoDr9kudMPoekTfstBhKh+PSqrkOVLBHu+vEc1Ioj YfSikU5Z+ppfiI+5Ldhg41Ea0jeBFzltsA4XaH7a8T51Egz+y9+SGlGdBZbovmJP+nJn 2OBVtN96SE3UPxGEFRYUD1POxnPYXvjOo98mgEGvupryDHxSi5S7pl6vWMh6o8U2e70h pFLaQdXYyLTDGYusXqt97CdJu4sj/xD79B5NCf/doQnmgewMJfeanBnf221pdFAflpzw xmpw== X-Gm-Message-State: AGi0Pua6lMU7o6p952YfXhd9ESVi4Hd8Sfw318RCWcUupndRD0+NuKAh hoY140DlkVOZ8er3VbuTCbijTwRr4W6uxkWNHwARJqsoc5UUYJaXXagHb4AF4iZW6222noJLoeH atLXiaZx6BzjlBUk6RQ== X-Received: by 2002:a05:6214:1367:: with SMTP id c7mr3265590qvw.22.1586281225473; Tue, 07 Apr 2020 10:40:25 -0700 (PDT) X-Google-Smtp-Source: APiQypLVImfDJ/AVSBFz2l/HNh1gPZsHQdRDevY7qthuTbzYsJ1UsbF8+5oguu1fS1TyOQYIDqLBTw== X-Received: by 2002:a05:6214:1367:: with SMTP id c7mr3265533qvw.22.1586281224725; Tue, 07 Apr 2020 10:40:24 -0700 (PDT) Received: from [192.168.1.130] (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id l3sm5755773qkl.85.2020.04.07.10.40.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2020 10:40:23 -0700 (PDT) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Tue, 7 Apr 2020 13:40:22 -0400 (EDT) To: Jason Merrill cc: Patrick Palka , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010] In-Reply-To: <6716ec8e-7c6d-04b0-a545-b0b0e8248669@redhat.com> Message-ID: References: <20200323012105.3692086-1-ppalka@redhat.com> <0c702b38-1fca-d0ac-c1ee-f7e080d9367c@redhat.com> <6716ec8e-7c6d-04b0-a545-b0b0e8248669@redhat.com> User-Agent: Alpine 2.22 (DEB 413 2020-03-19) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-28.5 required=5.0 tests=BAYES_00, BODY_8BITS, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, 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 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.29 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: Tue, 07 Apr 2020 17:40:32 -0000 On Mon, 6 Apr 2020, Jason Merrill wrote: > On 4/6/20 11:45 AM, Patrick Palka wrote: > > On Wed, 1 Apr 2020, Jason Merrill wrote: > >=20 > > > On 4/1/20 6:29 PM, Jason Merrill wrote: > > > > On 3/31/20 3:50 PM, Patrick Palka wrote: > > > > > On Tue, 31 Mar 2020, Jason Merrill wrote: > > > > >=20 > > > > > > On 3/30/20 6:46 PM, Patrick Palka wrote: > > > > > > > On Mon, 30 Mar 2020, Jason Merrill wrote: > > > > > > > > On 3/30/20 3:58 PM, Patrick Palka wrote: > > > > > > > > > On Thu, 26 Mar 2020, Jason Merrill wrote: > > > > > > > > >=20 > > > > > > > > > > On 3/22/20 9:21 PM, Patrick Palka wrote: > > > > > > > > > > > This patch relaxes an assertion in tsubst_default_arg= ument > > > > > > > > > > > that > > > > > > > > > > > exposes > > > > > > > > > > > a > > > > > > > > > > > latent > > > > > > > > > > > bug in how we substitute an array type into a cv-qual= ified > > > > > > > > > > > wildcard > > > > > > > > > > > function > > > > > > > > > > > parameter type.=C2=A0 Concretely, the latent bug is t= hat given > > > > > > > > > > > the > > > > > > > > > > > function > > > > > > > > > > > template > > > > > > > > > > >=20 > > > > > > > > > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 template = void foo(const T t); > > > > > > > > > > >=20 > > > > > > > > > > > one would expect the type of foo to be void(co= nst > > > > > > > > > > > int*), but > > > > > > > > > > > we > > > > > > > > > > > (seemingly prematurely) strip function parameter type= s of > > > > > > > > > > > their > > > > > > > > > > > top-level > > > > > > > > > > > cv-qualifiers when building the function's TYPE_ARG_T= YPES, > > > > > > > > > > > and > > > > > > > > > > > instead > > > > > > > > > > > end > > > > > > > > > > > up > > > > > > > > > > > obtaining void(int*) as the type of foo after > > > > > > > > > > > substitution > > > > > > > > > > > and > > > > > > > > > > > decaying. > > > > > > > > > > >=20 > > > > > > > > > > > We still however correctly substitute into and decay = the > > > > > > > > > > > formal > > > > > > > > > > > parameter > > > > > > > > > > > type, > > > > > > > > > > > obtaining const int* as the type of t after substitut= ion.=C2=A0 > > > > > > > > > > > But > > > > > > > > > > > this > > > > > > > > > > > then > > > > > > > > > > > leads > > > > > > > > > > > to us tripping over the assert in tsubst_default_argu= ment > > > > > > > > > > > that > > > > > > > > > > > verifies > > > > > > > > > > > the > > > > > > > > > > > formal parameter type and the function type are > > > > > > > > > > > consistent. > > > > > > > > > > >=20 > > > > > > > > > > > Assuming it's too late at this stage to fix the > > > > > > > > > > > substitution > > > > > > > > > > > bug, we > > > > > > > > > > > can > > > > > > > > > > > still > > > > > > > > > > > relax the assertion like so.=C2=A0 Tested on > > > > > > > > > > > x86_64-pc-linux-gnu, > > > > > > > > > > > does > > > > > > > > > > > this > > > > > > > > > > > look > > > > > > > > > > > OK? > > > > > > > > > >=20 > > > > > > > > > > This is core issues 1001/1322, which have not been reso= lved. > > > > > > > > > > Clang > > > > > > > > > > does > > > > > > > > > > the > > > > > > > > > > substitution the way you suggest; EDG rejects the testc= ase > > > > > > > > > > because the > > > > > > > > > > two > > > > > > > > > > substitutions produce different results.=C2=A0 I think = it would > > > > > > > > > > make > > > > > > > > > > sense > > > > > > > > > > to > > > > > > > > > > follow the EDG behavior until this issue is actually > > > > > > > > > > resolved. > > > > > > > > >=20 > > > > > > > > > Here is what I have so far towards that end.=C2=A0 When > > > > > > > > > substituting > > > > > > > > > into the > > > > > > > > > PARM_DECLs of a function decl, we now additionally check = if > > > > > > > > > the > > > > > > > > > aforementioned Core issues are relevant and issue a (fata= l) > > > > > > > > > diagnostic > > > > > > > > > if so.=C2=A0 This patch checks this in tsubst_decl > > > > > > > > > rather > > > > > > > > > than in tsubst_function_decl for efficiency reasons, so t= hat > > > > > > > > > we > > > > > > > > > don't > > > > > > > > > have to perform another traversal over the DECL_ARGUMENTS= / > > > > > > > > > TYPE_ARG_TYPES just to implement this check. > > > > > > > >=20 > > > > > > > > Hmm, this seems like writing more complicated code for a ve= ry > > > > > > > > marginal > > > > > > > > optimization; how many function templates have so many > > > > > > > > parameters > > > > > > > > that > > > > > > > > walking > > > > > > > > over them once to compare types will have any effect on com= pile > > > > > > > > time? > > > > > > >=20 > > > > > > > Good point... though I just tried implementing this check in > > > > > > > tsubst_function_decl, and it seems it might be just as compli= cated > > > > > > > to > > > > > > > implement it there instead, at least if we want to handle fun= ction > > > > > > > parameter packs correctly. > > > > > > >=20 > > > > > > > If we were to implement this check in tsubst_function_decl, t= hen > > > > > > > since > > > > > > > we have access to the instantiated function, it would presuma= bly > > > > > > > suffice > > > > > > > to compare its substituted DECL_ARGUMENTS with its substitute= d > > > > > > > TYPE_ARG_TYPES to see if they're consistent.=C2=A0 Doing so w= ould > > > > > > > certainly > > > > > > > catch the original testcase, i.e. > > > > > > >=20 > > > > > > > =C2=A0=C2=A0=C2=A0 template > > > > > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo(const T); > > > > > > > =C2=A0=C2=A0=C2=A0 int main() { foo(0); } > > > > > > >=20 > > > > > > > because the DECL_ARGUMENTS of foo would be {const int*= } and > > > > > > > its > > > > > > > TYPE_ARG_TYPES would be {int*}.=C2=A0 But apparently it doesn= 't catch > > > > > > > the > > > > > > > corresponding testcase that uses a function parameter pack, i= .e. > > > > > > >=20 > > > > > > > =C2=A0=C2=A0=C2=A0 template > > > > > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 void foo(const Ts...); > > > > > > > =C2=A0=C2=A0=C2=A0 int main() { foo(0); } > > > > > > >=20 > > > > > > > because it turns out we don't strip top-level cv-qualifiers f= rom > > > > > > > function parameter packs from TYPE_ARG_TYPES at declaration t= ime, > > > > > > > as > > > > > > > we > > > > > > > do with regular function parameters.=C2=A0 So in this second = testcase > > > > > > > both > > > > > > > DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {con= st > > > > > > > int*}, > > > > > > > and yet we would (presumably) want to reject this instantiati= on > > > > > > > too. > > > > > > >=20 > > > > > > > So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from > > > > > > > tsubst_function_decl would not suffice, and we would still ne= ed to > > > > > > > do > > > > > > > a > > > > > > > variant of the trick that's done in this patch, i.e. substitu= te > > > > > > > into > > > > > > > each dependent parameter type stripped of its top-level > > > > > > > cv-qualifiers, > > > > > > > to see if these cv-qualifiers make a material difference in t= he > > > > > > > resulting function type.=C2=A0 Or maybe there's yet another w= ay to > > > > > > > detect > > > > > > > this? > > > > > >=20 > > > > > > I think let's go ahead with comparing TYPE_ARG_TYPES and > > > > > > DECL_ARGUMENTS; > > > > > > the > > > > > > problem comes when they disagree.=C2=A0 If we're handling pack = expansions > > > > > > wrong, > > > > > > that's a separate issue. > > > > >=20 > > > > > Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility > > > > > seems > > > > > to be exposing a latent bug with how we handle lambdas that appea= r in > > > > > function parameter types.=C2=A0 Take g++.dg/cpp2a/lambda-uneval3.= C for > > > > > example: > > > > >=20 > > > > > =C2=A0=C2=A0=C2=A0=C2=A0 template void spam(decltype([= ]{}) (*s)[sizeof(T)]) {} > > > > > =C2=A0=C2=A0=C2=A0=C2=A0 int main() { spam(nullptr); } > > > > >=20 > > > > > According to tsubst_function_decl in current trunk, the type of t= he > > > > > function paremeter 's' of spam according to its TYPE_ARG_TY= PES > > > > > is > > > > > =C2=A0=C2=A0=C2=A0=C2=A0 struct ._anon_4[1] * > > > > > and according to its DECL_ARGUMENTS the type of 's' is > > > > > =C2=A0=C2=A0=C2=A0=C2=A0 struct ._anon_5[1] * > > > > >=20 > > > > > The disagreement happens because we call tsubst_lambda_expr twice > > > > > during > > > > > substitution and thereby generate two distinct lambda types, one = when > > > > > substituting into the TYPE_ARG_TYPES and another when substitutin= g > > > > > into > > > > > the DECL_ARGUMENTS.=C2=A0 I'm not sure how to work around this > > > > > bug/false-positive.. > > > >=20 > > > > Oof. > > > >=20 > > > > I think probably the right answer is to rebuild TYPE_ARG_TYPES from > > > > DECL_ARGUMENTS if they don't match. > > >=20 > > > ...and treat that as a resolution of 1001/1322, so not giving an erro= r. > >=20 > > Is something like this what you have in mind? Bootstrap and testing in > > progress. >=20 > Yes, thanks. >=20 > > -- >8 -- > >=20 > > Subject: [PATCH] c++: Rebuild function type when it disagrees with form= al > > parameter types [PR92010] > >=20 > > gcc/cp/ChangeLog: > >=20 > > =09Core issues 1001 and 1322 > > =09PR c++/92010 > > =09* pt.c (maybe_rebuild_function_type): New function. > > =09(tsubst_function_decl): Use it. > >=20 > > gcc/testsuite/ChangeLog: > >=20 > > =09Core issues 1001 and 1322 > > =09PR c++/92010 > > =09* g++.dg/cpp2a/lambda-uneval11.c: New test. > > =09* g++.dg/template/array33.C: New test. > > =09* g++.dg/template/array34.C: New test. > > =09* g++.dg/template/defarg22.C: New test. > > --- > > gcc/cp/pt.c | 55 +++++++++++++++++ > > gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C | 10 ++++ > > gcc/testsuite/g++.dg/template/array33.C | 63 +++++++++++++++++++= + > > gcc/testsuite/g++.dg/template/array34.C | 63 +++++++++++++++++++= + > > gcc/testsuite/g++.dg/template/defarg22.C | 13 ++++ > > 5 files changed, 204 insertions(+) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C > > create mode 100644 gcc/testsuite/g++.dg/template/array33.C > > create mode 100644 gcc/testsuite/g++.dg/template/array34.C > > create mode 100644 gcc/testsuite/g++.dg/template/defarg22.C > >=20 > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > > index 041ce35a31c..fc0df790c0f 100644 > > --- a/gcc/cp/pt.c > > +++ b/gcc/cp/pt.c > > @@ -13475,6 +13475,59 @@ lookup_explicit_specifier (tree v) > > return *explicit_specifier_map->get (v); > > } > > +/* Check if the function type of DECL, a FUNCTION_DECL, agrees with = the > > type of > > + each of its formal parameters. If there is a disagreement then reb= uild > > + DECL's function type according to its formal parameter types, as pa= rt of > > a > > + resolution for Core issues 1001/1322. */ > > + > > +static void > > +maybe_rebuild_function_decl_type (tree decl) > > +{ > > + bool function_type_needs_rebuilding =3D false; > > + if (tree parm_list =3D FUNCTION_FIRST_USER_PARM (decl)) > > + { > > + tree parm_type_list =3D FUNCTION_FIRST_USER_PARMTYPE (decl); > > + while (parm_type_list && parm_type_list !=3D void_list_node) > > +=09{ > > +=09 tree parm_type =3D TREE_VALUE (parm_type_list); > > +=09 tree formal_parm_type_unqual =3D strip_top_quals (TREE_TYPE > > (parm_list)); > > +=09 if (!same_type_p (parm_type, formal_parm_type_unqual)) > > +=09 { > > +=09 function_type_needs_rebuilding =3D true; > > +=09 break; > > +=09 } > > + > > +=09 parm_list =3D DECL_CHAIN (parm_list); > > +=09 parm_type_list =3D TREE_CHAIN (parm_type_list); > > +=09} > > + } > > + > > + if (!function_type_needs_rebuilding) > > + return; > > + > > + const tree new_arg_types =3D copy_list (TYPE_ARG_TYPES (TREE_TYPE (d= ecl))); > > + > > + tree parm_list =3D FUNCTION_FIRST_USER_PARM (decl); > > + tree old_parm_type_list =3D FUNCTION_FIRST_USER_PARMTYPE (decl); > > + tree new_parm_type_list =3D skip_artificial_parms_for (decl, > > new_arg_types); > > + while (old_parm_type_list && old_parm_type_list !=3D void_list_node) > > + { > > + tree *new_parm_type =3D &TREE_VALUE (new_parm_type_list); > > + tree formal_parm_type_unqual =3D strip_top_quals (TREE_TYPE > > (parm_list)); > > + if (!same_type_p (*new_parm_type, formal_parm_type_unqual)) > > +=09*new_parm_type =3D formal_parm_type_unqual; > > + > > + if (TREE_CHAIN (old_parm_type_list) =3D=3D void_list_node) > > +=09TREE_CHAIN (new_parm_type_list) =3D void_list_node; > > + parm_list =3D DECL_CHAIN (parm_list); > > + old_parm_type_list =3D TREE_CHAIN (old_parm_type_list); > > + new_parm_type_list =3D TREE_CHAIN (new_parm_type_list); > > + } >=20 > The usual pattern for this sort of thing is to use a tree* to track the e= nd of > the new list, which should also avoid making a garbage copy of void_list_= node. > e.g. from tsubst_attribute: >=20 > > tree list =3D NULL_TREE; > > tree *q =3D &list; > > for (int i =3D 0; i < len; ++i) > > { > > tree elt =3D TREE_VEC_ELT (pack, i); > > *q =3D build_tree_list (purp, elt); > > q =3D &TREE_CHAIN (*q); > > } Ah so that's the right way do it :) Patch updated to make use of this pattern. This version of the patch is more complete. It builds the new FUNCTION_TYPE and METHOD_TYPE the same way that tsubst_function_type does, by splitting out and reusing the relevant parts of tsubst_function_type into a separate subroutine that is responsible for propagating TYPE_ATTRIBUTES, TYPE_RAISES_EXCEPTION, ref-qualifiers, etc. I wonder if for consistency and correctness we might have to update other callers of tsubst_function_type/tsubst to make sure this function-type-rebuilding based on parameter types is done in these callers too. For example, there is is_specialization_of_friend which calls tsubst_function_type on the type of a function decl, and fn_type_unification and determine_specialization which also call tsubst on the type of a function decl (and pass the tf_fndecl_type flag). If so, maybe we could instead leverage the tf_fndecl_type flag and the 'in_decl' tsubst parameter to change tsubst_arg_types to immediately build the function type according to the parameter types of in_decl (which would presumably be the FUNCTION_DECL)? That way, we would just have to update the above potentially problematic callers to pass tf_fndecl_type and set in_decl appropriately when calling tsubst and would only have to build the function type once. Patch partially tested on unbootstrapped x86_64-pc-linux-gnu, and bootstrap/regtest is in progress. -- >8 -- Subject: [PATCH] c++: Rebuild function type when it disagrees with formal parameter types [PR92010] gcc/cp/ChangeLog: =09Core issues 1001 and 1322 =09PR c++/92010 =09* pt.c (rebuild_function_or_method_type): Split function out from ... =09(tsubst_function_type): ... here. =09(maybe_rebuild_function_type): New function. =09(tsubst_function_decl): Use it. gcc/testsuite/ChangeLog: =09Core issues 1001 and 1322 =09PR c++/92010 =09* g++.dg/cpp2a/lambda-uneval11.c: New test. =09* g++.dg/template/array33.C: New test. =09* g++.dg/template/array34.C: New test. =09* g++.dg/template/defarg22.C: New test. --- gcc/cp/pt.c | 151 ++++++++++++++----- gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C | 10 ++ gcc/testsuite/g++.dg/template/array33.C | 63 ++++++++ gcc/testsuite/g++.dg/template/array34.C | 63 ++++++++ gcc/testsuite/g++.dg/template/defarg22.C | 13 ++ 5 files changed, 263 insertions(+), 37 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C create mode 100644 gcc/testsuite/g++.dg/template/array33.C create mode 100644 gcc/testsuite/g++.dg/template/array34.C create mode 100644 gcc/testsuite/g++.dg/template/defarg22.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6122227c22f..256a937eace 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13475,6 +13475,116 @@ lookup_explicit_specifier (tree v) return *explicit_specifier_map->get (v); } =20 +/* Given T, a FUNCTION_TYPE or METHOD_TYPE, construct and return a corresp= onding + FUNCTION_TYPE or METHOD_TYPE whose return type is RETURN_TYPE, argument= types + are ARG_TYPES, and exception specification is RAISES, and otherwise is + identical to T. */ + +static tree +rebuild_function_or_method_type (tree t, tree return_type, tree arg_types, +=09=09=09=09 tree raises, tsubst_flags_t complain) +{ + gcc_assert (FUNC_OR_METHOD_TYPE_P (t)); + + tree new_type; + if (TREE_CODE (t) =3D=3D FUNCTION_TYPE) + { + new_type =3D build_function_type (return_type, arg_types); + new_type =3D apply_memfn_quals (new_type, type_memfn_quals (t)); + } + else + { + tree r =3D TREE_TYPE (TREE_VALUE (arg_types)); + /* Don't pick up extra function qualifiers from the basetype. */ + r =3D cp_build_qualified_type_real (r, type_memfn_quals (t), complai= n); + if (! MAYBE_CLASS_TYPE_P (r)) +=09{ +=09 /* [temp.deduct] + +=09 Type deduction may fail for any of the following +=09 reasons: + +=09 -- Attempting to create "pointer to member of T" when T +=09 is not a class type. */ +=09 if (complain & tf_error) +=09 error ("creating pointer to member function of non-class type %qT", +=09=09 r); +=09 return error_mark_node; +=09} + + new_type =3D build_method_type_directly (r, return_type, +=09=09=09=09=09 TREE_CHAIN (arg_types)); + } + new_type =3D cp_build_type_attribute_variant (new_type, TYPE_ATTRIBUTES = (t)); + + cp_ref_qualifier rqual =3D type_memfn_rqual (t); + bool late_return_type_p =3D TYPE_HAS_LATE_RETURN_TYPE (t); + return build_cp_fntype_variant (new_type, rqual, raises, late_return_typ= e_p); +} + +/* Check if the function type of DECL, a FUNCTION_DECL, agrees with the ty= pe of + each of its formal parameters. If there is a disagreement then rebuild + DECL's function type according to its formal parameter types, as part o= f a + resolution for Core issues 1001/1322. */ + +static void +maybe_rebuild_function_decl_type (tree decl) +{ + bool function_type_needs_rebuilding =3D false; + if (tree parm_list =3D FUNCTION_FIRST_USER_PARM (decl)) + { + tree parm_type_list =3D FUNCTION_FIRST_USER_PARMTYPE (decl); + while (parm_type_list && parm_type_list !=3D void_list_node) +=09{ +=09 tree parm_type =3D TREE_VALUE (parm_type_list); +=09 tree formal_parm_type_unqual =3D strip_top_quals (TREE_TYPE (parm_lis= t)); +=09 if (!same_type_p (parm_type, formal_parm_type_unqual)) +=09 { +=09 function_type_needs_rebuilding =3D true; +=09 break; +=09 } + +=09 parm_list =3D DECL_CHAIN (parm_list); +=09 parm_type_list =3D TREE_CHAIN (parm_type_list); +=09} + } + + if (!function_type_needs_rebuilding) + return; + + const tree fntype =3D TREE_TYPE (decl); + tree parm_list =3D DECL_ARGUMENTS (decl); + tree old_parm_type_list =3D TYPE_ARG_TYPES (fntype); + tree new_parm_type_list =3D NULL_TREE; + tree *q =3D &new_parm_type_list; + for (int skip =3D num_artificial_parms_for (decl); skip > 0; skip--) + { + *q =3D copy_node (old_parm_type_list); + parm_list =3D DECL_CHAIN (parm_list); + old_parm_type_list =3D TREE_CHAIN (old_parm_type_list); + q =3D &TREE_CHAIN (*q); + } + while (old_parm_type_list && old_parm_type_list !=3D void_list_node) + { + *q =3D copy_node (old_parm_type_list); + tree *new_parm_type =3D &TREE_VALUE (*q); + tree formal_parm_type_unqual =3D strip_top_quals (TREE_TYPE (parm_li= st)); + if (!same_type_p (*new_parm_type, formal_parm_type_unqual)) +=09*new_parm_type =3D formal_parm_type_unqual; + + parm_list =3D DECL_CHAIN (parm_list); + old_parm_type_list =3D TREE_CHAIN (old_parm_type_list); + q =3D &TREE_CHAIN (*q); + } + if (old_parm_type_list =3D=3D void_list_node) + *q =3D void_list_node; + + TREE_TYPE (decl) + =3D rebuild_function_or_method_type (fntype, +=09=09=09=09 TREE_TYPE (fntype), new_parm_type_list, +=09=09=09=09 TYPE_RAISES_EXCEPTIONS (fntype), tf_none); +} + /* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL. */ =20 static tree @@ -13665,6 +13775,8 @@ tsubst_function_decl (tree t, tree args, tsubst_fla= gs_t complain, DECL_ARGUMENTS (r) =3D parms; DECL_RESULT (r) =3D NULL_TREE; =20 + maybe_rebuild_function_decl_type (r); + TREE_STATIC (r) =3D 0; TREE_PUBLIC (r) =3D TREE_PUBLIC (t); DECL_EXTERNAL (r) =3D 1; @@ -14694,7 +14806,6 @@ tsubst_function_type (tree t, { tree return_type; tree arg_types =3D NULL_TREE; - tree fntype; =20 /* The TYPE_CONTEXT is not used for function/method types. */ gcc_assert (TYPE_CONTEXT (t) =3D=3D NULL_TREE); @@ -14765,42 +14876,8 @@ tsubst_function_type (tree t, } =20 /* Construct a new type node and return it. */ - if (TREE_CODE (t) =3D=3D FUNCTION_TYPE) - { - fntype =3D build_function_type (return_type, arg_types); - fntype =3D apply_memfn_quals (fntype, type_memfn_quals (t)); - } - else - { - tree r =3D TREE_TYPE (TREE_VALUE (arg_types)); - /* Don't pick up extra function qualifiers from the basetype. */ - r =3D cp_build_qualified_type_real (r, type_memfn_quals (t), complai= n); - if (! MAYBE_CLASS_TYPE_P (r)) -=09{ -=09 /* [temp.deduct] - -=09 Type deduction may fail for any of the following -=09 reasons: - -=09 -- Attempting to create "pointer to member of T" when T -=09 is not a class type. */ -=09 if (complain & tf_error) -=09 error ("creating pointer to member function of non-class type %qT", -=09=09 r); -=09 return error_mark_node; -=09} - - fntype =3D build_method_type_directly (r, return_type, -=09=09=09=09=09 TREE_CHAIN (arg_types)); - } - fntype =3D cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t))= ; - - /* See comment above. */ - tree raises =3D NULL_TREE; - cp_ref_qualifier rqual =3D type_memfn_rqual (t); - fntype =3D build_cp_fntype_variant (fntype, rqual, raises, late_return_t= ype_p); - - return fntype; + return rebuild_function_or_method_type (t, return_type, arg_types, +=09=09=09=09=09 /*raises=3D*/NULL_TREE, complain); } =20 /* FNTYPE is a FUNCTION_TYPE or METHOD_TYPE. Substitute the template diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C b/gcc/testsuite/g= ++.dg/cpp2a/lambda-uneval11.C new file mode 100644 index 00000000000..a04262494c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval11.C @@ -0,0 +1,10 @@ +// PR c++/92010 +// { dg-do compile { target c++2a } } + +template void spam(decltype([]{}) (*s)[sizeof(T)] =3D nullptr) +{ } + +void foo() +{ + spam(); +} diff --git a/gcc/testsuite/g++.dg/template/array33.C b/gcc/testsuite/g++.dg= /template/array33.C new file mode 100644 index 00000000000..0aa587351b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/array33.C @@ -0,0 +1,63 @@ +// Verify that top-level cv-qualifiers on parameter types are considered +// when determining the function type of an instantiated function template= . +// This resolves a part of Core issues 1001/1322. +// { dg-do compile } +// { dg-additional-options "-Wno-volatile" } + +template +void foo0(T t =3D 0); + +template +void foo1(const T =3D 0); + +template +void foo2(volatile T t =3D 0); + +template +void foo3(const volatile T t =3D 0); + +#if __cplusplus >=3D 201103L +#define SA(X) static_assert(X,#X) +SA(__is_same(decltype(foo0), void(char*))); +SA(__is_same(decltype(foo0), void(const char*))); +SA(__is_same(decltype(foo0), void(volatile char*))); +SA(__is_same(decltype(foo0), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo1), void(const char*))); +SA(__is_same(decltype(foo1), void(const char*))); +SA(__is_same(decltype(foo1), void(const volatile char*)))= ; +SA(__is_same(decltype(foo1), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo2), void(volatile char*))); +SA(__is_same(decltype(foo2), void(const volatile char*))); +SA(__is_same(decltype(foo2), void(volatile char*))); +SA(__is_same(decltype(foo2), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo3), void(const volatile char*))); +SA(__is_same(decltype(foo3), void(const volatile char*))); +SA(__is_same(decltype(foo3), void(const volatile char*)))= ; +SA(__is_same(decltype(foo3), void(const volatile ch= ar*))); +#endif + +int main() +{ + foo0(); + foo0(); + foo0(); + foo0(); + + foo1(); + foo1(); + foo1(); + foo1(); + + foo2(); + foo2(); + foo2(); + foo2(); + + foo3(); + foo3(); + foo3(); + foo3(); +} diff --git a/gcc/testsuite/g++.dg/template/array34.C b/gcc/testsuite/g++.dg= /template/array34.C new file mode 100644 index 00000000000..38c06401974 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/array34.C @@ -0,0 +1,63 @@ +// Verify that top-level cv-qualifiers on parameter types are considered +// when determining the function type of an instantiated function template= . +// This resolves a part of Core issues 1001/1322. +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-volatile" } + +template +void foo0(Ts... t); + +template +void foo1(const Ts... t); + +template +void foo2(volatile Ts... t); + +template +void foo3(const volatile Ts... t); + +#if __cplusplus >=3D 201103L +#define SA(X) static_assert(X,#X) +SA(__is_same(decltype(foo0), void(char*))); +SA(__is_same(decltype(foo0), void(const char*))); +SA(__is_same(decltype(foo0), void(volatile char*))); +SA(__is_same(decltype(foo0), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo1), void(const char*))); +SA(__is_same(decltype(foo1), void(const char*))); +SA(__is_same(decltype(foo1), void(const volatile char*)))= ; +SA(__is_same(decltype(foo1), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo2), void(volatile char*))); +SA(__is_same(decltype(foo2), void(const volatile char*))); +SA(__is_same(decltype(foo2), void(volatile char*))); +SA(__is_same(decltype(foo2), void(const volatile ch= ar*))); + +SA(__is_same(decltype(foo3), void(const volatile char*))); +SA(__is_same(decltype(foo3), void(const volatile char*))); +SA(__is_same(decltype(foo3), void(const volatile char*)))= ; +SA(__is_same(decltype(foo3), void(const volatile ch= ar*))); +#endif + +int main() +{ + foo0(0); + foo0(0); + foo0(0); + foo0(0); + + foo1(0); + foo1(0); + foo1(0); + foo1(0); + + foo2(0); + foo2(0); + foo2(0); + foo2(0); + + foo3(0); + foo3(0); + foo3(0); + foo3(0); +} diff --git a/gcc/testsuite/g++.dg/template/defarg22.C b/gcc/testsuite/g++.d= g/template/defarg22.C new file mode 100644 index 00000000000..599061cedb0 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg22.C @@ -0,0 +1,13 @@ +// PR c++/92010 +// { dg-do compile { target c++11 } } + +template +void foo(const T t =3D "; ") +{ +} + +int main() +{ + foo (); +} + --=20 2.26.0.106.g9fadedd637