Implement basic parsing and semantic analysis for explicit
specialization of class templates, e.g.,

  template<typename T> class X;

  template<> class X<int> { /* blah */ };

Each specialization is a different *Decl node (naturally), and can
have different members. We keep track of forward declarations and
definitions as for other class/struct/union types.

This is only the basic framework: we still have to deal with checking
the template headers properly, improving recovery when there are
failures, handling nested name specifiers, etc.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64848 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5d601bc..953b552 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -228,7 +228,7 @@
   switch (Tok.getKind()) {
   case tok::kw_export:
   case tok::kw_template:
-    return ParseTemplateDeclaration(Context);
+    return ParseTemplateDeclarationOrSpecialization(Context);
   case tok::kw_namespace:
     return ParseNamespace(Context);
   case tok::kw_using:
@@ -2095,7 +2095,7 @@
       DS.AddAttributes(AttrList);
       AttrList = 0;  // Only apply the attributes to the first parameter.
     }
-    ParseDeclarationSpecifiers(DS);
+    ParseDeclarationSpecifiers(DS);    
 
     // Parse the declarator.  This is "PrototypeContext", because we must
     // accept either 'declarator' or 'abstract-declarator' here.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index d6b83f3..e36bc40 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -310,17 +310,69 @@
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec SS;
   if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+    // FIXME: can we get a class template specialization or
+    // template-id token here?
     if (Tok.isNot(tok::identifier))
       Diag(Tok, diag::err_expected_ident);
   }
 
-  // Parse the (optional) class name.
-  // FIXME: Alternatively, parse a simple-template-id.
+
+  // These variables encode the simple-template-id that we might end
+  // up parsing below. We don't translate this into a type
+  // automatically because (1) we want to create a separate
+  // declaration for each specialization, and (2) we want to retain
+  // more information about source locations that types provide.
+  DeclTy *Template = 0;
+  SourceLocation LAngleLoc, RAngleLoc;
+  TemplateArgList TemplateArgs;
+  TemplateArgIsTypeList TemplateArgIsType;
+  TemplateArgLocationList TemplateArgLocations;
+  ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0);
+  
+
+  // Parse the (optional) class name or simple-template-id.
   IdentifierInfo *Name = 0;
   SourceLocation NameLoc;
   if (Tok.is(tok::identifier)) {
     Name = Tok.getIdentifierInfo();
     NameLoc = ConsumeToken();
+
+    if (Tok.is(tok::less)) {
+      // This is a simple-template-id.
+      Action::TemplateNameKind TNK 
+        = Actions.isTemplateName(*Name, CurScope, Template, &SS);
+
+      bool Invalid = false;
+
+      // Parse the enclosed template argument list.
+      if (TNK != Action::TNK_Non_template)
+        Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc,
+                                                   &SS, true, LAngleLoc, 
+                                                   TemplateArgs,
+                                                   TemplateArgIsType,
+                                                   TemplateArgLocations,
+                                                   RAngleLoc);
+      
+      TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0],
+                            TemplateArgs.size());
+
+      if (TNK != Action::TNK_Class_template) {
+        // The template-name in the simple-template-id refers to
+        // something other than a class template. Give an appropriate
+        // error message and skip to the ';'.
+        SourceRange Range(NameLoc);
+        if (SS.isNotEmpty())
+          Range.setBegin(SS.getBeginLoc());
+        else if (!Invalid)
+          
+        Diag(LAngleLoc, diag::err_template_spec_syntax_non_template)
+          << Name << static_cast<int>(TNK) << Range;
+
+        DS.SetTypeSpecError();
+        SkipUntil(tok::semi, false, true);
+        return;
+      }
+    }
   }
 
   // There are three options here.  If we have 'struct foo;', then
@@ -347,7 +399,23 @@
 
   // Create the tag portion of the class or class template.
   DeclTy *TagOrTempDecl;
-  if (TemplateParams && TK != Action::TK_Reference)
+  if (Template && TK != Action::TK_Reference)
+    // Explicit specialization or class template partial
+    // specialization. Let semantic analysis decide.
+
+    // FIXME: we want a source range covering the simple-template-id.
+    TagOrTempDecl 
+      = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+                                                 StartLoc, SS, /*Range*/
+                                                 Template, NameLoc, 
+                                                 LAngleLoc, TemplateArgsPtr,
+                                                 &TemplateArgLocations[0],
+                                                 RAngleLoc, Attr,
+                       Action::MultiTemplateParamsArg(Actions, 
+                                    TemplateParams? &(*TemplateParams)[0] : 0,
+                                 TemplateParams? TemplateParams->size() : 0));
+
+  else if (TemplateParams && TK != Action::TK_Reference)
     TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc,
                                                SS, Name, NameLoc, Attr,
                        Action::MultiTemplateParamsArg(Actions, 
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 7424530..52824f5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -19,12 +19,23 @@
 
 using namespace clang;
 
-/// ParseTemplateDeclaration - Parse a template declaration, which includes 
-/// the template parameter list and either a function of class declaration.
+/// \brief Parse a template declaration or an explicit specialization.
+///
+/// Template declarations include one or more template parameter lists
+/// and either the function or class template declaration. Explicit
+/// specializations contain one or more 'template < >' prefixes
+/// followed by a (possibly templated) declaration. Since the
+/// syntactic form of both features is nearly identical, we parse all
+/// of the template headers together and let semantic analysis sort
+/// the declarations from the explicit specializations.
 ///
 ///       template-declaration: [C++ temp]
 ///         'export'[opt] 'template' '<' template-parameter-list '>' declaration
-Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
+///
+///       explicit-specialization: [ C++ temp.expl.spec]
+///         'template' '<' '>' declaration
+Parser::DeclTy *
+Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context) {
   assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && 
 	 "Token does not start a template declaration.");
   
