[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