On Tue, 7 Apr 2020, Jason Merrill wrote: > 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. Concretely, the latent bug is that > > > > > > > > > > > > > given > > > > > > > > > > > > > the > > > > > > > > > > > > > function > > > > > > > > > > > > > template > > > > > > > > > > > > > > > > > > > > > > > > > > template<typename T> void foo(const T t); > > > > > > > > > > > > > > > > > > > > > > > > > > one would expect the type of foo<int[]> 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<int[]> 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. 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. 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. 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. This patch checks this in tsubst_decl <case > > > > > > > > > > > PARM_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. Doing so would > > > > > > > > > certainly > > > > > > > > > catch the original testcase, i.e. > > > > > > > > > > > > > > > > > > template<typename T> > > > > > > > > > void foo(const T); > > > > > > > > > int main() { foo<int[]>(0); } > > > > > > > > > > > > > > > > > > because the DECL_ARGUMENTS of foo<int[]> would be {const int*} > > > > > > > > > and > > > > > > > > > its > > > > > > > > > TYPE_ARG_TYPES would be {int*}. But apparently it doesn't > > > > > > > > > catch > > > > > > > > > the > > > > > > > > > corresponding testcase that uses a function parameter pack, > > > > > > > > > i.e. > > > > > > > > > > > > > > > > > > template<typename... Ts> > > > > > > > > > void foo(const Ts...); > > > > > > > > > int main() { foo<int[]>(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. So in this second > > > > > > > > > testcase > > > > > > > > > both > > > > > > > > > DECL_ARGUMENTS and TYPE_ARG_TYPES of foo<int[]> 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. 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. If we're handling pack > > > > > > > > expansions > > > > > > > > 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 > > > > > > > in > > > > > > > function parameter types. Take g++.dg/cpp2a/lambda-uneval3.C for > > > > > > > example: > > > > > > > > > > > > > > template <class T> void spam(decltype([]{}) > > > > > > > (*s)[sizeof(T)]) {} > > > > > > > int main() { spam<char>(nullptr); } > > > > > > > > > > > > > > According to tsubst_function_decl in current trunk, the type of > > > > > > > the > > > > > > > function paremeter 's' of spam<char> according to its > > > > > > > TYPE_ARG_TYPES > > > > > > > is > > > > > > > struct ._anon_4[1] * > > > > > > > and according to its DECL_ARGUMENTS the type of 's' is > > > > > > > struct ._anon_5[1] * > > > > > > > > > > > > > > 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 substituting > > > > > > > into > > > > > > > the DECL_ARGUMENTS. 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 > > > > formal > > > > parameter types [PR92010] > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > Core issues 1001 and 1322 > > > > PR c++/92010 > > > > * pt.c (maybe_rebuild_function_type): New function. > > > > (tsubst_function_decl): Use it. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > Core issues 1001 and 1322 > > > > PR c++/92010 > > > > * g++.dg/cpp2a/lambda-uneval11.c: New test. > > > > * g++.dg/template/array33.C: New test. > > > > * g++.dg/template/array34.C: New test. > > > > * 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 > > > > rebuild > > > > + 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 = false; > > > > + if (tree parm_list = FUNCTION_FIRST_USER_PARM (decl)) > > > > + { > > > > + tree parm_type_list = FUNCTION_FIRST_USER_PARMTYPE (decl); > > > > + while (parm_type_list && parm_type_list != void_list_node) > > > > + { > > > > + tree parm_type = TREE_VALUE (parm_type_list); > > > > + tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE > > > > (parm_list)); > > > > + if (!same_type_p (parm_type, formal_parm_type_unqual)) > > > > + { > > > > + function_type_needs_rebuilding = true; > > > > + break; > > > > + } > > > > + > > > > + parm_list = DECL_CHAIN (parm_list); > > > > + parm_type_list = TREE_CHAIN (parm_type_list); > > > > + } > > > > + } > > > > + > > > > + if (!function_type_needs_rebuilding) > > > > + return; > > > > + > > > > + const tree new_arg_types = copy_list (TYPE_ARG_TYPES (TREE_TYPE > > > > (decl))); > > > > + > > > > + tree parm_list = FUNCTION_FIRST_USER_PARM (decl); > > > > + tree old_parm_type_list = FUNCTION_FIRST_USER_PARMTYPE (decl); > > > > + tree new_parm_type_list = skip_artificial_parms_for (decl, > > > > new_arg_types); > > > > + while (old_parm_type_list && old_parm_type_list != void_list_node) > > > > + { > > > > + tree *new_parm_type = &TREE_VALUE (new_parm_type_list); > > > > + tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE > > > > (parm_list)); > > > > + if (!same_type_p (*new_parm_type, formal_parm_type_unqual)) > > > > + *new_parm_type = formal_parm_type_unqual; > > > > + > > > > + if (TREE_CHAIN (old_parm_type_list) == void_list_node) > > > > + TREE_CHAIN (new_parm_type_list) = void_list_node; > > > > + parm_list = DECL_CHAIN (parm_list); > > > > + old_parm_type_list = TREE_CHAIN (old_parm_type_list); > > > > + new_parm_type_list = 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 = NULL_TREE; > > > > tree *q = &list; > > > > for (int i = 0; i < len; ++i) > > > > { > > > > tree elt = TREE_VEC_ELT (pack, i); > > > > *q = build_tree_list (purp, elt); > > > > q = &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] > > OK, thanks. Note that we're trying to keep the length of the git subject line > (not the email subject line that adds [PATCH] and such) under 50 chars for the > sake of things like git log --oneline. Going over isn't a terrible thing, but > please keep that in mind.
Ah okay, noted. To that end, I committed the patch with the subject line changed to the shorter c++: Function type and parameter type disagreements [PR92010] > > > gcc/cp/ChangeLog: > > > > Core issues 1001 and 1322 > > PR c++/92010 > > * pt.c (rebuild_function_or_method_type): Split function out from ... > > (tsubst_function_type): ... here. > > (maybe_rebuild_function_type): New function. > > (tsubst_function_decl): Use it. > > > > gcc/testsuite/ChangeLog: > > > > Core issues 1001 and 1322 > > PR c++/92010 > > * g++.dg/cpp2a/lambda-uneval11.c: New test. > > * g++.dg/template/array33.C: New test. > > * g++.dg/template/array34.C: New test. > > * 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); > > } > > +/* Given T, a FUNCTION_TYPE or METHOD_TYPE, construct and return a > > corresponding > > + 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, > > + tree raises, tsubst_flags_t complain) > > +{ > > + gcc_assert (FUNC_OR_METHOD_TYPE_P (t)); > > + > > + tree new_type; > > + if (TREE_CODE (t) == FUNCTION_TYPE) > > + { > > + new_type = build_function_type (return_type, arg_types); > > + new_type = apply_memfn_quals (new_type, type_memfn_quals (t)); > > + } > > + else > > + { > > + tree r = TREE_TYPE (TREE_VALUE (arg_types)); > > + /* Don't pick up extra function qualifiers from the basetype. */ > > + r = cp_build_qualified_type_real (r, type_memfn_quals (t), complain); > > + if (! MAYBE_CLASS_TYPE_P (r)) > > + { > > + /* [temp.deduct] > > + > > + Type deduction may fail for any of the following > > + reasons: > > + > > + -- Attempting to create "pointer to member of T" when T > > + is not a class type. */ > > + if (complain & tf_error) > > + error ("creating pointer to member function of non-class type > > %qT", > > + r); > > + return error_mark_node; > > + } > > + > > + new_type = build_method_type_directly (r, return_type, > > + TREE_CHAIN (arg_types)); > > + } > > + new_type = cp_build_type_attribute_variant (new_type, TYPE_ATTRIBUTES > > (t)); > > + > > + cp_ref_qualifier rqual = type_memfn_rqual (t); > > + bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t); > > + return build_cp_fntype_variant (new_type, rqual, raises, > > late_return_type_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 rebuild > > + 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 = false; > > + if (tree parm_list = FUNCTION_FIRST_USER_PARM (decl)) > > + { > > + tree parm_type_list = FUNCTION_FIRST_USER_PARMTYPE (decl); > > + while (parm_type_list && parm_type_list != void_list_node) > > + { > > + tree parm_type = TREE_VALUE (parm_type_list); > > + tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE > > (parm_list)); > > + if (!same_type_p (parm_type, formal_parm_type_unqual)) > > + { > > + function_type_needs_rebuilding = true; > > + break; > > + } > > + > > + parm_list = DECL_CHAIN (parm_list); > > + parm_type_list = TREE_CHAIN (parm_type_list); > > + } > > + } > > + > > + if (!function_type_needs_rebuilding) > > + return; > > + > > + const tree fntype = TREE_TYPE (decl); > > + tree parm_list = DECL_ARGUMENTS (decl); > > + tree old_parm_type_list = TYPE_ARG_TYPES (fntype); > > + tree new_parm_type_list = NULL_TREE; > > + tree *q = &new_parm_type_list; > > + for (int skip = num_artificial_parms_for (decl); skip > 0; skip--) > > + { > > + *q = copy_node (old_parm_type_list); > > + parm_list = DECL_CHAIN (parm_list); > > + old_parm_type_list = TREE_CHAIN (old_parm_type_list); > > + q = &TREE_CHAIN (*q); > > + } > > + while (old_parm_type_list && old_parm_type_list != void_list_node) > > + { > > + *q = copy_node (old_parm_type_list); > > + tree *new_parm_type = &TREE_VALUE (*q); > > + tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE > > (parm_list)); > > + if (!same_type_p (*new_parm_type, formal_parm_type_unqual)) > > + *new_parm_type = formal_parm_type_unqual; > > + > > + parm_list = DECL_CHAIN (parm_list); > > + old_parm_type_list = TREE_CHAIN (old_parm_type_list); > > + q = &TREE_CHAIN (*q); > > + } > > + if (old_parm_type_list == void_list_node) > > + *q = void_list_node; > > + > > + TREE_TYPE (decl) > > + = rebuild_function_or_method_type (fntype, > > + TREE_TYPE (fntype), new_parm_type_list, > > + TYPE_RAISES_EXCEPTIONS (fntype), > > tf_none); > > +} > > + > > /* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL. */ > > static tree > > @@ -13665,6 +13775,8 @@ tsubst_function_decl (tree t, tree args, > > tsubst_flags_t complain, > > DECL_ARGUMENTS (r) = parms; > > DECL_RESULT (r) = NULL_TREE; > > + maybe_rebuild_function_decl_type (r); > > + > > TREE_STATIC (r) = 0; > > TREE_PUBLIC (r) = TREE_PUBLIC (t); > > DECL_EXTERNAL (r) = 1; > > @@ -14694,7 +14806,6 @@ tsubst_function_type (tree t, > > { > > tree return_type; > > tree arg_types = NULL_TREE; > > - tree fntype; > > /* The TYPE_CONTEXT is not used for function/method types. */ > > gcc_assert (TYPE_CONTEXT (t) == NULL_TREE); > > @@ -14765,42 +14876,8 @@ tsubst_function_type (tree t, > > } > > /* Construct a new type node and return it. */ > > - if (TREE_CODE (t) == FUNCTION_TYPE) > > - { > > - fntype = build_function_type (return_type, arg_types); > > - fntype = apply_memfn_quals (fntype, type_memfn_quals (t)); > > - } > > - else > > - { > > - tree r = TREE_TYPE (TREE_VALUE (arg_types)); > > - /* Don't pick up extra function qualifiers from the basetype. */ > > - r = cp_build_qualified_type_real (r, type_memfn_quals (t), complain); > > - if (! MAYBE_CLASS_TYPE_P (r)) > > - { > > - /* [temp.deduct] > > - > > - Type deduction may fail for any of the following > > - reasons: > > - > > - -- Attempting to create "pointer to member of T" when T > > - is not a class type. */ > > - if (complain & tf_error) > > - error ("creating pointer to member function of non-class type > > %qT", > > - r); > > - return error_mark_node; > > - } > > - > > - fntype = build_method_type_directly (r, return_type, > > - TREE_CHAIN (arg_types)); > > - } > > - fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t)); > > - > > - /* See comment above. */ > > - tree raises = NULL_TREE; > > - cp_ref_qualifier rqual = type_memfn_rqual (t); > > - fntype = build_cp_fntype_variant (fntype, rqual, raises, > > late_return_type_p); > > - > > - return fntype; > > + return rebuild_function_or_method_type (t, return_type, arg_types, > > + /*raises=*/NULL_TREE, complain); > > } > > /* 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 <class T> void spam(decltype([]{}) (*s)[sizeof(T)] = nullptr) > > +{ } > > + > > +void foo() > > +{ > > + spam<int>(); > > +} > > 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<typename T> > > +void foo0(T t = 0); > > + > > +template<typename T> > > +void foo1(const T = 0); > > + > > +template<typename T> > > +void foo2(volatile T t = 0); > > + > > +template<typename T> > > +void foo3(const volatile T t = 0); > > + > > +#if __cplusplus >= 201103L > > +#define SA(X) static_assert(X,#X) > > +SA(__is_same(decltype(foo0<char[]>), void(char*))); > > +SA(__is_same(decltype(foo0<const char[]>), void(const char*))); > > +SA(__is_same(decltype(foo0<volatile char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo0<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo1<char[]>), void(const char*))); > > +SA(__is_same(decltype(foo1<const char[]>), void(const char*))); > > +SA(__is_same(decltype(foo1<volatile char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo1<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo2<char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo2<const char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo2<volatile char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo2<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo3<char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<const char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<volatile char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<const volatile char[]>), void(const volatile > > char*))); > > +#endif > > + > > +int main() > > +{ > > + foo0<char[]>(); > > + foo0<const char[]>(); > > + foo0<volatile char[]>(); > > + foo0<const volatile char[]>(); > > + > > + foo1<char[]>(); > > + foo1<const char[]>(); > > + foo1<volatile char[]>(); > > + foo1<const volatile char[]>(); > > + > > + foo2<char[]>(); > > + foo2<const char[]>(); > > + foo2<volatile char[]>(); > > + foo2<const volatile char[]>(); > > + > > + foo3<char[]>(); > > + foo3<const char[]>(); > > + foo3<volatile char[]>(); > > + foo3<const volatile char[]>(); > > +} > > 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<typename... Ts> > > +void foo0(Ts... t); > > + > > +template<typename... Ts> > > +void foo1(const Ts... t); > > + > > +template<typename... Ts> > > +void foo2(volatile Ts... t); > > + > > +template<typename... Ts> > > +void foo3(const volatile Ts... t); > > + > > +#if __cplusplus >= 201103L > > +#define SA(X) static_assert(X,#X) > > +SA(__is_same(decltype(foo0<char[]>), void(char*))); > > +SA(__is_same(decltype(foo0<const char[]>), void(const char*))); > > +SA(__is_same(decltype(foo0<volatile char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo0<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo1<char[]>), void(const char*))); > > +SA(__is_same(decltype(foo1<const char[]>), void(const char*))); > > +SA(__is_same(decltype(foo1<volatile char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo1<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo2<char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo2<const char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo2<volatile char[]>), void(volatile char*))); > > +SA(__is_same(decltype(foo2<const volatile char[]>), void(const volatile > > char*))); > > + > > +SA(__is_same(decltype(foo3<char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<const char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<volatile char[]>), void(const volatile char*))); > > +SA(__is_same(decltype(foo3<const volatile char[]>), void(const volatile > > char*))); > > +#endif > > + > > +int main() > > +{ > > + foo0<char[]>(0); > > + foo0<const char[]>(0); > > + foo0<volatile char[]>(0); > > + foo0<const volatile char[]>(0); > > + > > + foo1<char[]>(0); > > + foo1<const char[]>(0); > > + foo1<volatile char[]>(0); > > + foo1<const volatile char[]>(0); > > + > > + foo2<char[]>(0); > > + foo2<const char[]>(0); > > + foo2<volatile char[]>(0); > > + foo2<const volatile char[]>(0); > > + > > + foo3<char[]>(0); > > + foo3<const char[]>(0); > > + foo3<volatile char[]>(0); > > + foo3<const volatile char[]>(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 <typename T = char[3]> > > +void foo(const T t = "; ") > > +{ > > +} > > + > > +int main() > > +{ > > + foo (); > > +} > > + > > > >