This fixes instantiation of definition for friend function templates, when the declaration found and the one containing the definition have different template contexts. In these cases, the the function declaration corresponding to the definition is not available; it may not even be instantiated at all. So this patch adds a bit which tracks which function template declaration was instantiated from the member template. It's used to find which primary template serves as a context for the purpose of obtainining the template arguments needed to instantiate the definition. Fixes #55509 Relanding patch, with no changes, after it was reverted due to revert of commit this patch depended on.
102 lines
2.3 KiB
C++
102 lines
2.3 KiB
C++
// 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
|