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" } > > +}; > > > >