diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-21 00:16:32 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-21 00:16:32 +0000 |
commit | 6b906869527be40b0d38d755e9ef51b331b88162 (patch) | |
tree | 383418b55d313e27f7e21b20756b8f5347176355 | |
parent | c42a92aa1fbd24b7a26c7c29552d07478a8e2045 (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.h | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 87 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 35 | ||||
-rw-r--r-- | test/SemaTemplate/member-function-template.cpp | 29 |
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 |