diff options
author | Patrick Palka <ppalka@redhat.com> | 2023-12-14 10:18:48 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2023-12-14 10:18:48 -0500 |
commit | 83088b331cde0843d65d316e554873ef6d7b6bca (patch) | |
tree | 1754c8a755e1ffcc6fb44de99142316005ef6506 /gcc/testsuite/g++.dg/cpp23 | |
parent | d782ec8362eadc3169286eb1e39c631effd02323 (diff) | |
download | gcc-83088b331cde0843d65d316e554873ef6d7b6bca.zip gcc-83088b331cde0843d65d316e554873ef6d7b6bca.tar.gz gcc-83088b331cde0843d65d316e554873ef6d7b6bca.tar.bz2 |
c++: Implement P2582R1, CTAD from inherited constructors
This patch implements C++23 class template argument deduction from
inherited constructors, the mechanism for which relies on alias
CTAD which we already fully support. The process for transforming
the return type of an inherited guide is specified in terms of a
partially specialized class template, but this patch implements it in
a simpler way, effectively performing ahead of time deduction instead
of instantiation time deduction. I wasn't able to find an example for
which this implementation strategy makes a difference, but I didn't
look very hard. Support seems good enough to advertise as complete
but there doesn't seem to be a feature-test macro update for this
feature yet. There should be no functional change before C++23 mode.
There's a couple of FIXMEs, one in inherited_ctad_tweaks for recognizing
more forms of inherited constructors, and one in deduction_guides_for for
making the cache aware of base-class dependencies.
gcc/cp/ChangeLog:
* cp-tree.h (type_targs_deducible_from): Adjust return type.
* pt.cc (alias_ctad_tweaks): Also handle C++23 inherited CTAD.
(inherited_ctad_tweaks): Define.
(type_targs_deducible_from): Return the deduced arguments or
NULL_TREE instead of a bool. Handle 'tmpl' being a TREE_LIST
representing a synthetic alias template.
(ctor_deduction_guides_for): Do inherited_ctad_tweaks for each
USING_DECL in C++23 mode.
(deduction_guides_for): Add FIXME for stale cache entries in
light of inherited CTAD.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/class-deduction67.C: Accept in C++23 mode.
* g++.dg/cpp23/class-deduction-inherited1.C: New test.
* g++.dg/cpp23/class-deduction-inherited2.C: New test.
* g++.dg/cpp23/class-deduction-inherited3.C: New test.
* g++.dg/cpp23/class-deduction-inherited4.C: New test.
Diffstat (limited to 'gcc/testsuite/g++.dg/cpp23')
4 files changed, 112 insertions, 0 deletions
diff --git a/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C new file mode 100644 index 0000000..5fd1270 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C @@ -0,0 +1,38 @@ +// Modified example from P2582R1 +// { dg-do compile { target c++23 } } + +template <typename T> struct B { + B(T); +}; +B(bool) -> B<char>; +template <typename T> struct C : public B<T> { + using B<T>::B; +}; +template <typename T> struct D : public B<T> {}; + +C c(42); // OK, deduces C<int> +using ty1 = decltype(c); +using ty1 = C<int>; + +D d(42); // { dg-error "deduction|no match" } + +C c2(true); // OK, deduces C<char> +using ty2 = decltype(c2); +using ty2 = C<char>; + +template <typename T> struct E : public B<int> { + using B<int>::B; +}; + +E e(42); // { dg-error "deduction|no match" } + +template <typename T, typename U, typename V> struct F { + F(T, U, V); +}; +template <typename T, typename U> struct G : F<U, T, int> { + using F<U, T, int>::F; +}; + +G g(true, 'a', 1); // OK, deduces G<char, bool> +using ty3 = decltype(g); +using ty3 = G<char, bool>; diff --git a/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C new file mode 100644 index 0000000..cb3c595 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C @@ -0,0 +1,26 @@ +// { dg-do compile { target c++23 } } + +template<class T, class U, class V> struct F { + F(T, U, V); // #1 + F(T*, U*, V*); // #2 + template<class W> + F(int, int, W); // #3 +}; + +F(bool, bool, bool) -> F<bool*, void*, int>; + +template<class T, class U> struct G : F<U, T, int> { + using F<U, T, int>::F; +}; + +using ty1 = decltype(G(true, 'a', 1)); // uses #1 +using ty1 = G<char, bool>; + +using ty2 = decltype(G((bool*)0, (char*)0, (int*)0)); // uses #2 +using ty2 = G<char, bool>; + +using ty3 = decltype(G(0, 0, 0)); // uses #3 +using ty3 = G<int, int>; + +using ty4 = decltype(G(true, true, true)); // uses #4 +using ty4 = G<void*, bool*>; diff --git a/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C new file mode 100644 index 0000000..57e323b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++23 } } + +template<class T> +struct A { + A(T); + template<class U> A(T, U); +}; + +template<class T> +struct B : A<const T> { + using A<const T>::A; +}; + +using type = decltype(B(0)); +using type = decltype(B(0, 0)); +using type = B<int>; diff --git a/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C new file mode 100644 index 0000000..5e3a7f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C @@ -0,0 +1,32 @@ +// { dg-do compile { target c++23 } } + +template<class T> +struct A { A(T); }; + +template<class T> +struct B : A<T> { + using B::A::A; // FIXME: we don't notice this inherited ctor +}; + +using ty1 = decltype(B(0)); // { dg-bogus "" "" { xfail *-*-* } } +using ty1 = B<int>; + +template<class T=void> +struct C : A<int> { + using A<int>::A; // FIXME: we don't notice this one either +}; + +using ty2 = decltype(C(0)); // { dg-bogus "" "" { xfail *-*-* } } +using ty2 = C<void>; + +template<class T> +struct D : A<T> { + using A<T>::A; +}; + +using ty3 = decltype(D(0)); +using ty3 = D<int>; + +A(int) -> A<char>; // FIXME: we need to rebuild the guides of D +using ty4 = decltype(D(0)); +using ty4 = D<char>; // { dg-bogus "conflicting" "" { xfail *-*-* } } |