1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// 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;
}
}
|