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