llvm-project/clang/test/SemaTemplate/instantiate-function-params.cpp
cor3ntin 8c5a307bd8
[Clang] Bypass TAD during overload resolution if a perfect match exists (#136203)
This implements the same overload resolution behavior as GCC,
as described in https://wg21.link/p3606 (section 1-2, not 3)

If during overload resolution, there is a non-template candidate
that would be always be picked - because each of the argument
is a perfect match (ie the source and target types are the same),
we do not perform deduction for any template candidate
that might exists.

The goal is to be able to merge
https://github.com/llvm/llvm-project/pull/122423 without being too
disruptive.

This change means that the selection of the best viable candidate and
template argument deduction become interleaved.

To avoid rewriting half of Clang we store in OverloadCandidateSet
enough information to be able to deduce template candidates from
OverloadCandidateSet::BestViableFunction. Which means
the lifetime of any object used by template argument must outlive
a call to Add*Template*Candidate.

This two phase resolution is not performed for some initialization
as there are cases where template candidate are better match
in these cases per the standard. It's also bypassed for code completion.

The change has a nice impact on compile times

https://llvm-compile-time-tracker.com/compare.php?from=719b029c16eeb1035da522fd641dfcc4cee6be74&to=bf7041045c9408490c395230047c5461de72fc39&stat=instructions%3Au

Fixes https://github.com/llvm/llvm-project/issues/62096
Fixes https://github.com/llvm/llvm-project/issues/74581

Reapplies https://github.com/llvm/llvm-project/pull/133426
2025-04-18 06:10:58 +02:00

101 lines
3.4 KiB
C++

// RUN: %clang_cc1 -triple i686-unknown-unknown -fsyntax-only -verify %s
// PR6619
template<bool C> struct if_c { };
template<typename T1> struct if_ {
typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 7{{in instantiation}}
};
template <class Model, void (Model::*)()> struct wrap_constraints { };
template <class Model>
inline char has_constraints_(Model* , // expected-note 3{{candidate template ignored}}
wrap_constraints<Model,&Model::constraints>* = 0);
template <class Model> struct not_satisfied {
static const bool value = sizeof( has_constraints_((Model*)0) == 1); // expected-error 3{{no matching function}} \
// expected-note 4{{in instantiation}}
};
template <class ModelFn> struct requirement_;
template <void(*)()> struct instantiate {
};
template <class Model> struct requirement_<void(*)(Model)> : if_< not_satisfied<Model> >::type { // expected-error 3{{no type named 'type' in}} expected-note 7{{in instantiation}}
};
template <class Model> struct usage_requirements {
};
template < typename TT > struct InputIterator {
typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note 2{{in instantiation}}
};
template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note 2{{in instantiation}}
typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note 2{{in instantiation}}
};
typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX;// expected-note 6{{in instantiation}}
template<typename T> struct X0 { };
template<typename R, typename A1> struct X0<R(A1 param)> { };
template<typename T, typename A1, typename A2>
void instF0(X0<T(A1)> x0a, X0<T(A2)> x0b) {
X0<T(A1)> x0c;
X0<T(A2)> x0d;
}
template void instF0<int, int, float>(X0<int(int)>, X0<int(float)>);
template<typename R, typename A1, R (*ptr)(A1)> struct FuncPtr { };
template<typename A1, int (*ptr)(A1)> struct FuncPtr<int, A1, ptr> { };
template<typename R, typename A1> R unary_func(A1);
template<typename R, typename A1, typename A2>
void use_func_ptr() {
FuncPtr<R, A1, &unary_func<R, A1> > fp1;
FuncPtr<R, A2, &unary_func<R, A2> > fp2;
};
template void use_func_ptr<int, float, double>();
namespace PR6990 {
template < typename , typename = int, typename = int > struct X1;
template <typename >
struct X2;
template <typename = int *, typename TokenT = int,
typename = int( X2<TokenT> &)>
struct X3
{
};
template <typename , typename P>
struct X3_base : X3< X1<int, P> >
{
protected: typedef X1< P> type;
X3<type> e;
};
struct r : X3_base<int, int>
{
};
}
namespace InstantiateFunctionTypedef {
template<typename T>
struct X {
typedef int functype(int, int);
functype func1;
__attribute__((noreturn)) functype func2;
typedef int stdfunctype(int, int) __attribute__((stdcall));
__attribute__((stdcall)) functype stdfunc1;
stdfunctype stdfunc2;
__attribute__((pcs("aapcs"))) functype pcsfunc; // expected-warning {{'pcs' calling convention is not supported for this target}}
};
void f(X<int> x) {
(void)x.func1(1, 2);
(void)x.func2(1, 2);
(void)x.stdfunc1(1, 2);
(void)x.stdfunc2(1, 2);
(void)x.pcsfunc(1, 2);
}
}