c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547]

Message ID 20211001134643.1941700-1-ppalka@redhat.com
State New
Headers
Series c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547] |

Commit Message

Patrick Palka Oct. 1, 2021, 1:46 p.m. UTC
  Here during partial ordering of the two partial specializations we end
up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
thereafter because uses_template_parms calls potential_constant_expression
which doesn't handle NONTYPE_ARGUMENT_PACK.

This patch fixes this by checking dependent_template_arg_p instead of
uses_template_parms when parm==arg, which does handle NONTYPE_ARGUMENT_PACK.
We could also perhaps fix uses_template_parms / inst_dep_expr_p to better
handle NONTYPE_ARGUMENT_PACK, but interestingly none of our existing tests
exercise calling those functions on NONTYPE_ARGUMENT_PACK, so such a fix
would be seemingly moot.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/11?

	PR c++/102547

gcc/cp/ChangeLog:

	* pt.c (unify): Check dependent_template_arg_p instead of
	uses_template_parms when parm==arg.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/variadic-partial2.C: New test.
---
 gcc/cp/pt.c                                   |  2 +-
 .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
 .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
  

Comments

Jason Merrill Oct. 1, 2021, 1:57 p.m. UTC | #1
On 10/1/21 09:46, Patrick Palka wrote:
> Here during partial ordering of the two partial specializations we end
> up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
> thereafter because uses_template_parms calls potential_constant_expression
> which doesn't handle NONTYPE_ARGUMENT_PACK.
> 
> This patch fixes this by checking dependent_template_arg_p instead of
> uses_template_parms when parm==arg, which does handle NONTYPE_ARGUMENT_PACK.
> We could also perhaps fix uses_template_parms / inst_dep_expr_p to better
> handle NONTYPE_ARGUMENT_PACK,

Please.

