]> granicus.if.org Git - clang/commitdiff
Implement instantiation of the declarations of member function
authorDouglas Gregor <dgregor@apple.com>
Thu, 27 Aug 2009 16:57:43 +0000 (16:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 27 Aug 2009 16:57:43 +0000 (16:57 +0000)
templates within class templates, producing a member function template
of a class template specialization. If you can parse that, I'm
sorry. Example:

  template<typename T>
  struct X {
    template<typename U> void f(T, U);
  };

When we instantiate X<int>, we now instantiate the declaration
X<int>::f, which looks like this:

  template<typename U> void X<int>::f(int, U);

The path this takes through
TemplateDeclInstantiator::VisitCXXMethodDecl is convoluted and
ugly, but I don't know how to improve it yet. I'm resting my hopes on
the multi-level substitution required to instantiate definitions of
nested templates, which may simplify this code as well.

More testing to come...

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80252 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclTemplate.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/instantiate-member-template.cpp [new file with mode: 0644]

index ac03a9ea31edb3e68482e5aa3fc48fcfdcf363a8..fc1c4ddcc1c07548bb87a985faa71e0b3ae83054 100644 (file)
@@ -552,9 +552,15 @@ protected:
   /// \brief Data that is common to all of the declarations of a given
   /// function template.
   struct Common {
+    Common() : InstantiatedFromMember(0) { }
+    
     /// \brief The function template specializations for this function
     /// template, including explicit specializations and instantiations.
     llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
+    
+    /// \brief The member function template from which this was most
+    /// directly instantiated (or null).
+    FunctionTemplateDecl *InstantiatedFromMember;    
   };
   
   /// \brief A pointer to the previous declaration (if this is a redeclaration)
@@ -606,6 +612,37 @@ public:
   
   virtual FunctionTemplateDecl *getCanonicalDecl();
   
+  /// \brief Retrieve the member function template that this function template 
+  /// was instantiated from.
+  ///
+  /// This routine will return non-NULL for member function templates of
+  /// class templates.  For example, given:
+  ///
+  /// \code
+  /// template <typename T>
+  /// struct X {
+  ///   template <typename U> void f();
+  /// };
+  /// \endcode
+  ///
+  /// X<int>::A<float> is a CXXMethodDecl (whose parent is X<int>, a
+  /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will 
+  /// return X<int>::f, a FunctionTemplateDecl (whose parent is again
+  /// X<int>) for which getInstantiatedFromMemberTemplate() will return
+  /// X<T>::f, a FunctionTemplateDecl (whose parent is X<T>, a 
+  /// ClassTemplateDecl).
+  ///
+  /// \returns NULL if this is not an instantiation of a member function 
+  /// template.
+  FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
+    return getCommonPtr()->InstantiatedFromMember;
+  }
+  
+  void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) {
+    assert(!getCommonPtr()->InstantiatedFromMember);
+    getCommonPtr()->InstantiatedFromMember = FTD;
+  }
+  
   /// Create a template function node.
   static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
                                       SourceLocation L,
index 5f834dc50066cc9857bd5b336e17904ddd922927..045c12aab5485a3f237bcdf7d61b80eb83bd8680 100644 (file)
@@ -2534,10 +2534,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       if (CheckTemplateDeclScope(S, TemplateParams))
         return 0;
       
-      FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
+      FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
                                                       NewFD->getLocation(),
                                                       Name, TemplateParams,
                                                       NewFD);
+      FunctionTemplate->setLexicalDeclContext(CurContext);
       NewFD->setDescribedFunctionTemplate(FunctionTemplate);
     } else {
       // FIXME: Handle function template specializations
index 5e917890836ef9a3b82c61eed356381e9f3f4304..42fc1f8165d580d929a41ce0895e7a7b8f287f56 100644 (file)
@@ -48,13 +48,15 @@ namespace {
     Decl *VisitFriendClassDecl(FriendClassDecl *D);
     Decl *VisitFunctionDecl(FunctionDecl *D);
     Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
-    Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+    Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
+                             TemplateParameterList *TemplateParams = 0);
     Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
     Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
     Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
     ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
     Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+    Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
 
     // Base case. FIXME: Remove once we can instantiate everything.
@@ -356,7 +358,8 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
 Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
-  if (!InstParams) return NULL;
+  if (!InstParams) 
+    return NULL;
 
   CXXRecordDecl *Pattern = D->getTemplatedDecl();
   CXXRecordDecl *RecordInst
@@ -375,6 +378,32 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   return Inst;
 }
 
