public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: do_class_deduction and dependent init [PR93383]
@ 2021-04-12 17:20 Patrick Palka
  2021-04-21 19:18 ` Patrick Palka
  2021-04-22  2:02 ` Jason Merrill
  0 siblings, 2 replies; 8+ messages in thread
From: Patrick Palka @ 2021-04-12 17:20 UTC (permalink / raw)
  To: gcc-patches

Here we're crashing during deduction for a template placeholder from a
dependent initializer because one of the initializer's elements has an
empty TREE_TYPE, something which resolve_args and later unify_one_argument
don't expect.  And if the deduction from a dependent initializer
otherwise fails, we prematurely issue an error rather than reattempting
the deduction at instantiation time.

This patch makes do_class_deduction more tolerant about dependent
initializers, in a manner similar to what do_auto_deduction does: if
deduction from a dependent initializer fails, just return the original
placeholder unchanged.

Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on
cmcstl2 and range-v3, and on all the testcases in PR93383, does this
look OK for trunk?

gcc/cp/ChangeLog:

	PR c++/89565
	PR c++/93383
	PR c++/99200
	* pt.c (do_class_deduction): If an argument has no type, don't
	attempt deduction.  If deduction fails and the initializer is
	type-dependent, try again at instantiation time.

gcc/testsuite/ChangeLog:

	PR c++/89565
	PR c++/93383
	PR c++/99200
	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
	* g++.dg/cpp2a/nontype-class44.C: New test.
	* g++.dg/cpp2a/nontype-class45.C: New test.
---
 gcc/cp/pt.c                                  | 11 +++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  1 -
 gcc/testsuite/g++.dg/cpp2a/nontype-class44.C | 11 +++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
 4 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0ce7fa359c1..612feac7976 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29334,6 +29334,13 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   else
     args = make_tree_vector_single (init);
 
+  /* If an argument is missing its type, we can't possibly deduce from this
+     (type-dependent) initializer ahead of time.  */
+  if (processing_template_decl)
+    for (tree arg : *args)
+      if (!TREE_TYPE (arg))
+	return ptype;
+
   /* Do this now to avoid problems with erroneous args later on.  */
   args = resolve_args (args, complain);
   if (args == NULL)
