From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) by sourceware.org (Postfix) with ESMTP id A7258385DC3E for ; Tue, 7 Apr 2020 21:23:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A7258385DC3E Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-373-DsM61K0SNqyrwBagfvmezg-1; Tue, 07 Apr 2020 17:22:00 -0400 X-MC-Unique: DsM61K0SNqyrwBagfvmezg-1 Received: by mail-qt1-f198.google.com with SMTP id d18so4382695qtq.16 for ; Tue, 07 Apr 2020 14:22:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=bQK/82pJ6ZT2QKz0OwxHE6tn0DfFH1VECNE2KaYgyaU=; b=DCmSK4FnAcZ3bZBhEct7/O2J/BaZ4JOqO8EUZ9Oxt1MXUK8BxGbvaOD4Fo5zcxV90p lVQEh2wQN11XdwnN067WXpKd6CSTPB5E4X7UnU6LZZtKkStcSw7zvvE4CzBfdLYjVZi5 ug+WiAN5CqiIB8Etd8ik/So6s+/dqF8F+JFAZWs9iPmNGlbBfTBbGy9JwIkqnvNLkHBS rCPGTw7hD0FdHNfprXyfa26PjlGDdRoSHroz37eu2zl8yFH0qrL/ElrQfuaxP2pJsz9x v0MLxd5AhvdLIDpVZG3zRNpS6x4c4qnUyevgxoJBlvSRnVCHnJ7WTJODAVu2gJ81i6SB oARA== X-Gm-Message-State: AGi0PuZzFyJ4vTXhVeIvaI4F/W0SGIvKztIgfuzsTq8kIvVwrkel+i1x OvY1DDPixGXeNCEjKu2y9RdCeF8JR94kvs+57wL2SRVGldgdVBALvofzIMwtfMCgh0SXO4RZkgN qMHX3VDIqgFvWhiZs0w== X-Received: by 2002:a37:4dc8:: with SMTP id a191mr4567845qkb.450.1586294519591; Tue, 07 Apr 2020 14:21:59 -0700 (PDT) X-Google-Smtp-Source: APiQypJ7LFXXkNevGqByZe4yjy+2+haHZoBUUhG0KJnpnPVOSb906sYOlM5nVT0XCi4LiNoZgJIjDQ== X-Received: by 2002:a37:4dc8:: with SMTP id a191mr4567782qkb.450.1586294518710; Tue, 07 Apr 2020 14:21:58 -0700 (PDT) Received: from [192.168.2.148] (209-6-216-142.s141.c3-0.smr-cbr1.sbo-smr.ma.cable.rcncustomer.com. [209.6.216.142]) by smtp.gmail.com with ESMTPSA id e17sm16447347qtw.1.2020.04.07.14.21.57 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 07 Apr 2020 14:21:58 -0700 (PDT) Subject: Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010] To: Patrick Palka Cc: gcc-patches@gcc.gnu.org References: <20200323012105.3692086-1-ppalka@redhat.com> <0c702b38-1fca-d0ac-c1ee-f7e080d9367c@redhat.com> <6716ec8e-7c6d-04b0-a545-b0b0e8248669@redhat.com> From: Jason Merrill Message-ID: <8bb9dc4b-76ab-fe33-1d97-e653bb43c903@redhat.com> Date: Tue, 7 Apr 2020 17:21:57 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.3.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-27.9 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 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 21:23:54 -0000 On 4/7/20 1:40 PM, Patrick Palka wrote: > 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: >>> >>>> 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: >>>>>> >>>>>>> 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: >>>>>>>>>> >>>>>>>>>>> On 3/22/20 9:21 PM, Patrick Palka wrote: >>>>>>>>>>>> This patch relaxes an assertion in tsubst_default_argument >>>>>>>>>>>> that >>>>>>>>>>>> exposes >>>>>>>>>>>> a >>>>>>>>>>>> latent >>>>>>>>>>>> bug in how we substitute an array type into a cv-qualified >>>>>>>>>>>> wildcard >>>>>>>>>>>> function >>>>>>>>>>>> parameter type.=C2=A0 Concretely, the latent bug is that given >>>>>>>>>>>> the >>>>>>>>>>>> function >>>>>>>>>>>> template >>>>>>>>>>>> >>>>>>>>>>>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 template void foo= (const T t); >>>>>>>>>>>> >>>>>>>>>>>> one would expect the type of foo to be void(const >>>>>>>>>>>> int*), but >>>>>>>>>>>> we >>>>>>>>>>>> (seemingly prematurely) strip function parameter types of >>>>>>>>>>>> their >>>>>>>>>>>> top-level >>>>>>>>>>>> cv-qualifiers when building the function's TYPE_ARG_TYPES, >>>>>>>>>>>> and >>>>>>>>>>>> instead >>>>>>>>>>>> end >>>>>>>>>>>> up >>>>>>>>>>>> obtaining void(int*) as the type of foo after >>>>>>>>>>>> substitution >>>>>>>>>>>> and >>>>>>>>>>>> decaying. >>>>>>>>>>>> >>>>>>>>>>>> We still however correctly substitute into and decay the >>>>>>>>>>>> formal >>>>>>>>>>>> parameter >>>>>>>>>>>> type, >>>>>>>>>>>> obtaining const int* as the type of t after substitution. >>>>>>>>>>>> But >>>>>>>>>>>> this >>>>>>>>>>>> then >>>>>>>>>>>> leads >>>>>>>>>>>> to us tripping over the assert in tsubst_default_argument >>>>>>>>>>>> that >>>>>>>>>>>> verifies >>>>>>>>>>>> the >>>>>>>>>>>> formal parameter type and the function type are >>>>>>>>>>>> consistent. >>>>>>>>>>>> >>>>>>>>>>>> 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? >>>>>>>>>>> >>>>>>>>>>> This is core issues 1001/1322, which have not been resolved. >>>>>>>>>>> Clang >>>>>>>>>>> does >>>>>>>>>>> the >>>>>>>>>>> substitution the way you suggest; EDG rejects the testcase >>>>>>>>>>> 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. >>>>>>>>>> >>>>>>>>>> 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 (fatal) >>>>>>>>>> diagnostic >>>>>>>>>> if so.=C2=A0 This patch checks this in tsubst_decl >>>>>>>>>> rather >>>>>>>>>> than in tsubst_function_decl for efficiency reasons, so that >>>>>>>>>> we >>>>>>>>>> don't >>>>>>>>>> have to perform another traversal over the DECL_ARGUMENTS / >>>>>>>>>> TYPE_ARG_TYPES just to implement this check. >>>>>>>>> >>>>>>>>> Hmm, this seems like writing more complicated code for a very >>>>>>>>> marginal >>>>>>>>> optimization; how many function templates have so many >>>>>>>>> parameters >>>>>>>>> that >>>>>>>>> walking >>>>>>>>> over them once to compare types will have any effect on compile >>>>>>>>> time? >>>>>>>> >>>>>>>> Good point... though I just tried implementing this check in >>>>>>>> tsubst_function_decl, and it seems it might be just as complicated >>>>>>>> to >>>>>>>> implement it there instead, at least if we want to handle function >>>>>>>> parameter packs correctly. >>>>>>>> >>>>>>>> If we were to implement this check in tsubst_function_decl, then >>>>>>>> since >>>>>>>> we have access to the instantiated function, it would presumably >>>>>>>> suffice >>>>>>>> to compare its substituted DECL_ARGUMENTS with its substituted >>>>>>>> TYPE_ARG_TYPES to see if they're consistent.=C2=A0 Doing so would >>>>>>>> certainly >>>>>>>> catch the original testcase, i.e. >>>>>>>> >>>>>>>> =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); } >>>>>>>> >>>>>>>> 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 ca= tch >>>>>>>> the >>>>>>>> corresponding testcase that uses a function parameter pack, i.e. >>>>>>>> >>>>>>>> =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); } >>>>>>>> >>>>>>>> because it turns out we don't strip top-level cv-qualifiers from >>>>>>>> function parameter packs from TYPE_ARG_TYPES at declaration time, >>>>>>>> as >>>>>>>> we >>>>>>>> do with regular function parameters.=C2=A0 So in this second testc= ase >>>>>>>> both >>>>>>>> DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const >>>>>>>> int*}, >>>>>>>> and yet we would (presumably) want to reject this instantiation >>>>>>>> too. >>>>>>>> >>>>>>>> So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from >>>>>>>> tsubst_function_decl would not suffice, and we would still need to >>>>>>>> do >>>>>>>> a >>>>>>>> variant of the trick that's done in this patch, i.e. substitute >>>>>>>> into >>>>>>>> each dependent parameter type stripped of its top-level >>>>>>>> cv-qualifiers, >>>>>>>> to see if these cv-qualifiers make a material difference in the >>>>>>>> resulting function type.=C2=A0 Or maybe there's yet another way to >>>>>>>> detect >>>>>>>> this? >>>>>>> >>>>>>> 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 expa= nsions >>>>>>> wrong, >>>>>>> that's a separate issue. >>>>>> >>>>>> Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility >>>>>> seems >>>>>> to be exposing a latent bug with how we handle lambdas that appear i= n >>>>>> function parameter types.=C2=A0 Take g++.dg/cpp2a/lambda-uneval3.C f= or >>>>>> example: >>>>>> >>>>>> =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); } >>>>>> >>>>>> According to tsubst_function_decl in current trunk, the type of the >>>>>> function paremeter 's' of spam according to its TYPE_ARG_TYPES >>>>>> 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] * >>>>>> >>>>>> The disagreement happens because we call tsubst_lambda_expr twice >>>>>> during >>>>>> substitution and thereby generate two distinct lambda types, one whe= n >>>>>> substituting into the TYPE_ARG_TYPES and another when substituting >>>>>> into >>>>>> the DECL_ARGUMENTS.=C2=A0 I'm not sure how to work around this >>>>>> bug/false-positive.. >>>>> >>>>> Oof. >>>>> >>>>> I think probably the right answer is to rebuild TYPE_ARG_TYPES from >>>>> DECL_ARGUMENTS if they don't match. >>>> >>>> ...and treat that as a resolution of 1001/1322, so not giving an error= . >>> >>> Is something like this what you have in mind? Bootstrap and testing in >>> progress. >> >> Yes, thanks. >> >>> -- >8 -- >>> >>> Subject: [PATCH] c++: Rebuild function type when it disagrees with form= al >>> parameter types [PR92010] >>> >>> gcc/cp/ChangeLog: >>> >>> =09Core issues 1001 and 1322 >>> =09PR c++/92010 >>> =09* pt.c (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 | 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 >>> >>> 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); >>> + } >> >> The usual pattern for this sort of thing is to use a tree* to track the = end of >> the new list, which should also avoid making a garbage copy of void_list= _node. >> e.g. from tsubst_attribute: >> >>> 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); >>> } >=20 > Ah so that's the right way do it :) Patch updated to make use of this > pattern. >=20 > 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. >=20 > 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). >=20 > 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. >=20 > Patch partially tested on unbootstrapped x86_64-pc-linux-gnu, and > bootstrap/regtest is in progress. >=20 > -- >8 -- >=20 > Subject: [PATCH] c++: Rebuild function type when it disagrees with formal > parameter types [PR92010] OK, thanks. Note that we're trying to keep the length of the git=20 subject line (not the email subject line that adds [PATCH] and such)=20 under 50 chars for the sake of things like git log --oneline. Going=20 over isn't a terrible thing, but please keep that in mind. > gcc/cp/ChangeLog: >=20 > =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. >=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 | 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 >=20 > 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 corre= sponding > + FUNCTION_TYPE or METHOD_TYPE whose return type is RETURN_TYPE, argume= nt types > + are ARG_TYPES, and exception specification is RAISES, and otherwise i= s > + identical to T. */ > + > +static tree > +rebuild_function_or_method_type (tree t, tree return_type, tree arg_type= s, > +=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), compl= ain); > + 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_ATTRIBUTE= S (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_t= ype_p); > +} > + > +/* 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 rebui= ld > + DECL's function type according to its formal parameter types, as part= 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_l= ist)); > +=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_= list)); > + 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_f= lags_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), compl= ain); > - 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= _type_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 templa= te. > +// 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 = char*))); > + > +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 = char*))); > + > +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 = 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 char*)= )); > +SA(__is_same(decltype(foo3), void(const volatile = char*))); > +#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 templa= te. > +// 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 = char*))); > + > +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 = char*))); > + > +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 = 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 char*)= )); > +SA(__is_same(decltype(foo3), void(const volatile = char*))); > +#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++= .dg/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