
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
101 lines
3.4 KiB
C++
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);
|
|
}
|
|
}
|