[cfe-commits] r79504 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/Sema.h lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.mem/p1.cpp

John McCall rjmccall at apple.com
Wed Aug 19 18:44:22 PDT 2009


Author: rjmccall
Date: Wed Aug 19 20:44:21 2009
New Revision: 79504

URL: http://llvm.org/viewvc/llvm-project?rev=79504&view=rev
Log:
Basic nested-template implementation.


Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Aug 19 20:44:21 2009
@@ -1061,6 +1061,8 @@
   /// \brief Data that is common to all of the declarations of a given
   /// class template.
   struct Common {
+    Common() : InstantiatedFromMember(0) {}
+
     /// \brief The class template specializations for this class
     /// template, including explicit specializations and instantiations.
     llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
@@ -1072,6 +1074,10 @@
 
     /// \brief The injected-class-name type for this class template.
     QualType InjectedClassNameType;
+
+    /// \brief The templated member class from which this was most
+    /// directly instantiated (or null).
+    ClassTemplateDecl *InstantiatedFromMember;
   };
 
   /// \brief Previous declaration of this class template.
@@ -1151,6 +1157,35 @@
   /// \endcode
   QualType getInjectedClassNameType(ASTContext &Context);
 
+  /// \brief Retrieve the member class template that this class template was
+  /// derived from.
+  ///
+  /// This routine will return non-NULL for templated member classes of
+  /// class templates.  For example, given:
+  ///
+  /// \code
+  /// template <typename T>
+  /// struct X {
+  ///   template <typename U> struct A {};
+  /// };
+  /// \endcode
+  ///
+  /// X<int>::A<float> is a ClassTemplateSpecializationDecl (whose parent
+  /// is X<int>, also a CTSD) for which getSpecializedTemplate() will
+  /// return X<int>::A<U>, a TemplateClassDecl (whose parent is again
+  /// X<int>) for which getInstantiatedFromMemberTemplate() will return
+  /// X<T>::A<U>, a TemplateClassDecl (whose parent is X<T>, also a TCD).
+  ///
+  /// \returns null if this is not an instantiation of a member class template.
+  ClassTemplateDecl *getInstantiatedFromMemberTemplate() const {
+    return CommonPtr->InstantiatedFromMember;
+  }
+
+  void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) {
+    assert(!CommonPtr->InstantiatedFromMember);
+    CommonPtr->InstantiatedFromMember = CTD;
+  }
+
   // Implement isa/cast/dyncast support
   static bool classof(const Decl *D)
   { return D->getKind() == ClassTemplate; }

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=79504&r1=79503&r2=79504&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Aug 19 20:44:21 2009
@@ -2847,6 +2847,10 @@
                             const TemplateArgumentList &TemplateArgs);
 
   bool
+  InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
+                             CXXRecordDecl *Pattern);
+
+  bool
   InstantiateClass(SourceLocation PointOfInstantiation,
                    CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
                    const TemplateArgumentList &TemplateArgs,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Aug 19 20:44:21 2009
@@ -568,6 +568,38 @@
   return Invalid;
 }
 
+/// \brief Force a template's pattern class to be instantiated.
+///
+/// \returns true if an error occurred
+bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
+                                      CXXRecordDecl *Pattern) {
+  if (Pattern->getDefinition(Context)) return false;
+
+  ClassTemplateDecl *PatternTemp = Pattern->getDescribedClassTemplate();
+  if (!PatternTemp) return false;
+
+  // Check whether this template is a lazy instantiation of a
+  // dependent member template, e.g. Inner<U> in
+  // Outer<int>::Inner<U>.
+  ClassTemplateDecl *PatternPatternTemp
+    = PatternTemp->getInstantiatedFromMemberTemplate();
+  if (!PatternPatternTemp) return false;
+  
+  ClassTemplateSpecializationDecl *Spec = 0;
+  for (DeclContext *Parent = Pattern->getDeclContext();
+       Parent && !Spec; Parent = Parent->getParent())
+    Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
+  assert(Spec && "Not a member of a class template specialization?");
+
+  // TODO: the error message from a nested failure here is probably
+  // not ideal.
+  return InstantiateClass(PointOfInstantiation,
+                          Pattern,
+                          PatternPatternTemp->getTemplatedDecl(),
+                          Spec->getTemplateArgs(),
+                          /* ExplicitInstantiation = */ false);
+}
+
 /// \brief Instantiate the definition of a class from a given pattern.
 ///
 /// \param PointOfInstantiation The point of instantiation within the
