From: Patrick Palka <ppalka@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: Patrick Palka <ppalka@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]
Date: Wed, 8 Apr 2020 10:18:00 -0400 (EDT) [thread overview]
Message-ID: <alpine.DEB.2.22.413.2004080932040.3094475@idea> (raw)
In-Reply-To: <8bb9dc4b-76ab-fe33-1d97-e653bb43c903@redhat.com>
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 ();
> > +}
> > +
> >
>
>
prev parent reply other threads:[~2020-04-08 14:42 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-23 1:21 Patrick Palka
2020-03-23 3:11 ` Patrick Palka
2020-03-26 19:29 ` Jason Merrill
2020-03-30 19:58 ` Patrick Palka
2020-03-30 20:15 ` Patrick Palka
2020-03-30 20:42 ` Jason Merrill
2020-03-30 22:46 ` Patrick Palka
2020-03-31 17:13 ` Jason Merrill
2020-03-31 19:50 ` Patrick Palka
2020-04-01 22:29 ` Jason Merrill
2020-04-01 22:37 ` Jason Merrill
2020-04-06 15:45 ` Patrick Palka
2020-04-06 21:33 ` Jason Merrill
2020-04-07 17:40 ` Patrick Palka
2020-04-07 20:26 ` Patrick Palka
2020-04-07 21:21 ` Jason Merrill
2020-04-08 14:18 ` Patrick Palka [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.DEB.2.22.413.2004080932040.3094475@idea \
--to=ppalka@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jason@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).