Basic representation of C++ class templates, from Andrew Sutton.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63750 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b0e24f5..b27f11b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -60,6 +60,7 @@
   class SwitchStmt;
   class ExtVectorType;
   class TypedefDecl;
+  class TemplateDecl;
   class ObjCInterfaceDecl;
   class ObjCCompatibleAliasDecl;
   class ObjCProtocolDecl;
@@ -1479,14 +1480,23 @@
   virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
                                  const CXXScopeSpec *SS = 0);
   bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
-  virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename, 
-				     SourceLocation KeyLoc,
-				     IdentifierInfo *ParamName,
-				     SourceLocation ParamNameLoc,
+  TemplateDecl *AdjustDeclIfTemplate(DeclTy *&Decl);
+
+  virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename,
+                                     SourceLocation KeyLoc,
+                                     IdentifierInfo *ParamName,
+                                     SourceLocation ParamNameLoc,
                                      unsigned Depth, unsigned Position);
   virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
-                                                unsigned Depth, 
+                                                unsigned Depth,
                                                 unsigned Position);
+  virtual DeclTy *ActOnTemplateTemplateParameter(Scope *S,
+                                                 SourceLocation TmpLoc,
+                                                 TemplateParamsTy *Params,
+                                                 IdentifierInfo *ParamName,
+                                                 SourceLocation ParamNameLoc,
+                                                 unsigned Depth,
+                                                 unsigned Position);
   virtual TemplateParamsTy *
   ActOnTemplateParameterList(unsigned Depth,
                              SourceLocation ExportLoc,
@@ -1495,6 +1505,7 @@
                              DeclTy **Params, unsigned NumParams,
                              SourceLocation RAngleLoc);
   
+
   // Objective-C declarations.
   virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                                            IdentifierInfo *ClassName,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a3ca97b..3e501f4 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Parse/DeclSpec.h"
 #include "clang/Basic/TargetInfo.h"
@@ -1170,7 +1171,7 @@
   // The scope passed in may not be a decl scope.  Zip up the scope tree until
   // we find one that is.
   while ((S->getFlags() & Scope::DeclScope) == 0 ||
-        (S->getFlags() & Scope::TemplateParamScope) != 0)
+         (S->getFlags() & Scope::TemplateParamScope) != 0)
     S = S->getParent();
   
   DeclContext *DC;
@@ -2778,6 +2779,9 @@
 /// former case, Name will be non-null.  In the later case, Name will be null.
 /// TagSpec indicates what kind of tag this is. TK indicates whether this is a
 /// reference/declaration/definition of a tag.
+///
+/// This creates and returns template declarations if any template parameter
+/// lists are given.
 Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                              SourceLocation KWLoc, const CXXScopeSpec &SS,
                              IdentifierInfo *Name, SourceLocation NameLoc,
@@ -2786,7 +2790,12 @@
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TK == TK_Definition) &&
          "Nameless record must be a definition!");
-  
+  assert((TemplateParameterLists.size() == 0 || TK != TK_Reference) &&
+         "Can't have a reference to a template");
+  assert((TemplateParameterLists.size() == 0 || 
+          TagSpec != DeclSpec::TST_enum) &&
+         "No such thing as an enum template");
+
   TagDecl::TagKind Kind;
   switch (TagSpec) {
   default: assert(0 && "Unknown tag type!");
@@ -2799,6 +2808,7 @@
   DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   NamedDecl *PrevDecl = 0;
+  TemplateDecl *PrevTemplate = 0;
 
   bool Invalid = false;
 
@@ -2863,6 +2873,11 @@
   }
 
   if (PrevDecl) {    
+    // If we found a template, keep track of the template and its
+    // underlying declaration.
+    if ((PrevTemplate = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl)))
+      PrevDecl = PrevTemplate->getTemplatedDecl();
+
     if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
       // If this is a use of a previous tag, or if the tag is already declared
       // in the same scope (so that the definition/declaration completes or