> but interestingly none of our existing tests
> exercise calling those functions on NONTYPE_ARGUMENT_PACK, so such a fix
> would be seemingly moot.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?
> 
> 	PR c++/102547
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.c (unify): Check dependent_template_arg_p instead of
> 	uses_template_parms when parm==arg.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/variadic-partial2.C: New test.
> ---
>   gcc/cp/pt.c                                   |  2 +-
>   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
>   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
>   3 files changed, 39 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 1dcdffe322a..59c00c77a30 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -23587,7 +23587,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>        even if ARG == PARM, since we won't record unifications for the
>        template parameters.  We might need them if we're trying to
>        figure out which of two things is more specialized.  */
> -  if (arg == parm && !uses_template_parms (parm))
> +  if (arg == parm && !dependent_template_arg_p (parm))
>       return unify_success (explain_p);
>   
>     /* Handle init lists early, so the rest of the function can assume
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> new file mode 100644
> index 00000000000..df61f26a3c1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> @@ -0,0 +1,16 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +struct vals_client { };
> +
> +template<int V0, int V1, class T>
> +struct vals_client<vals<V0, V1>, T> { };
> +
> +template<int V0, int V1>
> +struct vals_client<vals<V0, V1>, void> { };
> +
> +template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> new file mode 100644
> index 00000000000..cc0ea488ad3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> @@ -0,0 +1,22 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +// A version of variadic-partial2.C where the partial ordering is performed
> +// on function templates instead of class templates.
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +void f(V, T) { };
> +
> +template<int V0, int V1, class T>
> +void f(vals<V0, V1>, T) { };
> +
> +template<int V0, int V1>
> +void f(vals<V0, V1>, char) { };
> +
> +template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
> +
> +int main() {
> +  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
> +}
>
  
Patrick Palka Oct. 1, 2021, 2:26 p.m. UTC | #2
On Fri, 1 Oct 2021, Jason Merrill wrote:

> On 10/1/21 09:46, Patrick Palka wrote:
> > Here during partial ordering of the two partial specializations we end
> > up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
> > thereafter because uses_template_parms calls potential_constant_expression
> > which doesn't handle NONTYPE_ARGUMENT_PACK.
> > 
> > This patch fixes this by checking dependent_template_arg_p instead of
> > uses_template_parms when parm==arg, which does handle NONTYPE_ARGUMENT_PACK.
> > We could also perhaps fix uses_template_parms / inst_dep_expr_p to better
> > handle NONTYPE_ARGUMENT_PACK,
> 
> Please.

Sounds good, like the following then?  Passes light testing, bootstrap
and regtest on progress.

-- >8 --

	PR c++/102547

gcc/cp/ChangeLog:

	* pt.c (instantiation_dependent_expression_p): Sidestep checking
	potential_constant_expression on NONTYPE_ARGUMENT_PACK.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/variadic-partial2.C: New test.
	* g++.dg/cpp0x/variadic-partial2a.C: New test.
---
 gcc/cp/pt.c                                   |  4 +++-
 .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
 .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1dcdffe322a..643204103c5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree expression)
 {
   return (instantiation_dependent_uneval_expression_p (expression)
 	  || (processing_template_decl
-	      && potential_constant_expression (expression)
+	      && expression != NULL_TREE
+	      && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
+		  || potential_constant_expression (expression))
 	      && value_dependent_expression_p (expression)));
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
new file mode 100644
index 00000000000..df61f26a3c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
@@ -0,0 +1,16 @@
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+struct vals_client { };
+
+template<int V0, int V1, class T>
+struct vals_client<vals<V0, V1>, T> { };
+
+template<int V0, int V1>
+struct vals_client<vals<V0, V1>, void> { };
+
+template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
new file mode 100644
index 00000000000..cc0ea488ad3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
@@ -0,0 +1,22 @@
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+// A version of variadic-partial2.C where the partial ordering is performed
+// on function templates instead of class templates.
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+void f(V, T) { };
+
+template<int V0, int V1, class T>
+void f(vals<V0, V1>, T) { };
+
+template<int V0, int V1>
+void f(vals<V0, V1>, char) { };
+
+template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
+
+int main() {
+  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
+}
  
Jason Merrill Oct. 1, 2021, 3:36 p.m. UTC | #3
On 10/1/21 10:26, Patrick Palka wrote:
> On Fri, 1 Oct 2021, Jason Merrill wrote:
> 
>> On 10/1/21 09:46, Patrick Palka wrote:
>>> Here during partial ordering of the two partial specializations we end
>>> up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
>>> thereafter because uses_template_parms calls potential_constant_expression
>>> which doesn't handle NONTYPE_ARGUMENT_PACK.
>>>
>>> This patch fixes this by checking dependent_template_arg_p instead of
>>> uses_template_parms when parm==arg, which does handle NONTYPE_ARGUMENT_PACK.
>>> We could also perhaps fix uses_template_parms / inst_dep_expr_p to better
>>> handle NONTYPE_ARGUMENT_PACK,
>>
>> Please.
> 
> Sounds good, like the following then?  Passes light testing, bootstrap
> and regtest on progress.
> 
> -- >8 --
> 
> 	PR c++/102547
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.c (instantiation_dependent_expression_p): Sidestep checking
> 	potential_constant_expression on NONTYPE_ARGUMENT_PACK.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/variadic-partial2.C: New test.
> 	* g++.dg/cpp0x/variadic-partial2a.C: New test.
> ---
>   gcc/cp/pt.c                                   |  4 +++-
>   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
>   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
>   3 files changed, 41 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 1dcdffe322a..643204103c5 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree expression)
>   {
>     return (instantiation_dependent_uneval_expression_p (expression)
>   	  || (processing_template_decl
> -	      && potential_constant_expression (expression)
> +	      && expression != NULL_TREE
> +	      && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
> +		  || potential_constant_expression (expression))

I'd prefer to loop over the elements of the pack, either here or 
(probably better) in potential_constant_expression.

>   	      && value_dependent_expression_p (expression)));
>   }
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> new file mode 100644
> index 00000000000..df61f26a3c1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> @@ -0,0 +1,16 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +struct vals_client { };
> +
> +template<int V0, int V1, class T>
> +struct vals_client<vals<V0, V1>, T> { };
> +
> +template<int V0, int V1>
> +struct vals_client<vals<V0, V1>, void> { };
> +
> +template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> new file mode 100644
> index 00000000000..cc0ea488ad3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> @@ -0,0 +1,22 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +// A version of variadic-partial2.C where the partial ordering is performed
> +// on function templates instead of class templates.
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +void f(V, T) { };
> +
> +template<int V0, int V1, class T>
> +void f(vals<V0, V1>, T) { };
> +
> +template<int V0, int V1>
> +void f(vals<V0, V1>, char) { };
> +
> +template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
> +
> +int main() {
> +  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
> +}
>
  
Patrick Palka Oct. 1, 2021, 5:29 p.m. UTC | #4
On Fri, 1 Oct 2021, Jason Merrill wrote:

> On 10/1/21 10:26, Patrick Palka wrote:
> > On Fri, 1 Oct 2021, Jason Merrill wrote:
> > 
> > > On 10/1/21 09:46, Patrick Palka wrote:
> > > > Here during partial ordering of the two partial specializations we end
> > > > up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash
> > > > shortly
> > > > thereafter because uses_template_parms calls
> > > > potential_constant_expression
> > > > which doesn't handle NONTYPE_ARGUMENT_PACK.
> > > > 
> > > > This patch fixes this by checking dependent_template_arg_p instead of
> > > > uses_template_parms when parm==arg, which does handle
> > > > NONTYPE_ARGUMENT_PACK.
> > > > We could also perhaps fix uses_template_parms / inst_dep_expr_p to
> > > > better
> > > > handle NONTYPE_ARGUMENT_PACK,
> > > 
> > > Please.
> > 
> > Sounds good, like the following then?  Passes light testing, bootstrap
> > and regtest on progress.
> > 
> > -- >8 --
> > 
> > 	PR c++/102547
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* pt.c (instantiation_dependent_expression_p): Sidestep checking
> > 	potential_constant_expression on NONTYPE_ARGUMENT_PACK.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/cpp0x/variadic-partial2.C: New test.
> > 	* g++.dg/cpp0x/variadic-partial2a.C: New test.
> > ---
> >   gcc/cp/pt.c                                   |  4 +++-
> >   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
> >   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
> >   3 files changed, 41 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 1dcdffe322a..643204103c5 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree
> > expression)
> >   {
> >     return (instantiation_dependent_uneval_expression_p (expression)
> >   	  || (processing_template_decl
> > -	      && potential_constant_expression (expression)
> > +	      && expression != NULL_TREE
> > +	      && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
> > +		  || potential_constant_expression (expression))
> 
> I'd prefer to loop over the elements of the pack, either here or (probably
> better) in potential_constant_expression.

Ah, makes sense.  Like so?  Bootstrapped and regtested on
x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547]

Here during partial ordering of the two partial specializations we end
up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
thereafter because uses_template_parms(parms) calls potential_const_expr
which doesn't handle NONTYPE_ARGUMENT_PACK.

This patch fixes this by extending potential_constant_expression to handle
NONTYPE_ARGUMENT_PACK appropriately.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/11?

	PR c++/102547

gcc/cp/ChangeLog:

	* constexpr.c (potential_constant_expression_1): Handle
	NONTYPE_ARGUMENT_PACK.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/variadic-partial2.C: New test.
	* g++.dg/cpp0x/variadic-partial2a.C: New test.
---
 gcc/cp/constexpr.c                            | 10 +++++++++
 .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
 .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 18d9d117a48..e95ff00774f 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -9043,6 +9043,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case CO_RETURN_EXPR:
       return false;
 
+    case NONTYPE_ARGUMENT_PACK:
+      {
+	tree args = ARGUMENT_PACK_ARGS (t);
+	int len = TREE_VEC_LENGTH (args);
+	for (int i = 0; i < len; ++i)
+	  if (!RECUR (TREE_VEC_ELT (args, i), any))
+	    return false;
+	return true;
+      }
+
     default:
       if (objc_non_constant_expr_p (t))
 	return false;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
new file mode 100644
index 00000000000..df61f26a3c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
@@ -0,0 +1,16 @@
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+struct vals_client { };
+
+template<int V0, int V1, class T>
+struct vals_client<vals<V0, V1>, T> { };
+
+template<int V0, int V1>
+struct vals_client<vals<V0, V1>, void> { };
+
+template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
new file mode 100644
index 00000000000..e98bdbbc07b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
@@ -0,0 +1,22 @@
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+// A version of variadic-partial2.C where partial ordering is performed
+// on function templates instead of class templates.
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+void f(V, T) { };
+
+template<int V0, int V1, class T>
+void f(vals<V0, V1>, T) { };
+
+template<int V0, int V1>
+void f(vals<V0, V1>, char) { };
+
+template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
+
+int main() {
+  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
+}
  
Patrick Palka Oct. 2, 2021, 12:22 a.m. UTC | #5
On Fri, Oct 1, 2021 at 1:29 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Fri, 1 Oct 2021, Jason Merrill wrote:
>
> > On 10/1/21 10:26, Patrick Palka wrote:
> > > On Fri, 1 Oct 2021, Jason Merrill wrote:
> > >
> > > > On 10/1/21 09:46, Patrick Palka wrote:
> > > > > Here during partial ordering of the two partial specializations we end
> > > > > up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash
> > > > > shortly
> > > > > thereafter because uses_template_parms calls
> > > > > potential_constant_expression
> > > > > which doesn't handle NONTYPE_ARGUMENT_PACK.
> > > > >
> > > > > This patch fixes this by checking dependent_template_arg_p instead of
> > > > > uses_template_parms when parm==arg, which does handle
> > > > > NONTYPE_ARGUMENT_PACK.
> > > > > We could also perhaps fix uses_template_parms / inst_dep_expr_p to
> > > > > better
> > > > > handle NONTYPE_ARGUMENT_PACK,
> > > >
> > > > Please.
> > >
> > > Sounds good, like the following then?  Passes light testing, bootstrap
> > > and regtest on progress.
> > >
> > > -- >8 --
> > >
> > >     PR c++/102547
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >     * pt.c (instantiation_dependent_expression_p): Sidestep checking
> > >     potential_constant_expression on NONTYPE_ARGUMENT_PACK.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >     * g++.dg/cpp0x/variadic-partial2.C: New test.
> > >     * g++.dg/cpp0x/variadic-partial2a.C: New test.
> > > ---
> > >   gcc/cp/pt.c                                   |  4 +++-
> > >   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
> > >   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
> > >   3 files changed, 41 insertions(+), 1 deletion(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> > >
> > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > > index 1dcdffe322a..643204103c5 100644
> > > --- a/gcc/cp/pt.c
> > > +++ b/gcc/cp/pt.c
> > > @@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree
> > > expression)
> > >   {
> > >     return (instantiation_dependent_uneval_expression_p (expression)
> > >       || (processing_template_decl
> > > -         && potential_constant_expression (expression)
> > > +         && expression != NULL_TREE
> > > +         && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
> > > +             || potential_constant_expression (expression))
> >
> > I'd prefer to loop over the elements of the pack, either here or (probably
> > better) in potential_constant_expression.
>
> Ah, makes sense.  Like so?  Bootstrapped and regtested on
> x86_64-pc-linux-gnu.

On second thought given that a NONTYPE_ARGUMENT_PACK is by
construction a sequence of non-type template arguments, is looping
over its elements in potential_const_expr necessary?  Maybe we should
just return true unconditionally.

>
> -- >8 --
>
> Subject: [PATCH] c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547]
>
> Here during partial ordering of the two partial specializations we end
> up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
> thereafter because uses_template_parms(parms) calls potential_const_expr
> which doesn't handle NONTYPE_ARGUMENT_PACK.
>
> This patch fixes this by extending potential_constant_expression to handle
> NONTYPE_ARGUMENT_PACK appropriately.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?
>
>         PR c++/102547
>
> gcc/cp/ChangeLog:
>
>         * constexpr.c (potential_constant_expression_1): Handle
>         NONTYPE_ARGUMENT_PACK.
>
> gcc/testsuite/ChangeLog:
>
>         * g++.dg/cpp0x/variadic-partial2.C: New test.
>         * g++.dg/cpp0x/variadic-partial2a.C: New test.
> ---
>  gcc/cp/constexpr.c                            | 10 +++++++++
>  .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
>  .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
>  3 files changed, 48 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
>
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 18d9d117a48..e95ff00774f 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -9043,6 +9043,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
>      case CO_RETURN_EXPR:
>        return false;
>
> +    case NONTYPE_ARGUMENT_PACK:
> +      {
> +       tree args = ARGUMENT_PACK_ARGS (t);
> +       int len = TREE_VEC_LENGTH (args);
> +       for (int i = 0; i < len; ++i)
> +         if (!RECUR (TREE_VEC_ELT (args, i), any))
> +           return false;
> +       return true;
> +      }
> +
>      default:
>        if (objc_non_constant_expr_p (t))
>         return false;
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> new file mode 100644
> index 00000000000..df61f26a3c1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> @@ -0,0 +1,16 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +struct vals_client { };
> +
> +template<int V0, int V1, class T>
> +struct vals_client<vals<V0, V1>, T> { };
> +
> +template<int V0, int V1>
> +struct vals_client<vals<V0, V1>, void> { };
> +
> +template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> new file mode 100644
> index 00000000000..e98bdbbc07b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> @@ -0,0 +1,22 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +// A version of variadic-partial2.C where partial ordering is performed
> +// on function templates instead of class templates.
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +void f(V, T) { };
> +
> +template<int V0, int V1, class T>
> +void f(vals<V0, V1>, T) { };
> +
> +template<int V0, int V1>
> +void f(vals<V0, V1>, char) { };
> +
> +template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
> +
> +int main() {
> +  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
> +}
> --
> 2.33.0.610.gcefe983a32
>
  
Patrick Palka Oct. 2, 2021, 12:39 a.m. UTC | #6
On Fri, 1 Oct 2021, Patrick Palka wrote:

> On Fri, Oct 1, 2021 at 1:29 PM Patrick Palka <ppalka@redhat.com> wrote:
> >
> > On Fri, 1 Oct 2021, Jason Merrill wrote:
> >
> > > On 10/1/21 10:26, Patrick Palka wrote:
> > > > On Fri, 1 Oct 2021, Jason Merrill wrote:
> > > >
> > > > > On 10/1/21 09:46, Patrick Palka wrote:
> > > > > > Here during partial ordering of the two partial specializations we end
> > > > > > up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash
> > > > > > shortly
> > > > > > thereafter because uses_template_parms calls
> > > > > > potential_constant_expression
> > > > > > which doesn't handle NONTYPE_ARGUMENT_PACK.
> > > > > >
> > > > > > This patch fixes this by checking dependent_template_arg_p instead of
> > > > > > uses_template_parms when parm==arg, which does handle
> > > > > > NONTYPE_ARGUMENT_PACK.
> > > > > > We could also perhaps fix uses_template_parms / inst_dep_expr_p to
> > > > > > better
> > > > > > handle NONTYPE_ARGUMENT_PACK,
> > > > >
> > > > > Please.
> > > >
> > > > Sounds good, like the following then?  Passes light testing, bootstrap
> > > > and regtest on progress.
> > > >
> > > > -- >8 --
> > > >
> > > >     PR c++/102547
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >     * pt.c (instantiation_dependent_expression_p): Sidestep checking
> > > >     potential_constant_expression on NONTYPE_ARGUMENT_PACK.
> > > >
> > > > gcc/testsuite/ChangeLog:
> > > >
> > > >     * g++.dg/cpp0x/variadic-partial2.C: New test.
> > > >     * g++.dg/cpp0x/variadic-partial2a.C: New test.
> > > > ---
> > > >   gcc/cp/pt.c                                   |  4 +++-
> > > >   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
> > > >   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
> > > >   3 files changed, 41 insertions(+), 1 deletion(-)
> > > >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> > > >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> > > >
> > > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > > > index 1dcdffe322a..643204103c5 100644
> > > > --- a/gcc/cp/pt.c
> > > > +++ b/gcc/cp/pt.c
> > > > @@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree
> > > > expression)
> > > >   {
> > > >     return (instantiation_dependent_uneval_expression_p (expression)
> > > >       || (processing_template_decl
> > > > -         && potential_constant_expression (expression)
> > > > +         && expression != NULL_TREE
> > > > +         && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
> > > > +             || potential_constant_expression (expression))
> > >
> > > I'd prefer to loop over the elements of the pack, either here or (probably
> > > better) in potential_constant_expression.
> >
> > Ah, makes sense.  Like so?  Bootstrapped and regtested on
> > x86_64-pc-linux-gnu.
> 
> On second thought given that a NONTYPE_ARGUMENT_PACK is by
> construction a sequence of non-type template arguments, is looping
> over its elements in potential_const_expr necessary?  Maybe we should
> just return true unconditionally.

Never mind, I forgot that we also use NONTYPE_ARGUMENT_PACK to pack
function arguments, so we can't just assume the elements are always
constant.

> 
> >
> > -- >8 --
> >
> > Subject: [PATCH] c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547]
> >
> > Here during partial ordering of the two partial specializations we end
> > up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
> > thereafter because uses_template_parms(parms) calls potential_const_expr
> > which doesn't handle NONTYPE_ARGUMENT_PACK.
> >
> > This patch fixes this by extending potential_constant_expression to handle
> > NONTYPE_ARGUMENT_PACK appropriately.
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/11?
> >
> >         PR c++/102547
> >
> > gcc/cp/ChangeLog:
> >
> >         * constexpr.c (potential_constant_expression_1): Handle
> >         NONTYPE_ARGUMENT_PACK.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * g++.dg/cpp0x/variadic-partial2.C: New test.
> >         * g++.dg/cpp0x/variadic-partial2a.C: New test.
> > ---
> >  gcc/cp/constexpr.c                            | 10 +++++++++
> >  .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
> >  .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
> >  3 files changed, 48 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> >
> > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> > index 18d9d117a48..e95ff00774f 100644
> > --- a/gcc/cp/constexpr.c
> > +++ b/gcc/cp/constexpr.c
> > @@ -9043,6 +9043,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
> >      case CO_RETURN_EXPR:
> >        return false;
> >
> > +    case NONTYPE_ARGUMENT_PACK:
> > +      {
> > +       tree args = ARGUMENT_PACK_ARGS (t);
> > +       int len = TREE_VEC_LENGTH (args);
> > +       for (int i = 0; i < len; ++i)
> > +         if (!RECUR (TREE_VEC_ELT (args, i), any))
> > +           return false;
> > +       return true;
> > +      }
> > +
> >      default:
> >        if (objc_non_constant_expr_p (t))
> >         return false;
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> > new file mode 100644
> > index 00000000000..df61f26a3c1
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> > @@ -0,0 +1,16 @@
> > +// PR c++/102547
> > +// { dg-do compile { target c++11 } }
> > +
> > +template<int... Vs>
> > +struct vals { };
> > +
> > +template<class V, class T>
> > +struct vals_client { };
> > +
> > +template<int V0, int V1, class T>
> > +struct vals_client<vals<V0, V1>, T> { };
> > +
> > +template<int V0, int V1>
> > +struct vals_client<vals<V0, V1>, void> { };
> > +
> > +template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> > new file mode 100644
> > index 00000000000..e98bdbbc07b
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> > @@ -0,0 +1,22 @@
> > +// PR c++/102547
> > +// { dg-do compile { target c++11 } }
> > +// A version of variadic-partial2.C where partial ordering is performed
> > +// on function templates instead of class templates.
> > +
> > +template<int... Vs>
> > +struct vals { };
> > +
> > +template<class V, class T>
> > +void f(V, T) { };
> > +
> > +template<int V0, int V1, class T>
> > +void f(vals<V0, V1>, T) { };
> > +
> > +template<int V0, int V1>
> > +void f(vals<V0, V1>, char) { };
> > +
> > +template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
> > +
> > +int main() {
> > +  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
> > +}
> > --
> > 2.33.0.610.gcefe983a32
> >
>
  
Jason Merrill Oct. 5, 2021, 6:55 p.m. UTC | #7
On 10/1/21 13:29, Patrick Palka wrote:
> On Fri, 1 Oct 2021, Jason Merrill wrote:
> 
>> On 10/1/21 10:26, Patrick Palka wrote:
>>> On Fri, 1 Oct 2021, Jason Merrill wrote:
>>>
>>>> On 10/1/21 09:46, Patrick Palka wrote:
>>>>> Here during partial ordering of the two partial specializations we end
>>>>> up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash
>>>>> shortly
>>>>> thereafter because uses_template_parms calls
>>>>> potential_constant_expression
>>>>> which doesn't handle NONTYPE_ARGUMENT_PACK.
>>>>>
>>>>> This patch fixes this by checking dependent_template_arg_p instead of
>>>>> uses_template_parms when parm==arg, which does handle
>>>>> NONTYPE_ARGUMENT_PACK.
>>>>> We could also perhaps fix uses_template_parms / inst_dep_expr_p to
>>>>> better
>>>>> handle NONTYPE_ARGUMENT_PACK,
>>>>
>>>> Please.
>>>
>>> Sounds good, like the following then?  Passes light testing, bootstrap
>>> and regtest on progress.
>>>
>>> -- >8 --
>>>
>>> 	PR c++/102547
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* pt.c (instantiation_dependent_expression_p): Sidestep checking
>>> 	potential_constant_expression on NONTYPE_ARGUMENT_PACK.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* g++.dg/cpp0x/variadic-partial2.C: New test.
>>> 	* g++.dg/cpp0x/variadic-partial2a.C: New test.
>>> ---
>>>    gcc/cp/pt.c                                   |  4 +++-
>>>    .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
>>>    .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
>>>    3 files changed, 41 insertions(+), 1 deletion(-)
>>>    create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
>>>    create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
>>>
>>> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
>>> index 1dcdffe322a..643204103c5 100644
>>> --- a/gcc/cp/pt.c
>>> +++ b/gcc/cp/pt.c
>>> @@ -27705,7 +27705,9 @@ instantiation_dependent_expression_p (tree
>>> expression)
>>>    {
>>>      return (instantiation_dependent_uneval_expression_p (expression)
>>>    	  || (processing_template_decl
>>> -	      && potential_constant_expression (expression)
>>> +	      && expression != NULL_TREE
>>> +	      && (TREE_CODE (expression) == NONTYPE_ARGUMENT_PACK
>>> +		  || potential_constant_expression (expression))
>>
>> I'd prefer to loop over the elements of the pack, either here or (probably
>> better) in potential_constant_expression.
> 
> Ah, makes sense.  Like so?  Bootstrapped and regtested on
> x86_64-pc-linux-gnu.
> 
> -- >8 --
> 
> Subject: [PATCH] c++: unifying equal NONTYPE_ARGUMENT_PACKs [PR102547]
> 
> Here during partial ordering of the two partial specializations we end
> up in unify with parm=arg=NONTYPE_ARGUMENT_PACK<V0, V1>, and crash shortly
> thereafter because uses_template_parms(parms) calls potential_const_expr
> which doesn't handle NONTYPE_ARGUMENT_PACK.
> 
> This patch fixes this by extending potential_constant_expression to handle
> NONTYPE_ARGUMENT_PACK appropriately.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?

OK.

> 	PR c++/102547
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.c (potential_constant_expression_1): Handle
> 	NONTYPE_ARGUMENT_PACK.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/variadic-partial2.C: New test.
> 	* g++.dg/cpp0x/variadic-partial2a.C: New test.
> ---
>   gcc/cp/constexpr.c                            | 10 +++++++++
>   .../g++.dg/cpp0x/variadic-partial2.C          | 16 ++++++++++++++
>   .../g++.dg/cpp0x/variadic-partial2a.C         | 22 +++++++++++++++++++
>   3 files changed, 48 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> 
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 18d9d117a48..e95ff00774f 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -9043,6 +9043,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
>       case CO_RETURN_EXPR:
>         return false;
>   
> +    case NONTYPE_ARGUMENT_PACK:
> +      {
> +	tree args = ARGUMENT_PACK_ARGS (t);
> +	int len = TREE_VEC_LENGTH (args);
> +	for (int i = 0; i < len; ++i)
> +	  if (!RECUR (TREE_VEC_ELT (args, i), any))
> +	    return false;
> +	return true;
> +      }
> +
>       default:
>         if (objc_non_constant_expr_p (t))
>   	return false;
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> new file mode 100644
> index 00000000000..df61f26a3c1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
> @@ -0,0 +1,16 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +struct vals_client { };
> +
> +template<int V0, int V1, class T>
> +struct vals_client<vals<V0, V1>, T> { };
> +
> +template<int V0, int V1>
> +struct vals_client<vals<V0, V1>, void> { };
> +
> +template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
> diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> new file mode 100644
> index 00000000000..e98bdbbc07b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
> @@ -0,0 +1,22 @@
> +// PR c++/102547
> +// { dg-do compile { target c++11 } }
> +// A version of variadic-partial2.C where partial ordering is performed
> +// on function templates instead of class templates.
> +
> +template<int... Vs>
> +struct vals { };
> +
> +template<class V, class T>
> +void f(V, T) { };
> +
> +template<int V0, int V1, class T>
> +void f(vals<V0, V1>, T) { };
> +
> +template<int V0, int V1>
> +void f(vals<V0, V1>, char) { };
> +
> +template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
> +
> +int main() {
> +  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
> +}
>
  

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1dcdffe322a..59c00c77a30 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -23587,7 +23587,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
      even if ARG == PARM, since we won't record unifications for the
      template parameters.  We might need them if we're trying to
      figure out which of two things is more specialized.  */
