Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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, , 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 A(T) -> A; A(int) -> A; then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and resolve to A, 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 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 000..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 +struct A +{ + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; } + char v[N + 1]; +}; + +template +struct B +{ + constexpr operator const char *() { return s.v; } +}; +
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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, , 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 A(T) -> A; > >A(int) -> A; > > > > then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and > > resolve to A, 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 > > struct N{}; > > diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class45.C > >
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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, , 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 A(T) -> A; A(int) -> A; then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and resolve to A, 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 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 000..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 +struct A +{ + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; } + char v[N + 1]; +}; + +template +struct B +{ + constexpr operator const char *() { return s.v; } +}; + +template +const char * +foo () +{ + return B<__PRETTY_FUNCTION__>{}; +} + +template +const char * +bar () +{ + return B<__FUNCTION__>{}; +} + +auto a = foo (); +auto b = bar (); 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 000..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 struct A {}; + +template struct B { + void foo(B<+a>); + void bar(B); + template using
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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, , 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 A(T) -> A; A(int) -> A; then ahead-of-time CTAD for A{v} where v is type-dependent will succeed and resolve to A, 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 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 000..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 +struct A +{ + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; } + char v[N + 1]; +}; + +template +struct B +{ + constexpr operator const char *() { return s.v; } +}; + +template +const char * +foo () +{ + return B<__PRETTY_FUNCTION__>{}; +} + +template +const char * +bar () +{ + return B<__FUNCTION__>{}; +} + +auto a = foo (); +auto b = bar (); 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 000..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 struct A {}; + +template struct B { + void
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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, , 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 > > 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 000..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 struct A {}; > > + > > +template struct B { > > + void foo(B<+a>); > > + void bar(B); > > + template using type = B; > > + template 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
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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 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 000..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 struct A {}; + +template struct B { + void foo(B<+a>); + void bar(B); + template using type = B; + template 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 000..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 +struct A +{ + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; } + char v[N + 1]; +}; + +template +struct B +{ + constexpr operator const char *() { return s.v; } +}; + +template +const char * +foo () +{ + return B<__PRETTY_FUNCTION__>{}; +} + +template +const char * +bar () +{ + return B<__FUNCTION__>{}; +} + +auto a = foo (); +auto b = bar ();
Re: [PATCH] c++: do_class_deduction and dependent init [PR93383]
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 > 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 000..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 struct A {}; > + > +template struct B { > + void foo(B<+a>); > + void bar(B); > + template using type = B; > + template 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 000..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 > +struct A > +{ > + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = > s[i]; v[N] = 0; } > + char v[N + 1]; > +}; > + > +template > +struct B > +{ > + constexpr operator const char *() { return s.v; } > +}; > + > +template > +const char * > +foo () > +{ > + return B<__PRETTY_FUNCTION__>{}; > +} > + > +template > +const char * > +bar () > +{ > + return B<__FUNCTION__>{}; > +} > + > +auto a = foo (); > +auto b = bar (); > -- > 2.31.1.272.g89b43f80a5 > >
[PATCH] c++: do_class_deduction and dependent init [PR93383]
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 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 000..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 struct A {}; + +template struct B { + void foo(B<+a>); + void bar(B); + template using type = B; + template 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 000..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 +struct A +{ + constexpr A (const char ()[N]) { for (int i = 0; i < N; i++) v[i] = s[i]; v[N] = 0; } + char v[N + 1]; +}; + +template +struct B +{ + constexpr operator const char *() { return s.v; } +}; + +template +const char * +foo () +{ + return B<__PRETTY_FUNCTION__>{}; +} + +template +const char * +bar () +{ + return B<__FUNCTION__>{}; +} + +auto a = foo (); +auto b = bar (); -- 2.31.1.272.g89b43f80a5