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