@@ -29419,6 +29426,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 
   if (call == error_mark_node)
     {
+      if (type_dependent_expression_p (init))
+	/* Try again at instantiation time.  */
+	return ptype;
+
       if (complain & tf_warning_or_error)
 	{
 	  error ("class template argument deduction failed:");
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
index f5f79a71ec2..9b4da4f02ea 100644
--- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
@@ -1,6 +1,5 @@
 // PR c++/89565
 // { dg-do compile { target c++20 } }
-// { dg-ice "resolve_args" }
 
 template <auto>
 struct N{};
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
new file mode 100644
index 00000000000..d91e800424f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
@@ -0,0 +1,11 @@
+// PR c++/93383
+// { dg-do compile { target c++20 } }
+
+template <int> struct A {};
+
+template <A a> struct B {
+  void foo(B<+a>);
+  void bar(B<a.x>);
+  template <class T> using type = B<T{}>;
+  template <class> static inline auto y = A{0}; // { dg-error "deduction|no match" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
new file mode 100644
index 00000000000..e7addf5f291
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
@@ -0,0 +1,32 @@
+// PR c++/99200
+// { dg-do compile { target c++20 } }
+
+template <int N>
+struct A
+{
+  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; }
+  char v[N + 1];
+};
+
+template <A s>
+struct B
+{
+  constexpr operator const char *() { return s.v; }
+};
+
+template <typename T>
+const char *
+foo ()
+{ 
+  return B<__PRETTY_FUNCTION__>{};
+}
+
+template <typename T>
+const char *
+bar ()
+{ 
+  return B<__FUNCTION__>{};
+}
+
+auto a = foo <int> ();
+auto b = bar <double> ();
-- 
2.31.1.272.g89b43f80a5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-12 17:20 [PATCH] c++: do_class_deduction and dependent init [PR93383] Patrick Palka
@ 2021-04-21 19:18 ` Patrick Palka
  2021-04-22  2:02 ` Jason Merrill
  1 sibling, 0 replies; 8+ messages in thread
From: Patrick Palka @ 2021-04-21 19:18 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, jason

On Mon, 12 Apr 2021, Patrick Palka wrote:

> Here we're crashing during deduction for a template placeholder from a
> dependent initializer because one of the initializer's elements has an
> empty TREE_TYPE, something which resolve_args and later unify_one_argument
> don't expect.  And if the deduction from a dependent initializer
> otherwise fails, we prematurely issue an error rather than reattempting
> the deduction at instantiation time.
> 
> This patch makes do_class_deduction more tolerant about dependent
> initializers, in a manner similar to what do_auto_deduction does: if
> deduction from a dependent initializer fails, just return the original
> placeholder unchanged.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on
> cmcstl2 and range-v3, and on all the testcases in PR93383, does this
> look OK for trunk?

Ping.  This patch apparently also fixes the ICE reported in PR95291 and
its related/duplicate PRs.

> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* pt.c (do_class_deduction): If an argument has no type, don't
> 	attempt deduction.  If deduction fails and the initializer is
> 	type-dependent, try again at instantiation time.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
> 	* g++.dg/cpp2a/nontype-class44.C: New test.
> 	* g++.dg/cpp2a/nontype-class45.C: New test.
> ---
>  gcc/cp/pt.c                                  | 11 +++++++
>  gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  1 -
>  gcc/testsuite/g++.dg/cpp2a/nontype-class44.C | 11 +++++++
>  gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
>  4 files changed, 54 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 0ce7fa359c1..612feac7976 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29334,6 +29334,13 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>    else
>      args = make_tree_vector_single (init);
>  
> +  /* If an argument is missing its type, we can't possibly deduce from this
> +     (type-dependent) initializer ahead of time.  */
> +  if (processing_template_decl)
> +    for (tree arg : *args)
> +      if (!TREE_TYPE (arg))
> +	return ptype;
> +
>    /* Do this now to avoid problems with erroneous args later on.  */
>    args = resolve_args (args, complain);
>    if (args == NULL)
> @@ -29419,6 +29426,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>  
>    if (call == error_mark_node)
>      {
> +      if (type_dependent_expression_p (init))
> +	/* Try again at instantiation time.  */
> +	return ptype;
> +
>        if (complain & tf_warning_or_error)
>  	{
>  	  error ("class template argument deduction failed:");
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> index f5f79a71ec2..9b4da4f02ea 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> @@ -1,6 +1,5 @@
>  // PR c++/89565
>  // { dg-do compile { target c++20 } }
> -// { dg-ice "resolve_args" }
>  
>  template <auto>
>  struct N{};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> new file mode 100644
> index 00000000000..d91e800424f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> @@ -0,0 +1,11 @@
> +// PR c++/93383
> +// { dg-do compile { target c++20 } }
> +
> +template <int> struct A {};
> +
> +template <A a> struct B {
> +  void foo(B<+a>);
> +  void bar(B<a.x>);
> +  template <class T> using type = B<T{}>;
> +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no match" }
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> new file mode 100644
> index 00000000000..e7addf5f291
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> @@ -0,0 +1,32 @@
> +// PR c++/99200
> +// { dg-do compile { target c++20 } }
> +
> +template <int N>
> +struct A
> +{
> +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; }
> +  char v[N + 1];
> +};
> +
> +template <A s>
> +struct B
> +{
> +  constexpr operator const char *() { return s.v; }
> +};
> +
> +template <typename T>
> +const char *
> +foo ()
> +{ 
> +  return B<__PRETTY_FUNCTION__>{};
> +}
> +
> +template <typename T>
> +const char *
> +bar ()
> +{ 
> +  return B<__FUNCTION__>{};
> +}
> +
> +auto a = foo <int> ();
> +auto b = bar <double> ();
> -- 
> 2.31.1.272.g89b43f80a5
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-12 17:20 [PATCH] c++: do_class_deduction and dependent init [PR93383] Patrick Palka
  2021-04-21 19:18 ` Patrick Palka
@ 2021-04-22  2:02 ` Jason Merrill
  2021-04-22  3:14   ` Patrick Palka
  1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-04-22  2:02 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 4/12/21 1:20 PM, Patrick Palka wrote:
> Here we're crashing during deduction for a template placeholder from a
> dependent initializer because one of the initializer's elements has an
> empty TREE_TYPE, something which resolve_args and later unify_one_argument
> don't expect.  And if the deduction from a dependent initializer
> otherwise fails, we prematurely issue an error rather than reattempting
> the deduction at instantiation time.
> 
> This patch makes do_class_deduction more tolerant about dependent
> initializers, in a manner similar to what do_auto_deduction does: if
> deduction from a dependent initializer fails, just return the original
> placeholder unchanged.

Why doesn't the type_dependent_expression_p check in do_auto_deduction 
catch this already?

> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on
> cmcstl2 and range-v3, and on all the testcases in PR93383, does this
> look OK for trunk?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* pt.c (do_class_deduction): If an argument has no type, don't
> 	attempt deduction.  If deduction fails and the initializer is
> 	type-dependent, try again at instantiation time.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
> 	* g++.dg/cpp2a/nontype-class44.C: New test.
> 	* g++.dg/cpp2a/nontype-class45.C: New test.
> ---
>   gcc/cp/pt.c                                  | 11 +++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  1 -
>   gcc/testsuite/g++.dg/cpp2a/nontype-class44.C | 11 +++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
>   4 files changed, 54 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 0ce7fa359c1..612feac7976 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29334,6 +29334,13 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>     else
>       args = make_tree_vector_single (init);
>   
> +  /* If an argument is missing its type, we can't possibly deduce from this
> +     (type-dependent) initializer ahead of time.  */
> +  if (processing_template_decl)
> +    for (tree arg : *args)
> +      if (!TREE_TYPE (arg))
> +	return ptype;
>     /* Do this now to avoid problems with erroneous args later on.  */
>     args = resolve_args (args, complain);
>     if (args == NULL)
> @@ -29419,6 +29426,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>   
>     if (call == error_mark_node)
>       {
> +      if (type_dependent_expression_p (init))
> +	/* Try again at instantiation time.  */
> +	return ptype;
> +
>         if (complain & tf_warning_or_error)
>   	{
>   	  error ("class template argument deduction failed:");
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> index f5f79a71ec2..9b4da4f02ea 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> @@ -1,6 +1,5 @@
>   // PR c++/89565
>   // { dg-do compile { target c++20 } }
> -// { dg-ice "resolve_args" }
>   
>   template <auto>
>   struct N{};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> new file mode 100644
> index 00000000000..d91e800424f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> @@ -0,0 +1,11 @@
> +// PR c++/93383
> +// { dg-do compile { target c++20 } }
> +
> +template <int> struct A {};
> +
> +template <A a> struct B {
> +  void foo(B<+a>);
> +  void bar(B<a.x>);
> +  template <class T> using type = B<T{}>;
> +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no match" }
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> new file mode 100644
> index 00000000000..e7addf5f291
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> @@ -0,0 +1,32 @@
> +// PR c++/99200
> +// { dg-do compile { target c++20 } }
> +
> +template <int N>
> +struct A
> +{
> +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; }
> +  char v[N + 1];
> +};
> +
> +template <A s>
> +struct B
> +{
> +  constexpr operator const char *() { return s.v; }
> +};
> +
> +template <typename T>
> +const char *
> +foo ()
> +{
> +  return B<__PRETTY_FUNCTION__>{};
> +}
> +
> +template <typename T>
> +const char *
> +bar ()
> +{
> +  return B<__FUNCTION__>{};
> +}
> +
> +auto a = foo <int> ();
> +auto b = bar <double> ();
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-22  2:02 ` Jason Merrill
@ 2021-04-22  3:14   ` Patrick Palka
  2021-04-22 13:46     ` Patrick Palka
  0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-04-22  3:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches

On Wed, 21 Apr 2021, Jason Merrill wrote:

> On 4/12/21 1:20 PM, Patrick Palka wrote:
> > Here we're crashing during deduction for a template placeholder from a
> > dependent initializer because one of the initializer's elements has an
> > empty TREE_TYPE, something which resolve_args and later unify_one_argument
> > don't expect.  And if the deduction from a dependent initializer
> > otherwise fails, we prematurely issue an error rather than reattempting
> > the deduction at instantiation time.
> > 
> > This patch makes do_class_deduction more tolerant about dependent
> > initializers, in a manner similar to what do_auto_deduction does: if
> > deduction from a dependent initializer fails, just return the original
> > placeholder unchanged.
> 
> Why doesn't the type_dependent_expression_p check in do_auto_deduction catch
> this already?

That check applies only when context != adc_unify, but here we have
context == adc_unify since we're being called from
convert_template_argument.

And currently, when 'auto' deduction fails for a dependent initializer,
do_auto_deduction will just silently return the original placeholder:

      int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
                                       DEDUCE_CALL,
                                       NULL, /*explain_p=*/false);
      if (val > 0)
        {
          if (processing_template_decl)
            /* Try again at instantiation time.  */
            return type;

so I suppose this patch just makes do_class_deduction behave more
similarly to do_auto_deduction in this situation.

> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on
> > cmcstl2 and range-v3, and on all the testcases in PR93383, does this
> > look OK for trunk?
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	PR c++/89565
> > 	PR c++/93383
> > 	PR c++/99200
> > 	* pt.c (do_class_deduction): If an argument has no type, don't
> > 	attempt deduction.  If deduction fails and the initializer is
> > 	type-dependent, try again at instantiation time.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	PR c++/89565
> > 	PR c++/93383
> > 	PR c++/99200
> > 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
> > 	* g++.dg/cpp2a/nontype-class44.C: New test.
> > 	* g++.dg/cpp2a/nontype-class45.C: New test.
> > ---
> >   gcc/cp/pt.c                                  | 11 +++++++
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  1 -
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class44.C | 11 +++++++
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
> >   4 files changed, 54 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 0ce7fa359c1..612feac7976 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -29334,6 +29334,13 @@ do_class_deduction (tree ptype, tree tmpl, tree
> > init,
> >     else
> >       args = make_tree_vector_single (init);
> >   +  /* If an argument is missing its type, we can't possibly deduce from
> > this
> > +     (type-dependent) initializer ahead of time.  */
> > +  if (processing_template_decl)
> > +    for (tree arg : *args)
> > +      if (!TREE_TYPE (arg))
> > +	return ptype;
> >     /* Do this now to avoid problems with erroneous args later on.  */
> >     args = resolve_args (args, complain);
> >     if (args == NULL)
> > @@ -29419,6 +29426,10 @@ do_class_deduction (tree ptype, tree tmpl, tree
> > init,
> >       if (call == error_mark_node)
> >       {
> > +      if (type_dependent_expression_p (init))
> > +	/* Try again at instantiation time.  */
> > +	return ptype;
> > +
> >         if (complain & tf_warning_or_error)
> >   	{
> >   	  error ("class template argument deduction failed:");
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > index f5f79a71ec2..9b4da4f02ea 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > @@ -1,6 +1,5 @@
> >   // PR c++/89565
> >   // { dg-do compile { target c++20 } }
> > -// { dg-ice "resolve_args" }
> >     template <auto>
> >   struct N{};
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> > new file mode 100644
> > index 00000000000..d91e800424f
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class44.C
> > @@ -0,0 +1,11 @@
> > +// PR c++/93383
> > +// { dg-do compile { target c++20 } }
> > +
> > +template <int> struct A {};
> > +
> > +template <A a> struct B {
> > +  void foo(B<+a>);
> > +  void bar(B<a.x>);
> > +  template <class T> using type = B<T{}>;
> > +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no
> > match" }
> > +};
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > new file mode 100644
> > index 00000000000..e7addf5f291
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > @@ -0,0 +1,32 @@
> > +// PR c++/99200
> > +// { dg-do compile { target c++20 } }
> > +
> > +template <int N>
> > +struct A
> > +{
> > +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] =
> > s[i]; v[N] = 0; }
> > +  char v[N + 1];
> > +};
> > +
> > +template <A s>
> > +struct B
> > +{
> > +  constexpr operator const char *() { return s.v; }
> > +};
> > +
> > +template <typename T>
> > +const char *
> > +foo ()
> > +{
> > +  return B<__PRETTY_FUNCTION__>{};
> > +}
> > +
> > +template <typename T>
> > +const char *
> > +bar ()
> > +{
> > +  return B<__FUNCTION__>{};
> > +}
> > +
> > +auto a = foo <int> ();
> > +auto b = bar <double> ();
> > 
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-22  3:14   ` Patrick Palka
@ 2021-04-22 13:46     ` Patrick Palka
  2021-04-23 20:21       ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-04-22 13:46 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Jason Merrill, gcc-patches

On Wed, 21 Apr 2021, Patrick Palka wrote:

> On Wed, 21 Apr 2021, Jason Merrill wrote:
> 
> > On 4/12/21 1:20 PM, Patrick Palka wrote:
> > > Here we're crashing during deduction for a template placeholder from a
> > > dependent initializer because one of the initializer's elements has an
> > > empty TREE_TYPE, something which resolve_args and later unify_one_argument
> > > don't expect.  And if the deduction from a dependent initializer
> > > otherwise fails, we prematurely issue an error rather than reattempting
> > > the deduction at instantiation time.
> > > 
> > > This patch makes do_class_deduction more tolerant about dependent
> > > initializers, in a manner similar to what do_auto_deduction does: if
> > > deduction from a dependent initializer fails, just return the original
> > > placeholder unchanged.
> > 
> > Why doesn't the type_dependent_expression_p check in do_auto_deduction catch
> > this already?
> 
> That check applies only when context != adc_unify, but here we have
> context == adc_unify since we're being called from
> convert_template_argument.
> 
> And currently, when 'auto' deduction fails for a dependent initializer,
> do_auto_deduction will just silently return the original placeholder:
> 
>       int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
>                                        DEDUCE_CALL,
>                                        NULL, /*explain_p=*/false);
>       if (val > 0)
>         {
>           if (processing_template_decl)
>             /* Try again at instantiation time.  */
>             return type;
> 
> so I suppose this patch just makes do_class_deduction behave more
> similarly to do_auto_deduction in this situation.

On second thought, I think attempting CTAD a dependent initializer as the patch
does might sometimes give us the wrong answer.  If e.g. the class template in
question has the deduction guides

  template <class T> A(T) -> A<char>;
  A(int) -> A<void>;

then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and
resolve to A<char>, but at instantiation time the type of v might be int.  So
perhaps we should just have do_class_deduction punt on all type-dependent
expressions, e.g.

-- >8 --

gcc/cp/ChangeLog:

	PR c++/89565
	PR c++/93383
	PR c++/99200
	* pt.c (do_class_deduction): Give up if the initializer is
	type-dependent.

gcc/testsuite/ChangeLog:

	PR c++/89565
	PR c++/93383
	PR c++/99200
	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
	* g++.dg/cpp2a/nontype-class45.C: New test.
	* g++.dg/cpp2a/nontype-class46.C: New test.
---
 gcc/cp/pt.c                                  |  5 +++
 gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  2 --
 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/nontype-class46.C | 11 +++++++
 4 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class46.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7bcbe6dc3ce..6673f935ab6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29362,6 +29362,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
       return error_mark_node;
     }
 
+  /* If the initializer is dependent, we can't resolve the class template
+     placeholder ahead of time.  */
+  if (type_dependent_expression_p (init))
+    return ptype;
+
   tree type = TREE_TYPE (tmpl);
 
   bool try_list_ctor = false;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
index 512afad8e4f..9b4da4f02ea 100644
--- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
@@ -1,7 +1,5 @@
 // PR c++/89565
 // { dg-do compile { target c++20 } }
-// { dg-additional-options "-fchecking" }
-// { dg-ice "resolve_args" }
 
 template <auto>
 struct N{};
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
new file mode 100644
index 00000000000..e7addf5f291
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
@@ -0,0 +1,32 @@
+// PR c++/99200
+// { dg-do compile { target c++20 } }
+
+template <int N>
+struct A
+{
+  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; }
+  char v[N + 1];
+};
+
+template <A s>
+struct B
+{
+  constexpr operator const char *() { return s.v; }
+};
+
+template <typename T>
+const char *
+foo ()
+{ 
+  return B<__PRETTY_FUNCTION__>{};
+}
+
+template <typename T>
+const char *
+bar ()
+{ 
+  return B<__FUNCTION__>{};
+}
+
+auto a = foo <int> ();
+auto b = bar <double> ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
new file mode 100644
index 00000000000..d91e800424f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
@@ -0,0 +1,11 @@
+// PR c++/93383
+// { dg-do compile { target c++20 } }
+
+template <int> struct A {};
+
+template <A a> struct B {
+  void foo(B<+a>);
+  void bar(B<a.x>);
+  template <class T> using type = B<T{}>;
+  template <class> static inline auto y = A{0}; // { dg-error "deduction|no match" }
+};
-- 
2.31.1.362.g311531c9de


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-22 13:46     ` Patrick Palka
@ 2021-04-23 20:21       ` Jason Merrill
  2021-04-26 13:29         ` Patrick Palka
  0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-04-23 20:21 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

On 4/22/21 9:46 AM, Patrick Palka wrote:
> On Wed, 21 Apr 2021, Patrick Palka wrote:
> 
>> On Wed, 21 Apr 2021, Jason Merrill wrote:
>>
>>> On 4/12/21 1:20 PM, Patrick Palka wrote:
>>>> Here we're crashing during deduction for a template placeholder from a
>>>> dependent initializer because one of the initializer's elements has an
>>>> empty TREE_TYPE, something which resolve_args and later unify_one_argument
>>>> don't expect.  And if the deduction from a dependent initializer
>>>> otherwise fails, we prematurely issue an error rather than reattempting
>>>> the deduction at instantiation time.
>>>>
>>>> This patch makes do_class_deduction more tolerant about dependent
>>>> initializers, in a manner similar to what do_auto_deduction does: if
>>>> deduction from a dependent initializer fails, just return the original
>>>> placeholder unchanged.
>>>
>>> Why doesn't the type_dependent_expression_p check in do_auto_deduction catch
>>> this already?
>>
>> That check applies only when context != adc_unify, but here we have
>> context == adc_unify since we're being called from
>> convert_template_argument.
>>
>> And currently, when 'auto' deduction fails for a dependent initializer,
>> do_auto_deduction will just silently return the original placeholder:
>>
>>        int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
>>                                         DEDUCE_CALL,
>>                                         NULL, /*explain_p=*/false);
>>        if (val > 0)
>>          {
>>            if (processing_template_decl)
>>              /* Try again at instantiation time.  */
>>              return type;
>>
>> so I suppose this patch just makes do_class_deduction behave more
>> similarly to do_auto_deduction in this situation.
> 
> On second thought, I think attempting CTAD a dependent initializer as the patch
> does might sometimes give us the wrong answer.  If e.g. the class template in
> question has the deduction guides
> 
>    template <class T> A(T) -> A<char>;
>    A(int) -> A<void>;
> 
> then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and
> resolve to A<char>, but at instantiation time the type of v might be int.  So
> perhaps we should just have do_class_deduction punt on all type-dependent
> expressions, e.g.

OK.

> -- >8 --
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* pt.c (do_class_deduction): Give up if the initializer is
> 	type-dependent.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/89565
> 	PR c++/93383
> 	PR c++/99200
> 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
> 	* g++.dg/cpp2a/nontype-class45.C: New test.
> 	* g++.dg/cpp2a/nontype-class46.C: New test.
> ---
>   gcc/cp/pt.c                                  |  5 +++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  2 --
>   gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/nontype-class46.C | 11 +++++++
>   4 files changed, 48 insertions(+), 2 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 7bcbe6dc3ce..6673f935ab6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29362,6 +29362,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>         return error_mark_node;
>       }
>   
> +  /* If the initializer is dependent, we can't resolve the class template
> +     placeholder ahead of time.  */
> +  if (type_dependent_expression_p (init))
> +    return ptype;
> +
>     tree type = TREE_TYPE (tmpl);
>   
>     bool try_list_ctor = false;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> index 512afad8e4f..9b4da4f02ea 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> @@ -1,7 +1,5 @@
>   // PR c++/89565
>   // { dg-do compile { target c++20 } }
> -// { dg-additional-options "-fchecking" }
> -// { dg-ice "resolve_args" }
>   
>   template <auto>
>   struct N{};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> new file mode 100644
> index 00000000000..e7addf5f291
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> @@ -0,0 +1,32 @@
> +// PR c++/99200
> +// { dg-do compile { target c++20 } }
> +
> +template <int N>
> +struct A
> +{
> +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; }
> +  char v[N + 1];
> +};
> +
> +template <A s>
> +struct B
> +{
> +  constexpr operator const char *() { return s.v; }
> +};
> +
> +template <typename T>
> +const char *
> +foo ()
> +{
> +  return B<__PRETTY_FUNCTION__>{};
> +}
> +
> +template <typename T>
> +const char *
> +bar ()
> +{
> +  return B<__FUNCTION__>{};
> +}
> +
> +auto a = foo <int> ();
> +auto b = bar <double> ();
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> new file mode 100644
> index 00000000000..d91e800424f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> @@ -0,0 +1,11 @@
> +// PR c++/93383
> +// { dg-do compile { target c++20 } }
> +
> +template <int> struct A {};
> +
> +template <A a> struct B {
> +  void foo(B<+a>);
> +  void bar(B<a.x>);
> +  template <class T> using type = B<T{}>;
> +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no match" }
> +};
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-23 20:21       ` Jason Merrill
@ 2021-04-26 13:29         ` Patrick Palka
  2021-04-26 16:42           ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2021-04-26 13:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches

On Fri, 23 Apr 2021, Jason Merrill wrote:

> On 4/22/21 9:46 AM, Patrick Palka wrote:
> > On Wed, 21 Apr 2021, Patrick Palka wrote:
> > 
> > > On Wed, 21 Apr 2021, Jason Merrill wrote:
> > > 
> > > > On 4/12/21 1:20 PM, Patrick Palka wrote:
> > > > > Here we're crashing during deduction for a template placeholder from a
> > > > > dependent initializer because one of the initializer's elements has an
> > > > > empty TREE_TYPE, something which resolve_args and later
> > > > > unify_one_argument
> > > > > don't expect.  And if the deduction from a dependent initializer
> > > > > otherwise fails, we prematurely issue an error rather than
> > > > > reattempting
> > > > > the deduction at instantiation time.
> > > > > 
> > > > > This patch makes do_class_deduction more tolerant about dependent
> > > > > initializers, in a manner similar to what do_auto_deduction does: if
> > > > > deduction from a dependent initializer fails, just return the original
> > > > > placeholder unchanged.
> > > > 
> > > > Why doesn't the type_dependent_expression_p check in do_auto_deduction
> > > > catch
> > > > this already?
> > > 
> > > That check applies only when context != adc_unify, but here we have
> > > context == adc_unify since we're being called from
> > > convert_template_argument.
> > > 
> > > And currently, when 'auto' deduction fails for a dependent initializer,
> > > do_auto_deduction will just silently return the original placeholder:
> > > 
> > >        int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
> > >                                         DEDUCE_CALL,
> > >                                         NULL, /*explain_p=*/false);
> > >        if (val > 0)
> > >          {
> > >            if (processing_template_decl)
> > >              /* Try again at instantiation time.  */
> > >              return type;
> > > 
> > > so I suppose this patch just makes do_class_deduction behave more
> > > similarly to do_auto_deduction in this situation.
> > 
> > On second thought, I think attempting CTAD a dependent initializer as the
> > patch
> > does might sometimes give us the wrong answer.  If e.g. the class template
> > in
> > question has the deduction guides
> > 
> >    template <class T> A(T) -> A<char>;
> >    A(int) -> A<void>;
> > 
> > then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and
> > resolve to A<char>, but at instantiation time the type of v might be int.
> > So
> > perhaps we should just have do_class_deduction punt on all type-dependent
> > expressions, e.g.
> 
> OK.

Thanks a lot, patch committed as r12-100.

I wonder, would this be suitable for backporting to the 11 branch given
the amount of PRs this fixes (~16 if dups are counted)?   The patch
should affect only C++20 code (since do_class_deduction should see a
dependent init only when context=adc_unify, so the added early exit
check should be dead code unless class NTTP placeholders are used), and
there doesn't seem to be a general workaround for the ICEs this fixes.

> 
> > -- >8 --
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	PR c++/89565
> > 	PR c++/93383
> > 	PR c++/99200
> > 	* pt.c (do_class_deduction): Give up if the initializer is
> > 	type-dependent.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	PR c++/89565
> > 	PR c++/93383
> > 	PR c++/99200
> > 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
> > 	* g++.dg/cpp2a/nontype-class45.C: New test.
> > 	* g++.dg/cpp2a/nontype-class46.C: New test.
> > ---
> >   gcc/cp/pt.c                                  |  5 +++
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  2 --
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
> >   gcc/testsuite/g++.dg/cpp2a/nontype-class46.C | 11 +++++++
> >   4 files changed, 48 insertions(+), 2 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 7bcbe6dc3ce..6673f935ab6 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -29362,6 +29362,11 @@ do_class_deduction (tree ptype, tree tmpl, tree
> > init,
> >         return error_mark_node;
> >       }
> >   +  /* If the initializer is dependent, we can't resolve the class template
> > +     placeholder ahead of time.  */
> > +  if (type_dependent_expression_p (init))
> > +    return ptype;
> > +
> >     tree type = TREE_TYPE (tmpl);
> >       bool try_list_ctor = false;
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > index 512afad8e4f..9b4da4f02ea 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
> > @@ -1,7 +1,5 @@
> >   // PR c++/89565
> >   // { dg-do compile { target c++20 } }
> > -// { dg-additional-options "-fchecking" }
> > -// { dg-ice "resolve_args" }
> >     template <auto>
> >   struct N{};
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > new file mode 100644
> > index 00000000000..e7addf5f291
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
> > @@ -0,0 +1,32 @@
> > +// PR c++/99200
> > +// { dg-do compile { target c++20 } }
> > +
> > +template <int N>
> > +struct A
> > +{
> > +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] =
> > s[i]; v[N] = 0; }
> > +  char v[N + 1];
> > +};
> > +
> > +template <A s>
> > +struct B
> > +{
> > +  constexpr operator const char *() { return s.v; }
> > +};
> > +
> > +template <typename T>
> > +const char *
> > +foo ()
> > +{
> > +  return B<__PRETTY_FUNCTION__>{};
> > +}
> > +
> > +template <typename T>
> > +const char *
> > +bar ()
> > +{
> > +  return B<__FUNCTION__>{};
> > +}
> > +
> > +auto a = foo <int> ();
> > +auto b = bar <double> ();
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> > b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> > new file mode 100644
> > index 00000000000..d91e800424f
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
> > @@ -0,0 +1,11 @@
> > +// PR c++/93383
> > +// { dg-do compile { target c++20 } }
> > +
> > +template <int> struct A {};
> > +
> > +template <A a> struct B {
> > +  void foo(B<+a>);
> > +  void bar(B<a.x>);
> > +  template <class T> using type = B<T{}>;
> > +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no
> > match" }
> > +};
> > 
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
  2021-04-26 13:29         ` Patrick Palka
@ 2021-04-26 16:42           ` Jason Merrill
  0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2021-04-26 16:42 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

On 4/26/21 9:29 AM, Patrick Palka wrote:
> On Fri, 23 Apr 2021, Jason Merrill wrote:
> 
>> On 4/22/21 9:46 AM, Patrick Palka wrote:
>>> On Wed, 21 Apr 2021, Patrick Palka wrote:
>>>
>>>> On Wed, 21 Apr 2021, Jason Merrill wrote:
>>>>
>>>>> On 4/12/21 1:20 PM, Patrick Palka wrote:
>>>>>> Here we're crashing during deduction for a template placeholder from a
>>>>>> dependent initializer because one of the initializer's elements has an
>>>>>> empty TREE_TYPE, something which resolve_args and later
>>>>>> unify_one_argument
>>>>>> don't expect.  And if the deduction from a dependent initializer
>>>>>> otherwise fails, we prematurely issue an error rather than
>>>>>> reattempting
>>>>>> the deduction at instantiation time.
>>>>>>
>>>>>> This patch makes do_class_deduction more tolerant about dependent
>>>>>> initializers, in a manner similar to what do_auto_deduction does: if
>>>>>> deduction from a dependent initializer fails, just return the original
>>>>>> placeholder unchanged.
>>>>>
>>>>> Why doesn't the type_dependent_expression_p check in do_auto_deduction
>>>>> catch
>>>>> this already?
>>>>
>>>> That check applies only when context != adc_unify, but here we have
>>>> context == adc_unify since we're being called from
>>>> convert_template_argument.
>>>>
>>>> And currently, when 'auto' deduction fails for a dependent initializer,
>>>> do_auto_deduction will just silently return the original placeholder:
>>>>
>>>>         int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
>>>>                                          DEDUCE_CALL,
>>>>                                          NULL, /*explain_p=*/false);
>>>>         if (val > 0)
>>>>           {
>>>>             if (processing_template_decl)
>>>>               /* Try again at instantiation time.  */
>>>>               return type;
>>>>
>>>> so I suppose this patch just makes do_class_deduction behave more
>>>> similarly to do_auto_deduction in this situation.
>>>
>>> On second thought, I think attempting CTAD a dependent initializer as the
>>> patch
>>> does might sometimes give us the wrong answer.  If e.g. the class template
>>> in
>>> question has the deduction guides
>>>
>>>     template <class T> A(T) -> A<char>;
>>>     A(int) -> A<void>;
>>>
>>> then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and
>>> resolve to A<char>, but at instantiation time the type of v might be int.
>>> So
>>> perhaps we should just have do_class_deduction punt on all type-dependent
>>> expressions, e.g.
>>
>> OK.
> 
> Thanks a lot, patch committed as r12-100.
> 
> I wonder, would this be suitable for backporting to the 11 branch given
> the amount of PRs this fixes (~16 if dups are counted)?   The patch
> should affect only C++20 code (since do_class_deduction should see a
> dependent init only when context=adc_unify, so the added early exit
> check should be dead code unless class NTTP placeholders are used), and
> there doesn't seem to be a general workaround for the ICEs this fixes.

Sounds good.

>>> -- >8 --
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	PR c++/89565
>>> 	PR c++/93383
>>> 	PR c++/99200
>>> 	* pt.c (do_class_deduction): Give up if the initializer is
>>> 	type-dependent.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	PR c++/89565
>>> 	PR c++/93383
>>> 	PR c++/99200
>>> 	* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice.
>>> 	* g++.dg/cpp2a/nontype-class45.C: New test.
>>> 	* g++.dg/cpp2a/nontype-class46.C: New test.
>>> ---
>>>    gcc/cp/pt.c                                  |  5 +++
>>>    gcc/testsuite/g++.dg/cpp2a/nontype-class39.C |  2 --
>>>    gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 ++++++++++++++++++++
>>>    gcc/testsuite/g++.dg/cpp2a/nontype-class46.C | 11 +++++++
>>>    4 files changed, 48 insertions(+), 2 deletions(-)
>>>    create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
>>>    create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
>>>
>>> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
>>> index 7bcbe6dc3ce..6673f935ab6 100644
>>> --- a/gcc/cp/pt.c
>>> +++ b/gcc/cp/pt.c
>>> @@ -29362,6 +29362,11 @@ do_class_deduction (tree ptype, tree tmpl, tree
>>> init,
>>>          return error_mark_node;
>>>        }
>>>    +  /* If the initializer is dependent, we can't resolve the class template
>>> +     placeholder ahead of time.  */
>>> +  if (type_dependent_expression_p (init))
>>> +    return ptype;
>>> +
>>>      tree type = TREE_TYPE (tmpl);
>>>        bool try_list_ctor = false;
>>> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
>>> b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
>>> index 512afad8e4f..9b4da4f02ea 100644
>>> --- a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
>>> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
>>> @@ -1,7 +1,5 @@
>>>    // PR c++/89565
>>>    // { dg-do compile { target c++20 } }
>>> -// { dg-additional-options "-fchecking" }
>>> -// { dg-ice "resolve_args" }
>>>      template <auto>
>>>    struct N{};
>>> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
>>> b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
>>> new file mode 100644
>>> index 00000000000..e7addf5f291
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C
>>> @@ -0,0 +1,32 @@
>>> +// PR c++/99200
>>> +// { dg-do compile { target c++20 } }
>>> +
>>> +template <int N>
>>> +struct A
>>> +{
>>> +  constexpr A (const char (&s)[N]) { for (int i = 0; i < N; i++) v[i] =
>>> s[i]; v[N] = 0; }
>>> +  char v[N + 1];
>>> +};
>>> +
>>> +template <A s>
>>> +struct B
>>> +{
>>> +  constexpr operator const char *() { return s.v; }
>>> +};
>>> +
>>> +template <typename T>
>>> +const char *
>>> +foo ()
>>> +{
>>> +  return B<__PRETTY_FUNCTION__>{};
>>> +}
>>> +
>>> +template <typename T>
>>> +const char *
>>> +bar ()
>>> +{
>>> +  return B<__FUNCTION__>{};
>>> +}
>>> +
>>> +auto a = foo <int> ();
>>> +auto b = bar <double> ();
>>> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
>>> b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
>>> new file mode 100644
>>> index 00000000000..d91e800424f
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class46.C
>>> @@ -0,0 +1,11 @@
>>> +// PR c++/93383
>>> +// { dg-do compile { target c++20 } }
>>> +
>>> +template <int> struct A {};
>>> +
>>> +template <A a> struct B {
>>> +  void foo(B<+a>);
>>> +  void bar(B<a.x>);
>>> +  template <class T> using type = B<T{}>;
>>> +  template <class> static inline auto y = A{0}; // { dg-error "deduction|no
>>> match" }
>>> +};
>>>
>>
>>
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-04-26 16:42 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-12 17:20 [PATCH] c++: do_class_deduction and dependent init [PR93383] Patrick Palka
2021-04-21 19:18 ` Patrick Palka
2021-04-22  2:02 ` Jason Merrill
2021-04-22  3:14   ` Patrick Palka
2021-04-22 13:46     ` Patrick Palka
2021-04-23 20:21       ` Jason Merrill
2021-04-26 13:29         ` Patrick Palka
2021-04-26 16:42           ` Jason Merrill

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).