+Decl *
+TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+  TemplateParameterList *TempParams = D->getTemplateParameters();
+  TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+  if (!InstParams) 
+    return NULL;
+  
+  // FIXME: Handle instantiation of nested function templates that aren't 
+  // member function templates. This could happen inside a FriendDecl.
+  assert(isa<CXXMethodDecl>(D->getTemplatedDecl()));
+  CXXMethodDecl *InstMethod 
+    = cast_or_null<CXXMethodDecl>(
+                 VisitCXXMethodDecl(cast<CXXMethodDecl>(D->getTemplatedDecl()), 
+                                    InstParams));
+  if (!InstMethod)
+    return 0;
+
+  // Link the instantiated function template declaration to the function 
+  // template from which it was instantiated.
+  FunctionTemplateDecl *InstTemplate = InstMethod->getDescribedFunctionTemplate();
+  assert(InstTemplate && "VisitCXXMethodDecl didn't create a template!");
+  InstTemplate->setInstantiatedFromMemberTemplate(D);
+  Owner->addDecl(InstTemplate);
+  return InstTemplate;
+}
+
 Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
   CXXRecordDecl *PrevDecl = 0;
   if (D->isInjectedClassName())
@@ -481,12 +510,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
   return Function;
 }
 
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
-  // Check whether there is already a function template specialization for
-  // this declaration.
+Decl *
+TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
+                                      TemplateParameterList *TemplateParams) {
   FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
   void *InsertPos = 0;
-  if (FunctionTemplate) {
+  if (FunctionTemplate && !TemplateParams) {
+    // We are creating a function template specialization from a function 
+    // template. Check whether there is already a function template 
+    // specialization for this particular set of template arguments.
     llvm::FoldingSetNodeID ID;
     FunctionTemplateSpecializationInfo::Profile(ID, 
                                           TemplateArgs.getFlatArgumentList(),
@@ -548,7 +580,28 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
                                    D->isStatic(), D->isInline());
   }
 
-  if (!FunctionTemplate)
+  if (TemplateParams) {
+    // Our resulting instantiation is actually a function template, since we
+    // are substituting only the outer template parameters. For example, given
+    // 
+    //   template<typename T>
+    //   struct X {
+    //     template<typename U> void f(T, U);
+    //   };
+    //
+    //   X<int> x;
+    //
+    // We are instantiating the member template "f" within X<int>, which means
+    // substituting int for T, but leaving "f" as a member function template.
+    // Build the function template itself.
+    FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record,
+                                                    Method->getLocation(),
+                                                    Method->getDeclName(), 
+                                                    TemplateParams, Method);
+    if (D->isOutOfLine())
+      FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+    Method->setDescribedFunctionTemplate(FunctionTemplate);
+  } else if (!FunctionTemplate)
     Method->setInstantiationOfMemberFunction(D);
 
   // If we are instantiating a member function defined 
@@ -567,7 +620,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
 
   NamedDecl *PrevDecl = 0;
   
-  if (!FunctionTemplate) {
+  if (!FunctionTemplate || TemplateParams) {
     PrevDecl = SemaRef.LookupQualifiedName(Owner, Name, 
                                            Sema::LookupOrdinaryName, true);
   
@@ -579,7 +632,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
       PrevDecl = 0;
   }
 
-  if (FunctionTemplate)
+  if (FunctionTemplate && !TemplateParams)
     // Record this function template specialization.
     Method->setFunctionTemplateSpecialization(SemaRef.Context,
                                               FunctionTemplate,
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
new file mode 100644 (file)
index 0000000..959e5c1
--- /dev/null
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+  template<typename U> T f0(U);
+  template<typename U> U& f1(T*, U); // expected-error{{pointer to a reference}} \
+                                     // expected-note{{candidate}}
+};
+
+X0<int> x0i;
+X0<void> x0v;
+X0<int&> x0ir; // expected-note{{instantiation}}
+
+void test_X0(int *ip, double *dp) {
+  X0<int> xi;
+  int i1 = xi.f0(ip);
+  double *&dpr = xi.f1(ip, dp);
+  xi.f1(dp, dp); // expected-error{{no matching}}
+
+  X0<void> xv;
+  double *&dpr2 = xv.f1(ip, dp);
+}