c++: do_class_deduction and dependent init [PR93383]
authorPatrick Palka <ppalka@redhat.com>
Sat, 24 Apr 2021 04:14:29 +0000 (00:14 -0400)
committerPatrick Palka <ppalka@redhat.com>
Sat, 24 Apr 2021 04:14:29 +0000 (00:14 -0400)
Here we're crashing during CTAD with a dependent initializer (performed
from convert_template_argument) because one of the initializer's
elements has an empty TREE_TYPE, which ends up making resolve_args
unhappy.

Besides the case where we're initializing one template placeholder
from another, which is already specifically handled earlier in
do_class_deduction, it seems we can't in general correctly resolve a
template placeholder using a dependent initializer, so this patch makes
the function just punt until instantiation time instead.

gcc/cp/ChangeLog:

PR c++/89565
PR c++/93383
PR c++/95291
PR c++/99200
PR c++/99683
* pt.c (do_class_deduction): Punt if the initializer is
type-dependent.

gcc/testsuite/ChangeLog:

PR c++/89565
PR c++/93383
PR c++/95291
PR c++/99200
PR c++/99683
* g++.dg/cpp2a/nontype-class39.C: Remove dg-ice directive.
* g++.dg/cpp2a/nontype-class45.C: New test.
* g++.dg/cpp2a/nontype-class46.C: New test.
* g++.dg/cpp2a/nontype-class47.C: New test.
* g++.dg/cpp2a/nontype-class48.C: New test.

gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/nontype-class39.C
gcc/testsuite/g++.dg/cpp2a/nontype-class45.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nontype-class46.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nontype-class47.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nontype-class48.C [new file with mode: 0644]

index 8d64fef..8c3c814 100644 (file)
@@ -29368,6 +29368,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
       return error_mark_node;
     }
 
+  /* Wait until the initializer is non-dependent.  */
+  if (type_dependent_expression_p (init))
+    return ptype;
+
   tree type = TREE_TYPE (tmpl);
 
   bool try_list_ctor = false;
index 512afad..9b4da4f 100644 (file)
@@ -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 (file)
index 0000000..e7addf5
--- /dev/null
@@ -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 (file)
index 0000000..d91e800
--- /dev/null
@@ -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-class47.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class47.C
new file mode 100644 (file)
index 0000000..1f31b9b
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/95291
+// { dg-do compile { target c++20 } }
+
+template <typename T = int>
+class xy { };
+
+template <xy _size>
+struct window_root { };
+
+template <typename minion>
+struct flip_horizontally : window_root<minion::size> { };
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class48.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class48.C
new file mode 100644 (file)
index 0000000..9024436
--- /dev/null
@@ -0,0 +1,36 @@
+// PR c++/99683
+// { dg-do compile { target c++20 } }
+
+template<auto V>
+struct nttp_tag {};
+
+template<typename T>
+struct type_tag {};
+
+
+/************************************************/
+template<bool is_type>
+struct use_ctad
+{
+    template<auto V> requires (!is_type)
+    constexpr use_ctad(nttp_tag<V>) {}
+};
+
+template<auto V>
+use_ctad(nttp_tag<V>) -> use_ctad<false>;
+
+/**********************************************/
+template<use_ctad t>
+struct wrapper 
+{
+    template<typename Tag>
+    wrapper(Tag);
+};
+
+template<typename Tag>
+wrapper(Tag) -> wrapper<use_ctad{Tag()}>;
+
+int main()
+{
+    wrapper t{nttp_tag<42>{}};
+}