@@ -591,6 +623,10 @@
                        const TemplateArgumentList &TemplateArgs,
                        bool ExplicitInstantiation) {
   bool Invalid = false;
+
+  // Lazily instantiate member templates here.
+  if (InstantiateTemplatePattern(PointOfInstantiation, Pattern))
+    return true;
   
   CXXRecordDecl *PatternDef 
     = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Aug 19 20:44:21 2009
@@ -53,6 +53,8 @@
     Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
     ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+    Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+    Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
 
     // Base case. FIXME: Remove once we can instantiate everything.
     Decl *VisitDecl(Decl *) { 
@@ -69,6 +71,9 @@
                              llvm::SmallVectorImpl<ParmVarDecl *> &Params);
     bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
     bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+
+    TemplateParameterList *
+      InstantiateTemplateParams(TemplateParameterList *List);
   };
 }
 
@@ -322,6 +327,28 @@
   return 0;
 }
 
+Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+  TemplateParameterList *TempParams = D->getTemplateParameters();
+  TemplateParameterList *InstParams = InstantiateTemplateParams(TempParams);
+  if (!InstParams) return NULL;
+
+  CXXRecordDecl *Pattern = D->getTemplatedDecl();
+  CXXRecordDecl *RecordInst
+    = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+                            Pattern->getLocation(), Pattern->getIdentifier(),
+                            Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL);
+
+  ClassTemplateDecl *Inst
+    = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+                                D->getIdentifier(), InstParams, RecordInst, 0);
+  RecordInst->setDescribedClassTemplate(Inst);
+  Inst->setAccess(D->getAccess());
+  Inst->setInstantiatedFromMemberTemplate(D);
+
+  Owner->addDecl(Inst);
+  return Inst;
+}
+
 Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
   CXXRecordDecl *PrevDecl = 0;
   if (D->isInjectedClassName())
@@ -639,12 +666,79 @@
   return VisitParmVarDecl(D);
 }
 
+Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
+                                                    TemplateTypeParmDecl *D) {
+  // TODO: don't always clone when decls are refcounted.
+  const Type* T = D->getTypeForDecl();
+  assert(T->isTemplateTypeParmType());
+  const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>();
+  
+  TemplateTypeParmDecl *Inst =
+    TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+                                 TTPT->getDepth(), TTPT->getIndex(),
+                                 TTPT->getName(),
+                                 D->wasDeclaredWithTypename(),
+                                 D->isParameterPack());
+
+  if (D->hasDefaultArgument()) {
+    QualType DefaultPattern = D->getDefaultArgument();
+    QualType DefaultInst
+      = SemaRef.InstantiateType(DefaultPattern, TemplateArgs,
+                                D->getDefaultArgumentLoc(),
+                                D->getDeclName());
+    
+    Inst->setDefaultArgument(DefaultInst,
+                             D->getDefaultArgumentLoc(),
+                             D->defaultArgumentWasInherited() /* preserve? */);
+  }
+
+  return Inst;
+}
+
 Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
                             const TemplateArgumentList &TemplateArgs) {
   TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
   return Instantiator.Visit(D);
 }
 
+/// \brief Instantiates a nested template parameter list in the current
+/// instantiation context.
+///
+/// \param L The parameter list to instantiate
+///
+/// \returns NULL if there was an error
+TemplateParameterList *
+TemplateDeclInstantiator::InstantiateTemplateParams(TemplateParameterList *L) {
+  // Get errors for all the parameters before bailing out.
+  bool Invalid = false;
+
+  unsigned N = L->size();
+  typedef llvm::SmallVector<Decl*,8> ParamVector;
+  ParamVector Params;
+  Params.reserve(N);
+  for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
+       PI != PE; ++PI) {
+    Decl *D = Visit(*PI);
+    Params.push_back(D);
+    Invalid = Invalid || !D;
+  }
+
+  // Clean up if we had an error.
+  if (Invalid) {
+    for (ParamVector::iterator PI = Params.begin(), PE = Params.end();
+         PI != PE; ++PI)
+      if (*PI)
+        (*PI)->Destroy(SemaRef.Context);
+    return NULL;
+  }
+
+  TemplateParameterList *InstL
+    = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
+                                    L->getLAngleLoc(), &Params.front(), N,
+                                    L->getRAngleLoc());
+  return InstL;
+} 
+
 /// \brief Instantiates the type of the given function, including
 /// instantiating all of the function parameters.
 ///

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp?rev=79504&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p1.cpp Wed Aug 19 20:44:21 2009
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> struct A {
+  static T cond;
+  
+  template <class U> struct B {
+    static T twice(U value) {
+      return (cond ? value + value : value);
+    }
+  };
+};
+
+int foo() {
+  A<bool>::cond = true;
+  return A<bool>::B<int>::twice(4);
+}





More information about the cfe-commits mailing list