summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-08-21 00:16:32 +0000
committerDouglas Gregor <dgregor@apple.com>2009-08-21 00:16:32 +0000
commit6b906869527be40b0d38d755e9ef51b331b88162 (patch)
tree383418b55d313e27f7e21b20756b8f5347176355
parentc42a92aa1fbd24b7a26c7c29552d07478a8e2045 (diff)
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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79581 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h8
-rw-r--r--lib/Sema/SemaExpr.cpp36
-rw-r--r--lib/Sema/SemaOverload.cpp87
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp35
-rw-r--r--test/SemaTemplate/member-function-template.cpp29
5 files changed, 169 insertions, 26 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f13a87c580..9b9d6ebf03 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9f2be1c70b..5f16ef3d13 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index d338e427c8..df92634745 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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,19 +4318,36 @@ 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)) {
case OR_Success:
@@ -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;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 23256a853c..8d75ac463a 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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;
}
diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp
index 69ebec1365..0f3a37a702 100644
--- a/test/SemaTemplate/member-function-template.cpp
+++ b/test/SemaTemplate/member-function-template.cpp
@@ -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);
+} \ No newline at end of file