@@ -2877,6 +2892,7 @@
           Name = 0;
           PrevDecl = 0;
           Invalid = true;
+          // FIXME: Add template/non-template redecl check
         } else {
           // If this is a use, just return the declaration we found.
 
@@ -2886,7 +2902,7 @@
           // need to be changed with DeclGroups.
           if (TK == TK_Reference)
             return PrevDecl;
-          
+
           // Diagnose attempts to redefine a tag.
           if (TK == TK_Definition) {
             if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
@@ -2990,6 +3006,7 @@
   // declaration of the same entity, the two will be linked via
   // PrevDecl.
   TagDecl *New;
+  ClassTemplateDecl *NewTemplate = 0;
 
   if (Kind == TagDecl::TK_enum) {
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
@@ -3003,11 +3020,28 @@
 
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // struct X { int A; } D;    D should chain to X.
-    if (getLangOptions().CPlusPlus)
+    if (getLangOptions().CPlusPlus) {
       // FIXME: Look for a way to use RecordDecl for simple structs.
       New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
                                   cast_or_null<CXXRecordDecl>(PrevDecl));
-    else
+
+      // If there's are template parameters, then this must be a class
+      // template. Create the template decl node also.
+      // FIXME: Do we always create template decls? We may not for forward
+      // declarations.
+      // FIXME: What are we actually going to do with the template decl?
+      if (TemplateParameterLists.size() > 0) {
+        // FIXME: The allocation of the parameters is probably incorrect.
+        // FIXME: Does the TemplateDecl have the same name as the class?
+        TemplateParameterList *Params =
+          TemplateParameterList::Create(Context,
+                                        (Decl **)TemplateParameterLists.get(),
+                                        TemplateParameterLists.size());
+        NewTemplate = ClassTemplateDecl::Create(Context, DC, Loc,
+                                                DeclarationName(Name), Params,
+                                                New);
+      }
+    } else
       New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
                                cast_or_null<RecordDecl>(PrevDecl));
   }
@@ -3080,6 +3114,7 @@
 }
 
 void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) {
+  AdjustDeclIfTemplate(TagD);
   TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
 
   // Enter the tag context.
@@ -3105,6 +3140,7 @@
 }
 
 void Sema::ActOnTagFinishDefinition(Scope *S, DeclTy *TagD) {
+  AdjustDeclIfTemplate(TagD);
   TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
 
   if (isa<CXXRecordDecl>(Tag))
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 5595215..35050e5 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -757,6 +757,7 @@
                                              DeclTy *TagDecl,
                                              SourceLocation LBrac,
                                              SourceLocation RBrac) {
+  AdjustDeclIfTemplate(TagDecl);
   ActOnFields(S, RLoc, TagDecl,
               (DeclTy**)FieldCollector->getCurFields(),
               FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0c755f6..66cbdfd 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/LiteralSupport.h"
 #include "clang/Basic/SourceManager.h"
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 65dd949..1aa2ea0 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -536,7 +536,7 @@
     IEnd = IdResolver.end();
 
   // First we lookup local scope.
-  // We don't consider using-dirctives, as per 7.3.4.p1 [namespace.udir]
+  // We don't consider using-directives, as per 7.3.4.p1 [namespace.udir]
   // ...During unqualified name lookup (3.4.1), the names appear as if
   // they were declared in the nearest enclosing namespace which contains
   // both the using-directive and the nominated namespace.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index c46731e..e15343a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -13,6 +13,7 @@
 
 #include "Sema.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/Parse/DeclSpec.h"
 #include "clang/Basic/LangOptions.h"
 
@@ -38,6 +39,9 @@
     // FIXME: We need to represent templates via some kind of
     // TemplateDecl, because what follows is a hack that only works in
     // one specific case.
+    if (isa<TemplateDecl>(IIDecl))
+      return IIDecl;
+
     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
       if (FD->getType()->isDependentType())
         return FD;
@@ -50,7 +54,6 @@
           return Ovl;
       }
     }
