[cfe-commits] r74232 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Decl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/implicit-instantiation-1.cpp

Douglas Gregor dgregor at apple.com
Thu Jun 25 17:10:04 PDT 2009


Author: dgregor
Date: Thu Jun 25 19:10:03 2009
New Revision: 74232

URL: http://llvm.org/viewvc/llvm-project?rev=74232&view=rev
Log:
Implicit instantiation for function template specializations.

For a FunctionDecl that has been instantiated due to template argument
deduction, we now store the primary template from which it was
instantiated and the deduced template arguments. From this
information, we can instantiate the body of the function template.

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/implicit-instantiation-1.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Jun 25 19:10:03 2009
@@ -25,7 +25,8 @@
 class Stmt;
 class CompoundStmt;
 class StringLiteral;
-
+class TemplateArgumentList;
+  
 /// TranslationUnitDecl - The top declaration context.
 class TranslationUnitDecl : public Decl, public DeclContext {
   TranslationUnitDecl()
@@ -614,10 +615,17 @@
     None, Extern, Static, PrivateExtern
   };
 private:
+  /// \brief Provides information about a function template specialization, 
+  /// which is a FunctionDecl that has been explicitly specialization or
+  /// instantiated from a function template.
+  struct TemplateSpecializationInfo {
+    FunctionTemplateDecl *Template;
+    const TemplateArgumentList *TemplateArguments;
+  };
+  
   /// ParamInfo - new[]'d array of pointers to VarDecls for the formal
   /// parameters of this function.  This is null if a prototype or if there are
-  /// no formals.  TODO: we could allocate this space immediately after the
-  /// FunctionDecl object to save an allocation like FunctionType does.
+  /// no formals.
   ParmVarDecl **ParamInfo;
   
   LazyDeclStmtPtr Body;
@@ -664,8 +672,12 @@
   /// pointer to a FunctionTemplateDecl. For member functions
   /// of class template specializations, this will be the
   /// FunctionDecl from which the member function was instantiated.
-  llvm::PointerUnion<FunctionTemplateDecl*, FunctionDecl*>
-    TemplateOrInstantiation;
+  /// For function template specializations, this will be a 
+  /// FunctionTemplateSpecializationInfo, which contains information about
+  /// the template being specialized and the template arguments involved in 
+  /// that specialization.
+  llvm::PointerUnion3<FunctionTemplateDecl*, FunctionDecl*,
+                      TemplateSpecializationInfo*> TemplateOrSpecialization;
 
 protected:
   FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -678,7 +690,7 @@
       SClass(S), IsInline(isInline), C99InlineDefinition(false), 
       IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), 
       HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
-      EndRangeLoc(L), TemplateOrInstantiation() {}
+      EndRangeLoc(L), TemplateOrSpecialization() {}
 
   virtual ~FunctionDecl() {}
   virtual void Destroy(ASTContext& C);
@@ -887,13 +899,13 @@
   /// X<int>::A is required, it will be instantiated from the
   /// declaration returned by getInstantiatedFromMemberFunction().
   FunctionDecl *getInstantiatedFromMemberFunction() const {
-    return TemplateOrInstantiation.dyn_cast<FunctionDecl*>();
+    return TemplateOrSpecialization.dyn_cast<FunctionDecl*>();
   }
 
   /// \brief Specify that this record is an instantiation of the
   /// member function RD.
   void setInstantiationOfMemberFunction(FunctionDecl *RD) { 
-    TemplateOrInstantiation = RD;
+    TemplateOrSpecialization = RD;
   }
 
   /// \brief Retrieves the function template that is described by this
@@ -909,13 +921,54 @@
   /// getDescribedFunctionTemplate() retrieves the
   /// FunctionTemplateDecl from a FunctionDecl.
   FunctionTemplateDecl *getDescribedFunctionTemplate() const {
-    return TemplateOrInstantiation.dyn_cast<FunctionTemplateDecl*>();
+    return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>();
   }
 
   void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
-    TemplateOrInstantiation = Template;
+    TemplateOrSpecialization = Template;
   }
 
+  /// \brief Retrieve the primary template that this function template
+  /// specialization either specializes or was instantiated from.
+  ///
+  /// If this function declaration is not a function template specialization,
+  /// returns NULL.
+  FunctionTemplateDecl *getPrimaryTemplate() const {
+    if (TemplateSpecializationInfo *Info 
+          = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
+      return Info->Template;
+    }
+    return 0;
+  }
+  
+  /// \brief Retrieve the template arguments used to produce this function
+  /// template specialization from the primary template.
+  ///
+  /// If this function declaration is not a function template specialization,
+  /// returns NULL.
+  const TemplateArgumentList *getTemplateSpecializationArgs() const {
+    if (TemplateSpecializationInfo *Info 
+          = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
+      return Info->TemplateArguments;
+    }
+    return 0;
+  }
+  
+  
+  /// \brief Specify that this function declaration is actually a function
+  /// template specialization.
+  ///
+  /// \param Context the AST context in which this function resides.
+  ///
+  /// \param Template the function template that this function template
+  /// specialization specializes.
+  ///
+  /// \param TemplateArgs the template arguments that produced this
+  /// function template specialization from the template.
+  void setFunctionTemplateSpecialization(ASTContext &Context,
+                                         FunctionTemplateDecl *Template,
+                                      const TemplateArgumentList *TemplateArgs);
+  
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
     return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Jun 25 19:10:03 2009
@@ -153,7 +153,7 @@
   NamedDecl *TemplatedDecl;
   TemplateParameterList* TemplateParams;
 };