@@ -40,7 +51,7 @@
   //
   // We parse multiple levels non-recursively so that we can build a
   // single data structure containing all of the template parameter
-  // lists easily differentiate between the case above and:
+  // lists to easily differentiate between the case above and:
   //
   //   template<typename T>
   //   class A {
@@ -370,6 +381,68 @@
   return Param;
 }
 
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool 
+Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template,
+                                         SourceLocation TemplateNameLoc, 
+                                         const CXXScopeSpec *SS,
+                                         bool ConsumeLastToken,
+                                         SourceLocation &LAngleLoc,
+                                         TemplateArgList &TemplateArgs,
+                                    TemplateArgIsTypeList &TemplateArgIsType,
+                               TemplateArgLocationList &TemplateArgLocations,
+                                         SourceLocation &RAngleLoc) {
+  assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+  // Consume the '<'.
+  LAngleLoc = ConsumeToken();
+
+  // Parse the optional template-argument-list.
+  bool Invalid = false;
+  {
+    GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+    if (Tok.isNot(tok::greater))
+      Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
+                                          TemplateArgLocations);
+
+    if (Invalid) {
+      // Try to find the closing '>'.
+      SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+      return true;
+    }
+  }
+
+  if (Tok.isNot(tok::greater))
+    return true;
+
+  // Determine the location of the '>'. Only consume this token if the
+  // caller asked us to.
+  RAngleLoc = Tok.getLocation();
+
+  if (ConsumeLastToken)
+    ConsumeToken();
+
+  return false;
+}
+                                              
 /// AnnotateTemplateIdToken - The current token is an identifier that
 /// refers to the template declaration Template, and is followed by a
 /// '<'. Turn this template-id into a template-id annotation token.
@@ -382,46 +455,44 @@
   // Consume the template-name.
   SourceLocation TemplateNameLoc = ConsumeToken();
 
-  // Consume the '<'.
-  SourceLocation LAngleLoc = ConsumeToken();
-
-  // Parse the optional template-argument-list.
+  // Parse the enclosed template argument list.
+  SourceLocation LAngleLoc, RAngleLoc;
   TemplateArgList TemplateArgs;
   TemplateArgIsTypeList TemplateArgIsType;
   TemplateArgLocationList TemplateArgLocations;
+  bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+                                                  SS, false, LAngleLoc, 
+                                                  TemplateArgs, 
+                                                  TemplateArgIsType,
+                                                  TemplateArgLocations,
+                                                  RAngleLoc);
 
-  {
-    GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
-    if (Tok.isNot(tok::greater) && 
-        ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
-                                  TemplateArgLocations)) {
-      // Try to find the closing '>'.
-      SkipUntil(tok::greater, true, true);
+  ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
+                                     &TemplateArgIsType[0],
+                                     TemplateArgs.size());
 
-      // Clean up any template arguments that we successfully parsed.
-      ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
-                                         &TemplateArgIsType[0],
-                                         TemplateArgs.size());
-      
-      return;
-    }
-  }
+  if (Invalid) // FIXME: How to recover from a broken template-id?
+    return; 
 
-  if (Tok.isNot(tok::greater))
-    return;
-
-  // Determine the location of the '>'. We won't actually consume this
-  // token, because we'll be replacing it with the template-id.
-  SourceLocation RAngleLoc = Tok.getLocation();
-  
   // Build the annotation token.
-  if (TNK == Action::TNK_Function_template) {
+  if (TNK == Action::TNK_Class_template) {
+    Action::TypeResult Type 
+      = Actions.ActOnClassTemplateId(Template, TemplateNameLoc,
+                                     LAngleLoc, TemplateArgsPtr,
+                                     &TemplateArgLocations[0],
+                                     RAngleLoc, SS);
+    if (Type.isInvalid()) // FIXME: better recovery?
+      return;
+
+    Tok.setKind(tok::annot_typename);
+    Tok.setAnnotationValue(Type.get());
+  } else {
     // This is a function template. We'll be building a template-id
     // annotation token.
     Tok.setKind(tok::annot_template_id);    
     TemplateIdAnnotation *TemplateId 
       = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + 
-                                  sizeof(void*) * TemplateArgs.size());
+                                       sizeof(void*) * TemplateArgs.size());
     TemplateId->TemplateNameLoc = TemplateNameLoc;
     TemplateId->Template = Template;
     TemplateId->LAngleLoc = LAngleLoc;
@@ -430,24 +501,6 @@
     for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
       Args[Arg] = TemplateArgs[Arg];
     Tok.setAnnotationValue(TemplateId);
-  } else {
-    // This is a type template, e.g., a class template, template
-    // template parameter, or template alias. We'll be building a
-    // "typename" annotation token.
-    ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
-                                       &TemplateArgIsType[0],
-                                       TemplateArgs.size());
-    TypeTy *Ty 
-      = Actions.ActOnClassTemplateSpecialization(Template, TemplateNameLoc,
-                                                 LAngleLoc, TemplateArgsPtr,
-                                                 &TemplateArgLocations[0],
-                                                 RAngleLoc, SS);
-
-    if (!Ty) // Something went wrong; don't annotate
-      return;
-
-    Tok.setKind(tok::annot_typename);
-    Tok.setAnnotationValue(Ty);
   }
 
   // Common fields for the annotation token