diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-04-24 00:14:29 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-04-24 00:14:29 -0400 |
commit | bcd77b7b9f35bd5b559ed593c3b3e346c1e6f364 (patch) | |
tree | e88f062f4be1c92aecddaf6953f76ade32c1b36f | |
parent | 5f1a2cb9c2dc09eed53da5d5787d14bec700b10b (diff) | |
download | gcc-bcd77b7b9f35bd5b559ed593c3b3e346c1e6f364.zip gcc-bcd77b7b9f35bd5b559ed593c3b3e346c1e6f364.tar.gz gcc-bcd77b7b9f35bd5b559ed593c3b3e346c1e6f364.tar.bz2 |
c++: do_class_deduction and dependent init [PR93383]
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.
-rw-r--r-- | gcc/cp/pt.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class39.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class45.C | 32 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class46.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class47.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class48.C | 36 |
6 files changed, 94 insertions, 2 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8d64fef..8c3c814 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C index 512afad..9b4da4f 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 0000000..e7addf5 --- /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 0000000..d91e800 --- /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" } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class47.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class47.C new file mode 100644 index 0000000..1f31b9b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class47.C @@ -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 index 0000000..9024436 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class48.C @@ -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>{}}; +} |