-
+ 
 /// Declaration of a template function.
 class FunctionTemplateDecl : public TemplateDecl {
 protected:

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun 25 19:10:03 2009
@@ -821,6 +821,9 @@
   "in instantiation of member class %0 requested here">;
 def note_template_member_function_here : Note<
   "in instantiation of member function %q0 requested here">;
+def note_function_template_spec_here : Note<
+  "in instantiation of function template specialization %q0 requested here">;
+  
 def note_default_arg_instantiation_here : Note<
   "in instantiation of default argument for '%0' required here">;
 def note_partial_spec_deduct_instantiation_here : Note<

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Jun 25 19:10:03 2009
@@ -359,6 +359,10 @@
 
   C.Deallocate(ParamInfo);
 
+  if (TemplateSpecializationInfo *Info 
+        = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>())
+    C.Deallocate(Info);
+  
   Decl::Destroy(C);
 }
 
@@ -555,6 +559,20 @@
     return OO_None;
 }
 
+void 
+FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
+                                                FunctionTemplateDecl *Template,
+                                     const TemplateArgumentList *TemplateArgs) {
+  TemplateSpecializationInfo *Info 
+    = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>();
+  if (!Info)
+    Info = new (Context) TemplateSpecializationInfo;
+  
+  Info->Template = Template;
+  Info->TemplateArguments = TemplateArgs;
+  TemplateOrSpecialization = Info;
+}
+
 //===----------------------------------------------------------------------===//
 // TagDecl Implementation
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 25 19:10:03 2009
@@ -5566,12 +5566,15 @@
     }
   }
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
-    // Implicit instantiation of function templates
+    // Implicit instantiation of function templates and member functions of 
+    // class templates.
     if (!Function->getBody(Context)) {
-      if (Function->getInstantiatedFromMemberFunction())
+      // FIXME: distinguish between implicit instantiations of function
+      // templates and explicit specializations (the latter don't get
+      // instantiated, naturally).
+      if (Function->getInstantiatedFromMemberFunction() ||
+          Function->getPrimaryTemplate())
         PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
-
-      // FIXME: check for function template specializations.
     }
     
     

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jun 25 19:10:03 2009
@@ -870,6 +870,10 @@
   if (!Specialization || Trap.hasErrorOccurred())
     return TDK_SubstitutionFailure;
 
+  // Turn the specialization into an actual function template specialization.
+  Specialization->setFunctionTemplateSpecialization(Context,
+                                                    FunctionTemplate,
+                                                    Info.take());
   return TDK_Success;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Jun 25 19:10:03 2009
@@ -29,10 +29,18 @@
 /// instantiate the given declaration.
 const TemplateArgumentList &
 Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+  // Template arguments for a class template specialization.
   if (ClassTemplateSpecializationDecl *Spec 
         = dyn_cast<ClassTemplateSpecializationDecl>(D))
     return Spec->getTemplateArgs();
 
+  // Template arguments for a function template specialization.
+  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+    if (const TemplateArgumentList *TemplateArgs
+          = Function->getTemplateSpecializationArgs())
+      return *TemplateArgs;
+      
+  // Template arguments for a member of a class template specialization.
   DeclContext *EnclosingTemplateCtx = D->getDeclContext();
   while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
     assert(!EnclosingTemplateCtx->isFileContext() &&
@@ -158,8 +166,11 @@
           << Active->InstantiationRange;
       } else {
         FunctionDecl *Function = cast<FunctionDecl>(D);
-        unsigned DiagID = diag::note_template_member_function_here;
-        // FIXME: check for a function template
+        unsigned DiagID;
+        if (Function->getPrimaryTemplate())
+          DiagID = diag::note_function_template_spec_here;
+        else
+          DiagID = diag::note_template_member_function_here;
         Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), 
                      DiagID)
           << Function

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Jun 25 19:10:03 2009
@@ -645,16 +645,17 @@
 /// function.
 void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                          FunctionDecl *Function) {
-  // FIXME: make this work for function template specializations, too.
-
   if (Function->isInvalidDecl())
     return;
 
   assert(!Function->getBody(Context) && "Already instantiated!");
   
   // Find the function body that we'll be substituting.
-  const FunctionDecl *PatternDecl 
-    = Function->getInstantiatedFromMemberFunction();
+  const FunctionDecl *PatternDecl = 0;
+  if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
+    PatternDecl = Primary->getTemplatedDecl();
+  else 
+    PatternDecl = Function->getInstantiatedFromMemberFunction();
   Stmt *Pattern = 0;
   if (PatternDecl)
     Pattern = PatternDecl->getBody(Context, PatternDecl);

Modified: cfe/trunk/test/SemaTemplate/implicit-instantiation-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/implicit-instantiation-1.cpp?rev=74232&r1=74231&r2=74232&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/implicit-instantiation-1.cpp (original)
+++ cfe/trunk/test/SemaTemplate/implicit-instantiation-1.cpp Thu Jun 25 19:10:03 2009
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-
 template<typename T, typename U>
 struct X {
   T f(T x, U y) { return x + y; }
@@ -14,3 +13,13 @@
   (void)xip->g(2, 0); // okay: does not instantiate
 }
 
+template<typename T, typename U>
+T add(T t, U u) {
+  return t + u; // expected-error{{invalid operands}}
+}
+
+void test_add(char *cp, int i, int *ip) {
+  char* cp2 = add(cp, i);
+  add(cp, cp); // expected-note{{instantiation of}}
+  (void)sizeof(add(ip, ip));
+}
\ No newline at end of file





More information about the cfe-commits mailing list