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> ();