forked from OSchip/llvm-project
Implement support for calling member function templates, which involves:
- Allowing one to name a member function template within a class template and on the right-hand side of a member access expression. - Template argument deduction for calls to member function templates. - Registering specializations of member function templates (and finding them later). llvm-svn: 79581
This commit is contained in:
parent
d5eaa05a7f
commit
97628d6a4c
|
@ -804,6 +804,14 @@ public:
|
|||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool ForceRValue = false);
|
||||
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
||||
bool HasExplicitTemplateArgs,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
Expr *Object, Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool ForceRValue = false);
|
||||
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
|
||||
bool HasExplicitTemplateArgs,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
|
|
|
@ -939,18 +939,35 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
|
|||
Ctx = Method->getParent();
|
||||
MemberType = Method->getType();
|
||||
}
|
||||
} else if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(D)) {
|
||||
if (CXXMethodDecl *Method
|
||||
= dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) {
|
||||
if (!Method->isStatic()) {
|
||||
Ctx = Method->getParent();
|
||||
MemberType = Context.OverloadTy;
|
||||
}
|
||||
}
|
||||
} else if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(D)) {
|
||||
// FIXME: We need an abstraction for iterating over one or more function
|
||||
// templates or functions. This code is far too repetitive!
|
||||
for (OverloadedFunctionDecl::function_iterator
|
||||
Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func))
|
||||
if (!DMethod->isStatic()) {
|
||||
Ctx = Ovl->getDeclContext();
|
||||
MemberType = Context.OverloadTy;
|
||||
break;
|
||||
}
|
||||
CXXMethodDecl *DMethod = 0;
|
||||
if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(*Func))
|
||||
DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
|
||||
else
|
||||
DMethod = dyn_cast<CXXMethodDecl>(*Func);
|
||||
|
||||
if (DMethod && !DMethod->isStatic()) {
|
||||
Ctx = DMethod->getDeclContext();
|
||||
MemberType = Context.OverloadTy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2112,6 +2129,13 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
MemberFn, MemberLoc,
|
||||
MemberFn->getType()));
|
||||
}
|
||||
if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
||||
FunTmpl, MemberLoc,
|
||||
Context.OverloadTy));
|
||||
}
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemberDecl))
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
|
||||
|
|
|
@ -2237,6 +2237,48 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Add a C++ member function template as a candidate to the candidate
|
||||
/// set, using template argument deduction to produce an appropriate member
|
||||
/// function template specialization.
|
||||
void
|
||||
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
|
||||
bool HasExplicitTemplateArgs,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
Expr *Object, Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions,
|
||||
bool ForceRValue) {
|
||||
// C++ [over.match.funcs]p7:
|
||||
// In each case where a candidate is a function template, candidate
|
||||
// function template specializations are generated using template argument
|
||||
// deduction (14.8.3, 14.8.2). Those candidates are then handled as
|
||||
// candidate functions in the usual way.113) A given name can refer to one
|
||||
// or more function templates and also to a set of overloaded non-template
|
||||
// functions. In such a case, the candidate functions generated from each
|
||||
// function template are combined with the set of non-template candidate
|
||||
// functions.
|
||||
TemplateDeductionInfo Info(Context);
|
||||
FunctionDecl *Specialization = 0;
|
||||
if (TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs,
|
||||
ExplicitTemplateArgs, NumExplicitTemplateArgs,
|
||||
Args, NumArgs, Specialization, Info)) {
|
||||
// FIXME: Record what happened with template argument deduction, so
|
||||
// that we can give the user a beautiful diagnostic.
|
||||
(void)Result;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the function template specialization produced by template argument
|
||||
// deduction as a candidate.
|
||||
assert(Specialization && "Missing member function template specialization?");
|
||||
assert(isa<CXXMethodDecl>(Specialization) &&
|
||||
"Specialization is not a member function?");
|
||||
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs,
|
||||
CandidateSet, SuppressUserConversions, ForceRValue);
|
||||
}
|
||||
|
||||
/// \brief Add a C++ function template as a candidate in the candidate set,
|
||||
/// using template argument deduction to produce an appropriate function
|
||||
/// template specialization.
|
||||
|
@ -4276,18 +4318,35 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
Expr *ObjectArg = MemExpr->getBase();
|
||||
|
||||
CXXMethodDecl *Method = 0;
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
|
||||
if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
|
||||
isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) {
|
||||
// Add overload candidates
|
||||
OverloadCandidateSet CandidateSet;
|
||||
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
assert(isa<CXXMethodDecl>(*Func) && "Function is not a method");
|
||||
Method = cast<CXXMethodDecl>(*Func);
|
||||
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
}
|
||||
DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
|
||||
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
|
||||
for (OverloadedFunctionDecl::function_iterator
|
||||
Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
if (Method = dyn_cast<CXXMethodDecl>(*Func))
|
||||
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
else
|
||||
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
}
|
||||
} else
|
||||
AddMethodTemplateCandidate(
|
||||
cast<FunctionTemplateDecl>(MemExpr->getMemberDecl()),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) {
|
||||
|
@ -4298,7 +4357,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
case OR_No_Viable_Function:
|
||||
Diag(MemExpr->getSourceRange().getBegin(),
|
||||
diag::err_ovl_no_viable_member_function_in_call)
|
||||
<< Ovl->getDeclName() << MemExprE->getSourceRange();
|
||||
<< DeclName << MemExprE->getSourceRange();
|
||||
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
|
||||
// FIXME: Leaking incoming expressions!
|
||||
return true;
|
||||
|
@ -4306,7 +4365,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
case OR_Ambiguous:
|
||||
Diag(MemExpr->getSourceRange().getBegin(),
|
||||
diag::err_ovl_ambiguous_member_call)
|
||||
<< Ovl->getDeclName() << MemExprE->getSourceRange();
|
||||
<< DeclName << MemExprE->getSourceRange();
|
||||
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
|
||||
// FIXME: Leaking incoming expressions!
|
||||
return true;
|
||||
|
@ -4315,7 +4374,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
Diag(MemExpr->getSourceRange().getBegin(),
|
||||
diag::err_ovl_deleted_member_call)
|
||||
<< Best->Function->isDeleted()
|
||||
<< Ovl->getDeclName() << MemExprE->getSourceRange();
|
||||
<< DeclName << MemExprE->getSourceRange();
|
||||
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
|
||||
// FIXME: Leaking incoming expressions!
|
||||
return true;
|
||||
|
|
|
@ -457,7 +457,26 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
|
|||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
||||
// FIXME: Look for existing, explicit specializations.
|
||||
// Check whether there is already a function template specialization for
|
||||
// this declaration.
|
||||
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
|
||||
void *InsertPos = 0;
|
||||
if (FunctionTemplate) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionTemplateSpecializationInfo::Profile(ID,
|
||||
TemplateArgs.getFlatArgumentList(),
|
||||
TemplateArgs.flat_size(),
|
||||
SemaRef.Context);
|
||||
|
||||
FunctionTemplateSpecializationInfo *Info
|
||||
= FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
|
||||
InsertPos);
|
||||
|
||||
// If we already have a function template specialization, return it.
|
||||
if (Info)
|
||||
return Info->Function;
|
||||
}
|
||||
|
||||
Sema::LocalInstantiationScope Scope(SemaRef);
|
||||
|
||||
llvm::SmallVector<ParmVarDecl *, 4> Params;
|
||||
|
@ -471,7 +490,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
|||
= CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
|
||||
D->getDeclName(), T, D->getDeclaratorInfo(),
|
||||
D->isStatic(), D->isInline());
|
||||
Method->setInstantiationOfMemberFunction(D);
|
||||
|
||||
if (!FunctionTemplate)
|
||||
Method->setInstantiationOfMemberFunction(D);
|
||||
|
||||
// If we are instantiating a member function defined
|
||||
// out-of-line, the instantiation will have the same lexical
|
||||
|
@ -501,8 +522,14 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
|||
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
|
||||
/*FIXME:*/OverloadableAttrRequired);
|
||||
|
||||
if (!Method->isInvalidDecl() || !PrevDecl)
|
||||
Owner->addDecl(Method);
|
||||
if (FunctionTemplate)
|
||||
// Record this function template specialization.
|
||||
Method->setFunctionTemplateSpecialization(SemaRef.Context,
|
||||
FunctionTemplate,
|
||||
&TemplateArgs,
|
||||
InsertPos);
|
||||
else if (!Method->isInvalidDecl() || !PrevDecl)
|
||||
Owner->addDecl(Method);
|
||||
return Method;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,30 @@
|
|||
// RUN: clang-cc -fsyntax-only %s
|
||||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
struct X {
|
||||
template<typename T> T& f(T);
|
||||
template<typename T> T& f0(T);
|
||||
|
||||
void g0(int i, double d) {
|
||||
int &ir = f0(i);
|
||||
double &dr = f0(d);
|
||||
}
|
||||
|
||||
template<typename T> T& f1(T);
|
||||
template<typename T, typename U> U& f1(T, U);
|
||||
|
||||
void g1(int i, double d) {
|
||||
int &ir1 = f1(i);
|
||||
int &ir2 = f1(d, i);
|
||||
int &ir3 = f1(i, i);
|
||||
}
|
||||
};
|
||||
|
||||
void test_X_f0(X x, int i, float f) {
|
||||
int &ir = x.f0(i);
|
||||
float &fr = x.f0(f);
|
||||
}
|
||||
|
||||
void test_X_f1(X x, int i, float f) {
|
||||
int &ir1 = x.f1(i);
|
||||
int &ir2 = x.f1(f, i);
|
||||
int &ir3 = x.f1(i, i);
|
||||
}
|
Loading…
Reference in New Issue