Skip to content

Commit 9661a6d

Browse files
committed
bugfix1
1 parent bed0423 commit 9661a6d

File tree

1 file changed

+158
-74
lines changed

1 file changed

+158
-74
lines changed

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 158 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,7 @@ DeduceTemplateArguments(Sema &S,
10761076
// Pi of the respective parameter-type- list of P is compared with the
10771077
// corresponding parameter type Ai of the corresponding parameter-type-list
10781078
// of A. [...]
1079+
Sema::TemplateDeductionResult::TDK_NonDeducedMismatch;
10791080
unsigned ArgIdx = 0, ParamIdx = 0;
10801081
for (; ParamIdx != NumParams; ++ParamIdx) {
10811082
// Check argument types.
@@ -5293,10 +5294,31 @@ bool Sema::CheckIfFunctionSpecializationIsImmediate(FunctionDecl *FD,
52935294
return false;
52945295
}
52955296

5297+
static void
5298+
AddImplicitObjectParameterTypeCXX20(ASTContext &Context,
5299+
const CXXMethodDecl *Method,
5300+
bool isOtherRvr,
5301+
SmallVectorImpl<QualType> &ArgTypes) {
5302+
//- The type X(M ) is “rvalue reference to cv A” if the optional ref-qualifier of M is && or if M has no
5303+
// ref-qualifier and the positionally-corresponding parameter of the other transformed template has rvalue
5304+
// reference type; if this determination depends recursively upon whether X(M ) is an rvalue reference
5305+
// type, it is not considered to have rvalue reference type.
5306+
//- Otherwise, X(M ) is “lvalue reference to cv A”.
5307+
assert(Method && !Method->isExplicitObjectMemberFunction()&&" ");
5308+
5309+
QualType ArgTy = Context.getTypeDeclType(Method->getParent());
5310+
ArgTy = Context.getQualifiedType(ArgTy, Method->getMethodQualifiers());
5311+
if (Method->getRefQualifier() == RQ_RValue || (isOtherRvr && Method->getRefQualifier()==RQ_None))
5312+
ArgTy = Context.getRValueReferenceType(ArgTy);
5313+
else
5314+
ArgTy = Context.getLValueReferenceType(ArgTy);
5315+
ArgTypes.push_back(ArgTy);
5316+
5317+
}
52965318
/// If this is a non-static member function,
52975319
static void
52985320
AddImplicitObjectParameterType(ASTContext &Context,
5299-
CXXMethodDecl *Method,
5321+
const CXXMethodDecl *Method,
53005322
SmallVectorImpl<QualType> &ArgTypes) {
53015323
// C++11 [temp.func.order]p3:
53025324
// [...] The new parameter is of type "reference to cv A," where cv are
@@ -5320,11 +5342,13 @@ AddImplicitObjectParameterType(ASTContext &Context,
53205342
/// specialized as \p FT2.
53215343
static bool isAtLeastAsSpecializedAs(Sema &S,
53225344
SourceLocation Loc,
5323-
FunctionTemplateDecl *FT1,
5324-
FunctionTemplateDecl *FT2,
5345+
const FunctionTemplateDecl *FT1,
5346+
const FunctionTemplateDecl *FT2,
53255347
TemplatePartialOrderingContext TPOC,
53265348
unsigned NumCallArguments1,
5327-
bool Reversed) {
5349+
bool Reversed,
5350+
const SmallVector<QualType, 4>& Args1,
5351+
const SmallVector<QualType, 4>& Args2) {
53285352
assert(!Reversed || TPOC == TPOC_Call);
53295353

53305354
FunctionDecl *FD1 = FT1->getTemplatedDecl();
@@ -5341,66 +5365,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
53415365
// The types used to determine the ordering depend on the context in which
53425366
// the partial ordering is done:
53435367
TemplateDeductionInfo Info(Loc);
5344-
SmallVector<QualType, 4> Args2;
53455368
switch (TPOC) {
53465369
case TPOC_Call: {
5347-
// - In the context of a function call, the function parameter types are
5348-
// used.
5349-
CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
5350-
CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
5351-
5352-
// C++11 [temp.func.order]p3:
5353-
// [...] If only one of the function templates is a non-static
5354-
// member, that function template is considered to have a new
5355-
// first parameter inserted in its function parameter list. The
5356-
// new parameter is of type "reference to cv A," where cv are
5357-
// the cv-qualifiers of the function template (if any) and A is
5358-
// the class of which the function template is a member.
5359-
//
5360-
// Note that we interpret this to mean "if one of the function
5361-
// templates is a non-static member and the other is a non-member";
5362-
// otherwise, the ordering rules for static functions against non-static
5363-
// functions don't make any sense.
5364-
//
5365-
// C++98/03 doesn't have this provision but we've extended DR532 to cover
5366-
// it as wording was broken prior to it.
5367-
SmallVector<QualType, 4> Args1;
5368-
5369-
unsigned NumComparedArguments = NumCallArguments1;
5370-
5371-
if (!Method2 && Method1 && Method1->isImplicitObjectMemberFunction()) {
5372-
// Compare 'this' from Method1 against first parameter from Method2.
5373-
AddImplicitObjectParameterType(S.Context, Method1, Args1);
5374-
++NumComparedArguments;
5375-
} else if (!Method1 && Method2 &&
5376-
Method2->isImplicitObjectMemberFunction()) {
5377-
// Compare 'this' from Method2 against first parameter from Method1.
5378-
AddImplicitObjectParameterType(S.Context, Method2, Args2);
5379-
} else if (Method1 && Method2 && Reversed &&
5380-
Method1->isImplicitObjectMemberFunction() &&
5381-
Method2->isImplicitObjectMemberFunction()) {
5382-
// Compare 'this' from Method1 against second parameter from Method2
5383-
// and 'this' from Method2 against second parameter from Method1.
5384-
AddImplicitObjectParameterType(S.Context, Method1, Args1);
5385-
AddImplicitObjectParameterType(S.Context, Method2, Args2);
5386-
++NumComparedArguments;
5387-
}
5388-
5389-
Args1.insert(Args1.end(), Proto1->param_type_begin(),
5390-
Proto1->param_type_end());
5391-
Args2.insert(Args2.end(), Proto2->param_type_begin(),
5392-
Proto2->param_type_end());
5393-
5394-
// C++ [temp.func.order]p5:
5395-
// The presence of unused ellipsis and default arguments has no effect on
5396-
// the partial ordering of function templates.
5397-
if (Args1.size() > NumComparedArguments)
5398-
Args1.resize(NumComparedArguments);
5399-
if (Args2.size() > NumComparedArguments)
5400-
Args2.resize(NumComparedArguments);
5401-
if (Reversed)
5402-
std::reverse(Args2.begin(), Args2.end());
5403-
54045370
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
54055371
Args1.data(), Args1.size(), Info, Deduced,
54065372
TDF_None, /*PartialOrdering=*/true))
@@ -5508,11 +5474,97 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
55085474
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
55095475
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
55105476
unsigned NumCallArguments2, bool Reversed) {
5477+
5478+
SmallVector<QualType, 4> Args1;
5479+
SmallVector<QualType, 4> Args2;
5480+
const FunctionDecl *FD1 = FT1->getTemplatedDecl();
5481+
const FunctionDecl *FD2 = FT2->getTemplatedDecl();
5482+
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
5483+
const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
5484+
5485+
// - In the context of a function call, the function parameter types are
5486+
// used.
5487+
const CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
5488+
const CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
5489+
5490+
bool shouldConvert1;
5491+
bool shouldConvert2;
5492+
if (getLangOpts().CPlusPlus20){
5493+
// C++20 [temp.func.order]p3
5494+
// [...] Each function template M that is a member function is considered to have a new first parameter of type
5495+
// X(M), described below, inserted in its function parameter list.
5496+
//
5497+
// Note that we interpret "that is a member function" as
5498+
// "that is a member function with no expicit object argument".
5499+
// Otherwise the ordering rules for methods with expicit objet arguments
5500+
// against anything else make no sense.
5501+
shouldConvert1= Method1 && !Method1->isExplicitObjectMemberFunction();
5502+
shouldConvert2= Method2 && !Method2->isExplicitObjectMemberFunction();
5503+
bool isR1=Method1 && !Method1->isExplicitObjectMemberFunction() ?
5504+
Method1->getRefQualifier() == RQ_RValue:
5505+
//Proto1->getRefQualifier() ==RQ_RValue;
5506+
Proto1->param_type_begin()[0]->isRValueReferenceType();
5507+
bool isR2=Method2 && !Method2->isExplicitObjectMemberFunction() ?
5508+
Method2->getRefQualifier() == RQ_RValue:
5509+
Proto2->param_type_begin()[0]->isRValueReferenceType();
5510+
//FD2->getParamDecl(0)->getRefQualifier() ==RQ_RValue;
5511+
if (shouldConvert1)
5512+
// Compare 'this' from Method1 against first parameter from Method2.
5513+
AddImplicitObjectParameterTypeCXX20(this->Context, Method1,isR2, Args1);
5514+
if (shouldConvert2)
5515+
// Compare 'this' from Method2 against first parameter from Method1.
5516+
AddImplicitObjectParameterTypeCXX20(this->Context, Method2,isR1, Args2);
5517+
}else{
5518+
// C++11 [temp.func.order]p3:
5519+
// [...] If only one of the function templates is a non-static
5520+
// member, that function template is considered to have a new
5521+
// first parameter inserted in its function parameter list. The
5522+
// new parameter is of type "reference to cv A," where cv are
5523+
// the cv-qualifiers of the function template (if any) and A is
5524+
// the class of which the function template is a member.
5525+
//
5526+
// Note that we interpret this to mean "if one of the function
5527+
// templates is a non-static member and the other is a non-member";
5528+
// otherwise, the ordering rules for static functions against non-static
5529+
// functions don't make any sense.
5530+
//
5531+
// C++98/03 doesn't have this provision but we've extended DR532 to cover
5532+
// it as wording was broken prior to it.
5533+
shouldConvert1=!Method2 && Method1 && Method1->isImplicitObjectMemberFunction();
5534+
shouldConvert2=!Method1 && Method2 && Method2->isImplicitObjectMemberFunction();
5535+
if (shouldConvert1)
5536+
// Compare 'this' from Method1 against first parameter from Method2.
5537+
AddImplicitObjectParameterType(this->Context, Method1, Args1);
5538+
if (shouldConvert2)
5539+
// Compare 'this' from Method2 against first parameter from Method1.
5540+
AddImplicitObjectParameterType(this->Context, Method2, Args2);
5541+
}
5542+
unsigned NumComparedArguments = NumCallArguments1 + shouldConvert1;
5543+
5544+
Args1.insert(Args1.end(), Proto1->param_type_begin(),
5545+
Proto1->param_type_end());
5546+
Args2.insert(Args2.end(), Proto2->param_type_begin(),
5547+
Proto2->param_type_end());
5548+
5549+
// C++ [temp.func.order]p5:
5550+
// The presence of unused ellipsis and default arguments has no effect on
5551+
// the partial ordering of function templates.
5552+
if (Args1.size() > NumComparedArguments)
5553+
Args1.resize(NumComparedArguments);
5554+
if (Args2.size() > NumComparedArguments)
5555+
Args2.resize(NumComparedArguments);
5556+
if (Reversed)
5557+
std::reverse(Args2.begin(), Args2.end());
55115558

55125559
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
5513-
NumCallArguments1, Reversed);
5560+
NumCallArguments1, Reversed,Args1,Args2);
55145561
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
5515-
NumCallArguments2, Reversed);
5562+
NumCallArguments2, Reversed,Args2,Args1);
5563+
FT1->dump();
5564+
llvm::errs()<<"---\n";
5565+
FT2->dump();
5566+
llvm::errs()<<"---"<<NumCallArguments1<<" "<<NumCallArguments2<<"\n";
5567+
llvm::errs()<<"---"<<Better1<<" "<<Better2<<"\n";
55165568

55175569
// C++ [temp.deduct.partial]p10:
55185570
// F is more specialized than G if F is at least as specialized as G and G
@@ -5527,24 +5579,55 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
55275579
// ... and if G has a trailing function parameter pack for which F does not
55285580
// have a corresponding parameter, and if F does not have a trailing
55295581
// function parameter pack, then F is more specialized than G.
5530-
FunctionDecl *FD1 = FT1->getTemplatedDecl();
5531-
FunctionDecl *FD2 = FT2->getTemplatedDecl();
5532-
unsigned NumParams1 = FD1->getNumParams();
5582+
5583+
SmallVector<ParmVarDecl*> param1;
5584+
if (shouldConvert1){
5585+
param1.push_back({});//TODO
5586+
}
5587+
param1.insert(param1.end(), FD1->parameters().begin(),
5588+
FD1->parameters().end());
5589+
5590+
SmallVector<ParmVarDecl*> param2;
5591+
if (shouldConvert2){
5592+
param2.push_back({});//TODO
5593+
}
5594+
param2.insert(param2.end(), FD2->parameters().begin(),
5595+
FD2->parameters().end());
5596+
5597+
unsigned NumParams1 = param1.size();
5598+
unsigned NumParams2 = param2.size();
5599+
/*unsigned NumParams1 = FD1->getNumParams();
55335600
unsigned NumParams2 = FD2->getNumParams();
5601+
5602+
if (Method1) {
5603+
llvm::errs()<<"METHOD1:";
5604+
Method1->dump();
5605+
for (const auto& x:Method1->parameters()){
5606+
x->dump();
5607+
}
5608+
llvm::errs()<<"#";
5609+
Method1->getNonObjectParameter(0)->dump();
5610+
llvm::errs()<<"=#";
5611+
Method1->getThisType().dump();
5612+
llvm::errs()<<"#=";
5613+
Method1->getType().dump();
5614+
}*/
55345615
bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack();
55355616
bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack();
55365617
if (Variadic1 != Variadic2) {
5537-
if (Variadic1 && NumParams1 > NumParams2)
5618+
if (Variadic1 && NumParams1 + shouldConvert1 > NumParams2 + shouldConvert2)
55385619
return FT2;
5539-
if (Variadic2 && NumParams2 > NumParams1)
5620+
if (Variadic2 && NumParams2 + shouldConvert2 > NumParams1 + shouldConvert1)
55405621
return FT1;
55415622
}
55425623

55435624
// This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
55445625
// there is no wording or even resolution for this issue.
55455626
for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) {
5546-
QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType();
5547-
QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType();
5627+
if (!param1[i] || !param2[i])
5628+
continue;
5629+
QualType T1 = param1[i]->getType().getCanonicalType();
5630+
QualType T2 = param2[i]->getType().getCanonicalType();
55485631
auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
55495632
auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
55505633
if (!TST1 || !TST2)
@@ -5600,9 +5683,10 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
56005683
return nullptr;
56015684

56025685
for (unsigned i = 0; i < NumParams1; ++i)
5603-
if (!Context.hasSameType(FD1->getParamDecl(i)->getType(),
5604-
FD2->getParamDecl(i)->getType()))
5605-
return nullptr;
5686+
if (param1[i] && param2[i])//TODO: write in from args
5687+
if (!Context.hasSameType(param1[i]->getType(),
5688+
param2[i]->getType()))
5689+
return nullptr;
56065690

56075691
// C++20 [temp.func.order]p6.3:
56085692
// Otherwise, if the context in which the partial ordering is done is

0 commit comments

Comments
 (0)