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