-    return 0;
   }
   return 0;
 }
@@ -75,6 +78,18 @@
   return true;
 }
 
+/// AdjustDeclForTemplates - If the given decl happens to be a template, reset
+/// the parameter D to reference the templated declaration and return a pointer
+/// to the template declaration. Otherwise, do nothing to D and return null.
+TemplateDecl *Sema::AdjustDeclIfTemplate(DeclTy *&D)
+{
+  if(TemplateDecl *Temp = dyn_cast<TemplateDecl>(static_cast<Decl*>(D))) {
+    D = Temp->getTemplatedDecl();
+    return Temp;
+  }
+  return 0;
+}
+
 /// ActOnTypeParameter - Called when a C++ template type parameter
 /// (e.g., "typename T") has been parsed. Typename specifies whether
 /// the keyword "typename" was used to declare the type parameter
@@ -101,8 +116,8 @@
   }
 
   TemplateTypeParmDecl *Param
-    = TemplateTypeParmDecl::Create(Context, CurContext, 
-				   ParamNameLoc, ParamName, Typename);
+    = TemplateTypeParmDecl::Create(Context, CurContext, ParamNameLoc, 
+                                   Depth, Position, ParamName, Typename);
   if (Invalid)
     Param->setInvalidDecl();
 
@@ -124,8 +139,8 @@
                                                   unsigned Position) {
   QualType T = GetTypeForDeclarator(D, S);
 
-  assert(S->isTemplateParamScope() && 
-	 "Template type parameter not in template parameter scope!");
+  assert(S->isTemplateParamScope() &&
+         "Non-type template parameter not in template parameter scope!");
   bool Invalid = false;
 
   IdentifierInfo *ParamName = D.getIdentifier();
@@ -133,12 +148,12 @@
     NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
     if (PrevDecl && PrevDecl->isTemplateParameter())
       Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
-							   PrevDecl);
+                                                           PrevDecl);
   }
 
   NonTypeTemplateParmDecl *Param
     = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
-				      ParamName, T);
+                                      Depth, Position, ParamName, T);
   if (Invalid)
     Param->setInvalidDecl();
 
@@ -150,6 +165,46 @@
   return Param;
 }
 
+
+/// ActOnTemplateTemplateParameter - Called when a C++ template template
+/// parameter (e.g. T in template <template <typename> class T> class array)
+/// has been parsed. S is the current scope.
+Sema::DeclTy *Sema::ActOnTemplateTemplateParameter(Scope* S,
+                                                   SourceLocation TmpLoc,
+                                                   TemplateParamsTy *Params,
+                                                   IdentifierInfo *Name,
+                                                   SourceLocation NameLoc,
+                                                   unsigned Depth,
+                                                   unsigned Position)
+{
+  assert(S->isTemplateParamScope() &&
+         "Template template parameter not in template parameter scope!");
+
+  // Construct the parameter object.
+  TemplateTemplateParmDecl *Param =
+    TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth,
+                                     Position, Name,
+                                     (TemplateParameterList*)Params);
+
+  // Make sure the parameter is valid.
+  // FIXME: Decl object is not currently invalidated anywhere so this doesn't
+  // do anything yet. However, if the template parameter list or (eventual)
+  // default value is ever invalidated, that will propagate here.
+  bool Invalid = false;
+  if (Invalid) {
+    Param->setInvalidDecl();
+  }
+
+  // If the tt-param has a name, then link the identifier into the scope
+  // and lookup mechanisms.
+  if (Name) {
+    S->AddDecl(Param);
+    IdResolver.AddDecl(Param);
+  }
+
+  return Param;
+}
+
 /// ActOnTemplateParameterList - Builds a TemplateParameterList that
 /// contains the template parameters in Params/NumParams.
 Sema::TemplateParamsTy *
@@ -164,3 +219,4 @@
 
   return TemplateParameterList::Create(Context, (Decl**)Params, NumParams);
 }
+