| // RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s |
| |
| namespace t1 { |
| template<int N> struct A { |
| template<class C> friend auto cica(const A<N-1>&, C) { |
| return N; |
| } |
| }; |
| |
| template<> struct A<0> { |
| template<class C> friend auto cica(const A<0>&, C); |
| // expected-note@-1 {{declared here}} |
| }; |
| |
| void test() { |
| cica(A<0>{}, 0); |
| // expected-error@-1 {{function 'cica<int>' with deduced return type cannot be used before it is defined}} |
| |
| (void)A<1>{}; |
| cica(A<0>{}, 0); |
| } |
| } // namespace t1 |
| namespace t2 { |
| template<int N> struct A { |
| template<class C> friend auto cica(const A<N-1>&, C) { |
| return N; |
| } |
| }; |
| |
| template<> struct A<0> { |
| template<class C> friend auto cica(const A<0>&, C); |
| }; |
| |
| template <int N, class = decltype(cica(A<N>{}, nullptr))> |
| void MakeCica(); |
| // expected-note@-1 {{candidate function}} |
| |
| template <int N> void MakeCica(A<N+1> = {}); |
| // expected-note@-1 {{candidate function}} |
| |
| void test() { |
| MakeCica<0>(); |
| |
| MakeCica<0>(); |
| // expected-error@-1 {{call to 'MakeCica' is ambiguous}} |
| } |
| } // namespace t2 |
| namespace t3 { |
| template<int N> struct A { |
| template<class C> friend auto cica(const A<N-1>&, C) { |
| return N-1; |
| } |
| }; |
| |
| template<> struct A<0> { |
| template<class C> friend auto cica(const A<0>&, C); |
| }; |
| |
| template <int N, class AT, class = decltype(cica(AT{}, nullptr))> |
| static constexpr bool MakeCica(int); |
| |
| template <int N, class AT> |
| static constexpr bool MakeCica(short, A<N+1> = {}); |
| |
| template <int N, class AT = A<N>, class Val = decltype(MakeCica<N, AT>(0))> |
| static constexpr bool has_cica = Val{}; |
| |
| constexpr bool cica2 = has_cica<0> || has_cica<0>; |
| } // namespace t3 |
| namespace t4 { |
| template<int N> struct A { |
| template<class C> friend auto cica(const A<N-1>&, C); |
| }; |
| |
| template<> struct A<0> { |
| template<class C> friend auto cica(const A<0>&, C) { |
| C a; |
| } |
| }; |
| |
| template struct A<1>; |
| |
| void test() { |
| cica(A<0>{}, 0); |
| } |
| } // namespace t4 |
| namespace regression1 { |
| template <class> class A; |
| |
| template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>); |
| |
| template <class> struct A { |
| friend void foo <>(A); |
| }; |
| |
| template struct A<int>; |
| |
| template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>) {} |
| |
| template void foo<int>(A<int>); |
| } // namespace regression1 |
| namespace regression2 { |
| template <class> struct A { |
| template <class T> static void f() { |
| A<int>::f<T>(); |
| } |
| }; |
| template <> template <class T> void A<int>::f() { |
| static_assert(__is_same(T, long)); |
| } |
| template void A<void>::f<long>(); |
| } // namespace regression2 |
| |
| namespace GH139226 { |
| |
| struct FakeStream {}; |
| |
| template <typename T> |
| class BinaryTree; |
| |
| template <typename T> |
| FakeStream& operator<<(FakeStream& os, BinaryTree<T>& b); |
| |
| template <typename T> |
| FakeStream& operator>>(FakeStream& os, BinaryTree<T>& b) { |
| return os; |
| } |
| |
| template <typename T> |
| struct BinaryTree { |
| T* root{}; |
| friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) { |
| // expected-error@-1 {{friend function specialization cannot be defined}} |
| return os; |
| } |
| |
| friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&); |
| }; |
| |
| void foo() { |
| FakeStream fakeout; |
| BinaryTree<int> a{}; |
| fakeout << a; |
| fakeout >> a; |
| } |
| |
| } |