On Tue, 7 Apr 2020, 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.
Never mind about the above alternative suggestion, it wouldn't work for parameter types that involve lambdas in unevaluated contexts since we would still end up substituting into the lambda expression twice, and would still end up with TYPE_ARG_TYPES disagreeing with the DECL_ARGUMENTS. > > Patch partially tested on unbootstrapped x86_64-pc-linux-gnu, and > bootstrap/regtest is in progress. Bootstrap and regtest finished on x86_64-pc-linux-gnu with no new regressions. > > -- >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 (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 (); > +} > + > -- > 2.26.0.106.g9fadedd637 >