Refactor the parsing of declarations so that template declarations can
parse just a single declaration and provide a reasonable diagnostic
when the "only one declarator per template declaration" rule is
violated. This eliminates some ugly, ugly hackery where we used to
require thatn the layout of a DeclGroup of a single element be the
same as the layout of a single declaration.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71596 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index d38df93..22d1177 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -95,15 +95,102 @@
   } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
 
   // Parse the actual template declaration.
+  return ParseSingleDeclarationAfterTemplate(Context, &ParamLists,
+                                             SourceLocation(),
+                                             DeclEnd, AS);
+}
 
-  // FIXME: This accepts template<typename x> int y;
-  // FIXME: Converting DeclGroupPtr to DeclPtr like this is an insanely gruesome
-  // hack, will bring up on cfe-dev.
-  DeclGroupPtrTy DG = ParseDeclarationOrFunctionDefinition(&ParamLists, AS);
-  // FIXME: Should be ';' location not the token after it.  Resolve with above
-  // fixmes.
-  DeclEnd = Tok.getLocation();
-  return DeclPtrTy::make(DG.get());
+/// \brief Parse a single declaration that declares a template,
+/// template specialization, or explicit instantiation of a template.
+///
+/// \param TemplateParams if non-NULL, the template parameter lists
+/// that preceded this declaration. In this case, the declaration is a
+/// template declaration, out-of-line definition of a template, or an
+/// explicit template specialization. When NULL, the declaration is an
+/// explicit template instantiation.
+///
+/// \param TemplateLoc when TemplateParams is NULL, the location of
+/// the 'template' keyword that indicates that we have an explicit
+/// template instantiation.
+///
+/// \param DeclEnd will receive the source location of the last token
+/// within this declaration.
+///
+/// \param AS the access specifier associated with this
+/// declaration. Will be AS_none for namespace-scope declarations.
+///
+/// \returns the new declaration.
+Parser::DeclPtrTy 
+Parser::ParseSingleDeclarationAfterTemplate(
+                                       unsigned Context,
+                                       TemplateParameterLists *TemplateParams,
+                                       SourceLocation TemplateLoc,
+                                       SourceLocation &DeclEnd,
+                                       AccessSpecifier AS) {
+  // Parse the declaration specifiers.
+  DeclSpec DS;
+  // FIXME: Pass TemplateLoc through for explicit template instantiations
+  ParseDeclarationSpecifiers(DS, TemplateParams, AS);
+
+  if (Tok.is(tok::semi)) {
+    DeclEnd = ConsumeToken();
+    return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+  }
+
+  // Parse the declarator.
+  Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+  ParseDeclarator(DeclaratorInfo);
+  // Error parsing the declarator?
+  if (!DeclaratorInfo.hasName()) {
+    // If so, skip until the semi-colon or a }.
+    SkipUntil(tok::r_brace, true, true);
+    if (Tok.is(tok::semi))
+      ConsumeToken();
+    return DeclPtrTy();
+  }
+  
+  // If we have a declaration or declarator list, handle it.
+  if (isDeclarationAfterDeclarator()) {
+    // Parse this declaration.
+    DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
+
+    if (Tok.is(tok::comma)) {
+      Diag(Tok, diag::err_multiple_template_declarators)
+        << (TemplateParams == 0);
+      SkipUntil(tok::semi, true, false);
+      return ThisDecl;
+    }
+
+    // Eat the semi colon after the declaration.
+    ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+    return ThisDecl;
+  }
+
+  if (DeclaratorInfo.isFunctionDeclarator() &&
+      isStartOfFunctionDefinition()) {
+    if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+      Diag(Tok, diag::err_function_declared_typedef);
+
+      if (Tok.is(tok::l_brace)) {
+        // This recovery skips the entire function body. It would be nice
+        // to simply call ParseFunctionDefinition() below, however Sema
+        // assumes the declarator represents a function, not a typedef.
+        ConsumeBrace();
+        SkipUntil(tok::r_brace, true);
+      } else {
+        SkipUntil(tok::semi);
+      }
+      return DeclPtrTy();
+    }
+    return ParseFunctionDefinition(DeclaratorInfo);
+  }
+
+  if (DeclaratorInfo.isFunctionDeclarator())
+    Diag(Tok, diag::err_expected_fn_body);
+  else
+    Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
+  SkipUntil(tok::semi);
+  return DeclPtrTy();
 }
 
 /// ParseTemplateParameters - Parses a template-parameter-list enclosed in
@@ -693,3 +780,16 @@
   return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
 }
 
+/// \brief Parse a C++ explicit template instantiation 
+/// (C++ [temp.explicit]).
+///
+///       explicit-instantiation:
+///         'template' declaration
+Parser::DeclPtrTy Parser::ParseExplicitInstantiation(SourceLocation &DeclEnd) {
+  assert(Tok.is(tok::kw_template) && NextToken().isNot(tok::less) &&
+	 "Token does not start an explicit instantiation.");
+  
+  SourceLocation TemplateLoc = ConsumeToken();
+  return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, 0, 
+                                             TemplateLoc, DeclEnd, AS_none);
+}