-  if (arg == parm && !uses_template_parms (parm))
+  if (arg == parm && !dependent_template_arg_p (parm))
     return unify_success (explain_p);
 
   /* Handle init lists early, so the rest of the function can assume
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
new file mode 100644
index 00000000000..df61f26a3c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2.C
@@ -0,0 +1,16 @@ 
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+struct vals_client { };
+
+template<int V0, int V1, class T>
+struct vals_client<vals<V0, V1>, T> { };
+
+template<int V0, int V1>
+struct vals_client<vals<V0, V1>, void> { };
+
+template struct vals_client<vals<1, 2>, void>; //- "sorry, unimplemented..., ICE"
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
new file mode 100644
index 00000000000..cc0ea488ad3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial2a.C
@@ -0,0 +1,22 @@ 
+// PR c++/102547
+// { dg-do compile { target c++11 } }
+// A version of variadic-partial2.C where the partial ordering is performed
+// on function templates instead of class templates.
+
+template<int... Vs>
+struct vals { };
+
+template<class V, class T>
+void f(V, T) { };
+
+template<int V0, int V1, class T>
+void f(vals<V0, V1>, T) { };
+
+template<int V0, int V1>
+void f(vals<V0, V1>, char) { };
+
+template void f(vals<1, 2>, char); //- "sorry, unimplemented..., ICE"
+
+int main() {
+  f(vals<1, 3>{}, 'a'); //- "sorry, unimplemented..., ICE"
+}