forked from OSchip/llvm-project
PR17075: When performing partial ordering of a member function against a
non-member function, the number of arguments in the two candidate calls will be different (the non-member call will have one extra argument). We used to get confused by this, and fail to compare the last argument when testing whether the member is better, resulting in us always thinking it is, even if the non-member is more specialized in the last argument. llvm-svn: 190470
This commit is contained in:
parent
9a40ae8935
commit
e5b5220072
|
@ -5832,7 +5832,8 @@ public:
|
||||||
FunctionTemplateDecl *FT2,
|
FunctionTemplateDecl *FT2,
|
||||||
SourceLocation Loc,
|
SourceLocation Loc,
|
||||||
TemplatePartialOrderingContext TPOC,
|
TemplatePartialOrderingContext TPOC,
|
||||||
unsigned NumCallArguments);
|
unsigned NumCallArguments1,
|
||||||
|
unsigned NumCallArguments2);
|
||||||
UnresolvedSetIterator
|
UnresolvedSetIterator
|
||||||
getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd,
|
getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd,
|
||||||
TemplateSpecCandidateSet &FailedCandidates,
|
TemplateSpecCandidateSet &FailedCandidates,
|
||||||
|
|
|
@ -7962,7 +7962,8 @@ isBetterOverloadCandidate(Sema &S,
|
||||||
Loc,
|
Loc,
|
||||||
isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
|
isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
|
||||||
: TPOC_Call,
|
: TPOC_Call,
|
||||||
Cand1.ExplicitCallArguments))
|
Cand1.ExplicitCallArguments,
|
||||||
|
Cand2.ExplicitCallArguments))
|
||||||
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
|
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3979,7 +3979,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
|
||||||
FunctionTemplateDecl *FT1,
|
FunctionTemplateDecl *FT1,
|
||||||
FunctionTemplateDecl *FT2,
|
FunctionTemplateDecl *FT2,
|
||||||
TemplatePartialOrderingContext TPOC,
|
TemplatePartialOrderingContext TPOC,
|
||||||
unsigned NumCallArguments,
|
unsigned NumCallArguments1,
|
||||||
SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
|
SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
|
||||||
FunctionDecl *FD1 = FT1->getTemplatedDecl();
|
FunctionDecl *FD1 = FT1->getTemplatedDecl();
|
||||||
FunctionDecl *FD2 = FT2->getTemplatedDecl();
|
FunctionDecl *FD2 = FT2->getTemplatedDecl();
|
||||||
|
@ -3995,19 +3995,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
|
||||||
// The types used to determine the ordering depend on the context in which
|
// The types used to determine the ordering depend on the context in which
|
||||||
// the partial ordering is done:
|
// the partial ordering is done:
|
||||||
TemplateDeductionInfo Info(Loc);
|
TemplateDeductionInfo Info(Loc);
|
||||||
CXXMethodDecl *Method1 = 0;
|
SmallVector<QualType, 4> Args2;
|
||||||
CXXMethodDecl *Method2 = 0;
|
|
||||||
bool IsNonStatic2 = false;
|
|
||||||
bool IsNonStatic1 = false;
|
|
||||||
unsigned Skip2 = 0;
|
|
||||||
switch (TPOC) {
|
switch (TPOC) {
|
||||||
case TPOC_Call: {
|
case TPOC_Call: {
|
||||||
// - In the context of a function call, the function parameter types are
|
// - In the context of a function call, the function parameter types are
|
||||||
// used.
|
// used.
|
||||||
Method1 = dyn_cast<CXXMethodDecl>(FD1);
|
CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
|
||||||
Method2 = dyn_cast<CXXMethodDecl>(FD2);
|
CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
|
||||||
IsNonStatic1 = Method1 && !Method1->isStatic();
|
|
||||||
IsNonStatic2 = Method2 && !Method2->isStatic();
|
|
||||||
|
|
||||||
// C++11 [temp.func.order]p3:
|
// C++11 [temp.func.order]p3:
|
||||||
// [...] If only one of the function templates is a non-static
|
// [...] If only one of the function templates is a non-static
|
||||||
|
@ -4026,26 +4020,39 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
|
||||||
// first argument of the free function, which seems to match
|
// first argument of the free function, which seems to match
|
||||||
// existing practice.
|
// existing practice.
|
||||||
SmallVector<QualType, 4> Args1;
|
SmallVector<QualType, 4> Args1;
|
||||||
unsigned Skip1 = !S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1;
|
|
||||||
if (S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2)
|
unsigned Skip1 = 0, Skip2 = 0;
|
||||||
AddImplicitObjectParameterType(S.Context, Method1, Args1);
|
unsigned NumComparedArguments = NumCallArguments1;
|
||||||
|
|
||||||
|
if (!Method2 && Method1 && !Method1->isStatic()) {
|
||||||
|
if (S.getLangOpts().CPlusPlus11) {
|
||||||
|
// Compare 'this' from Method1 against first parameter from Method2.
|
||||||
|
AddImplicitObjectParameterType(S.Context, Method1, Args1);
|
||||||
|
++NumComparedArguments;
|
||||||
|
} else
|
||||||
|
// Ignore first parameter from Method2.
|
||||||
|
++Skip2;
|
||||||
|
} else if (!Method1 && Method2 && !Method2->isStatic()) {
|
||||||
|
if (S.getLangOpts().CPlusPlus11)
|
||||||
|
// Compare 'this' from Method2 against first parameter from Method1.
|
||||||
|
AddImplicitObjectParameterType(S.Context, Method2, Args2);
|
||||||
|
else
|
||||||
|
// Ignore first parameter from Method1.
|
||||||
|
++Skip1;
|
||||||
|
}
|
||||||
|
|
||||||
Args1.insert(Args1.end(),
|
Args1.insert(Args1.end(),
|
||||||
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
|
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
|
||||||
|
|
||||||
SmallVector<QualType, 4> Args2;
|
|
||||||
Skip2 = !S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2;
|
|
||||||
if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1)
|
|
||||||
AddImplicitObjectParameterType(S.Context, Method2, Args2);
|
|
||||||
Args2.insert(Args2.end(),
|
Args2.insert(Args2.end(),
|
||||||
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
|
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
|
||||||
|
|
||||||
// C++ [temp.func.order]p5:
|
// C++ [temp.func.order]p5:
|
||||||
// The presence of unused ellipsis and default arguments has no effect on
|
// The presence of unused ellipsis and default arguments has no effect on
|
||||||
// the partial ordering of function templates.
|
// the partial ordering of function templates.
|
||||||
if (Args1.size() > NumCallArguments)
|
if (Args1.size() > NumComparedArguments)
|
||||||
Args1.resize(NumCallArguments);
|
Args1.resize(NumComparedArguments);
|
||||||
if (Args2.size() > NumCallArguments)
|
if (Args2.size() > NumComparedArguments)
|
||||||
Args2.resize(NumCallArguments);
|
Args2.resize(NumComparedArguments);
|
||||||
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
|
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
|
||||||
Args1.data(), Args1.size(), Info, Deduced,
|
Args1.data(), Args1.size(), Info, Deduced,
|
||||||
TDF_None, /*PartialOrdering=*/true,
|
TDF_None, /*PartialOrdering=*/true,
|
||||||
|
@ -4099,20 +4106,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
|
||||||
// Figure out which template parameters were used.
|
// Figure out which template parameters were used.
|
||||||
llvm::SmallBitVector UsedParameters(TemplateParams->size());
|
llvm::SmallBitVector UsedParameters(TemplateParams->size());
|
||||||
switch (TPOC) {
|
switch (TPOC) {
|
||||||
case TPOC_Call: {
|
case TPOC_Call:
|
||||||
unsigned NumParams = std::min(NumCallArguments,
|
for (unsigned I = 0, N = Args2.size(); I != N; ++I)
|
||||||
std::min(Proto1->getNumArgs(),
|
::MarkUsedTemplateParameters(S.Context, Args2[I], false,
|
||||||
Proto2->getNumArgs()));
|
|
||||||
if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !IsNonStatic1)
|
|
||||||
::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
|
|
||||||
false,
|
|
||||||
TemplateParams->getDepth(), UsedParameters);
|
|
||||||
for (unsigned I = Skip2; I < NumParams; ++I)
|
|
||||||
::MarkUsedTemplateParameters(S.Context, Proto2->getArgType(I), false,
|
|
||||||
TemplateParams->getDepth(),
|
TemplateParams->getDepth(),
|
||||||
UsedParameters);
|
UsedParameters);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case TPOC_Conversion:
|
case TPOC_Conversion:
|
||||||
::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
|
::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
|
||||||
|
@ -4167,8 +4166,11 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
|
||||||
/// \param TPOC the context in which we are performing partial ordering of
|
/// \param TPOC the context in which we are performing partial ordering of
|
||||||
/// function templates.
|
/// function templates.
|
||||||
///
|
///
|
||||||
/// \param NumCallArguments The number of arguments in a call, used only
|
/// \param NumCallArguments1 The number of arguments in the call to FT1, used
|
||||||
/// when \c TPOC is \c TPOC_Call.
|
/// only when \c TPOC is \c TPOC_Call.
|
||||||
|
///
|
||||||
|
/// \param NumCallArguments2 The number of arguments in the call to FT2, used
|
||||||
|
/// only when \c TPOC is \c TPOC_Call.
|
||||||
///
|
///
|
||||||
/// \returns the more specialized function template. If neither
|
/// \returns the more specialized function template. If neither
|
||||||
/// template is more specialized, returns NULL.
|
/// template is more specialized, returns NULL.
|
||||||
|
@ -4177,12 +4179,13 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||||
FunctionTemplateDecl *FT2,
|
FunctionTemplateDecl *FT2,
|
||||||
SourceLocation Loc,
|
SourceLocation Loc,
|
||||||
TemplatePartialOrderingContext TPOC,
|
TemplatePartialOrderingContext TPOC,
|
||||||
unsigned NumCallArguments) {
|
unsigned NumCallArguments1,
|
||||||
|
unsigned NumCallArguments2) {
|
||||||
SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
|
SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
|
||||||
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
|
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
|
||||||
NumCallArguments, 0);
|
NumCallArguments1, 0);
|
||||||
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
|
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
|
||||||
NumCallArguments,
|
NumCallArguments2,
|
||||||
&RefParamComparisons);
|
&RefParamComparisons);
|
||||||
|
|
||||||
if (Better1 != Better2) // We have a clear winner
|
if (Better1 != Better2) // We have a clear winner
|
||||||
|
@ -4336,7 +4339,7 @@ UnresolvedSetIterator Sema::getMostSpecialized(
|
||||||
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
|
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
|
||||||
assert(Challenger && "Not a function template specialization?");
|
assert(Challenger && "Not a function template specialization?");
|
||||||
if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
|
if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
|
||||||
Loc, TPOC_Other, 0),
|
Loc, TPOC_Other, 0, 0),
|
||||||
Challenger)) {
|
Challenger)) {
|
||||||
Best = I;
|
Best = I;
|
||||||
BestTemplate = Challenger;
|
BestTemplate = Challenger;
|
||||||
|
@ -4351,7 +4354,7 @@ UnresolvedSetIterator Sema::getMostSpecialized(
|
||||||
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
|
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
|
||||||
if (I != Best &&
|
if (I != Best &&
|
||||||
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
|
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
|
||||||
Loc, TPOC_Other, 0),
|
Loc, TPOC_Other, 0, 0),
|
||||||
BestTemplate)) {
|
BestTemplate)) {
|
||||||
Ambiguous = true;
|
Ambiguous = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -43,3 +43,10 @@ namespace OrderWithStaticMember {
|
||||||
a.g(p);
|
a.g(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PR17075 {
|
||||||
|
template <typename T> struct V {};
|
||||||
|
struct S { template<typename T> S &operator>>(T &t) = delete; };
|
||||||
|
template<typename T> S &operator>>(S &s, V<T> &v);
|
||||||
|
void f(S s, V<int> v) { s >> v; }
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue