[cfe-commits] r79581 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/member-function-template.cpp
Douglas Gregor
dgregor at apple.com
Thu Aug 20 17:16:32 PDT 2009
Author: dgregor
Date: Thu Aug 20 19:16:32 2009
New Revision: 79581
URL: http://llvm.org/viewvc/llvm-project?rev=79581&view=rev
Log:
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).
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaTemplate/member-function-template.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=79581&r1=79580&r2=79581&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Aug 20 19:16:32 2009
@@ -804,6 +804,14 @@
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,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=79581&r1=79580&r2=79581&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Aug 20 19:16:32 2009
@@ -939,18 +939,35 @@
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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=79581&r1=79580&r2=79581&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Aug 20 19:16:32 2009
@@ -2237,6 +2237,48 @@
}
}
+/// \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 @@
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 @@
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 @@
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 @@
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;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=79581&r1=79580&r2=79581&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Aug 20 19:16:32 2009
@@ -457,7 +457,26 @@
}
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 @@
= 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 @@
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;
}
Modified: cfe/trunk/test/SemaTemplate/member-function-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-function-template.cpp?rev=79581&r1=79580&r2=79581&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/member-function-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/member-function-template.cpp Thu Aug 20 19:16:32 2009
@@ -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
More information about the cfe-commits
mailing list