Files
clang-p2996/clang/test/SemaTemplate/GH55509.cpp
Matheus Izvekov 07a0e2be86 [clang] Track function template instantiation from definition (#112241)
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.
2025-01-29 17:23:36 -03:00

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