Implement parsing for explicit instantiations of class templates, e.g.,

  template class X<int>;

This also cleans up the propagation of template information through
declaration parsing, which is used to improve some diagnostics.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71608 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 0718d3b..5650396 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -392,7 +392,7 @@
 ///         'union'
 void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
                                  SourceLocation StartLoc, DeclSpec &DS,
-                                 TemplateParameterLists *TemplateParams,
+                                 const ParsedTemplateInfo &TemplateInfo,
                                  AccessSpecifier AS) {
   DeclSpec::TST TagType;
   if (TagTokKind == tok::kw_struct)
@@ -475,15 +475,72 @@
 
   // Create the tag portion of the class or class template.
   Action::DeclResult TagOrTempResult;
+  TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+
+  // FIXME: When TK == TK_Reference and we have a template-id, we need
+  // to turn that template-id into a type.
+
   if (TemplateId && TK != Action::TK_Reference) {
-    // Explicit specialization or class template partial
-    // specialization. Let semantic analysis decide.
+    // Explicit specialization, class template partial specialization,
+    // or explicit instantiation.
     ASTTemplateArgsPtr TemplateArgsPtr(Actions, 
                                        TemplateId->getTemplateArgs(),
                                        TemplateId->getTemplateArgIsType(),
                                        TemplateId->NumArgs);
-    TagOrTempResult
-      = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+        TK == Action::TK_Declaration) {
+      // This is an explicit instantiation of a class template.
+      TagOrTempResult
+        = Actions.ActOnExplicitInstantiation(CurScope, 
+                                             TemplateInfo.TemplateLoc, 
+                                             TagType,
+                                             StartLoc, 
+                                             SS,
+                                     TemplateTy::make(TemplateId->Template), 
+                                             TemplateId->TemplateNameLoc, 
+                                             TemplateId->LAngleLoc, 
+                                             TemplateArgsPtr,
+                                      TemplateId->getTemplateArgLocations(),
+                                             TemplateId->RAngleLoc, 
+                                             Attr);
+    } else {
+      // This is an explicit specialization or a class template
+      // partial specialization.
+      TemplateParameterLists FakedParamLists;
+
+      if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+        // This looks like an explicit instantiation, because we have
+        // something like
+        //
+        //   template class Foo<X>
+        //
+        // but it is actually a declaration. Most likely, this was
+        // meant to be an explicit specialization, but the user forgot
+        // the '<>' after 'template'.
+        assert(TK == Action::TK_Definition && "Can only get a definition here");
+
+        SourceLocation LAngleLoc 
+          = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+        Diag(TemplateId->TemplateNameLoc, 
+             diag::err_explicit_instantiation_with_definition)
+          << SourceRange(TemplateInfo.TemplateLoc)
+          << CodeModificationHint::CreateInsertion(LAngleLoc, "<>");
+
+        // Create a fake template parameter list that contains only
+        // "template<>", so that we treat this construct as a class
+        // template specialization.
+        FakedParamLists.push_back(
+          Actions.ActOnTemplateParameterList(0, SourceLocation(), 
+                                             TemplateInfo.TemplateLoc,
+                                             LAngleLoc, 
+                                             0, 0, 
+                                             LAngleLoc));
+        TemplateParams = &FakedParamLists;
+      }
+
+      // Build the class template specialization.
+      TagOrTempResult
+        = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
                        StartLoc, SS,
                        TemplateTy::make(TemplateId->Template), 
                        TemplateId->TemplateNameLoc, 
@@ -495,6 +552,7 @@
                        Action::MultiTemplateParamsArg(Actions, 
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                  TemplateParams? TemplateParams->size() : 0));
+    }
     TemplateId->Destroy();
   } else if (TemplateParams && TK != Action::TK_Reference)
     TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, 
@@ -691,8 +749,8 @@
       
   if (Tok.is(tok::kw_template)) {
     SourceLocation DeclEnd;
-    ParseTemplateDeclarationOrSpecialization(Declarator::MemberContext, DeclEnd,
-                                             AS);
+    ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, 
+                                         AS);
     return;
   }
 
@@ -708,7 +766,7 @@
   // decl-specifier-seq:
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
-  ParseDeclarationSpecifiers(DS, 0, AS);
+  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
 
   if (Tok.is(tok::semi)) {
     ConsumeToken();