[PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

Patrick Palka ppalka@redhat.com
Tue Apr 7 17:40:22 GMT 2020


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]

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


More information about the Gcc-patches mailing list