Index: test/Parser/cxx/temp/parse-err-1.cpp
===================================================================
--- test/Parser/cxx/temp/parse-err-1.cpp	(revision 0)
+++ test/Parser/cxx/temp/parse-err-1.cpp	(revision 0)
@@ -0,0 +1,4 @@
+
+// Can't export classes... Parse error.
+export class foo { };   // expected-error {{parse error}}
+

Property changes on: test/Parser/cxx/temp/parse-err-1.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: test/Parser/cxx/temp/parse-err-2.cpp
===================================================================
--- test/Parser/cxx/temp/parse-err-2.cpp	(revision 0)
+++ test/Parser/cxx/temp/parse-err-2.cpp	(revision 0)
@@ -0,0 +1,4 @@
+
+// Need braces after template.
+template  { };   // expected-error {{expected '<' after 'template'}}
+

Property changes on: test/Parser/cxx/temp/parse-err-2.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: test/Parser/cxx/temp/temp-2-def.cpp
===================================================================
--- test/Parser/cxx/temp/temp-2-def.cpp	(revision 0)
+++ test/Parser/cxx/temp/temp-2-def.cpp	(revision 0)
@@ -0,0 +1,5 @@
+
+// clang gives a syntax error on the { because foo is a definition and not a
+// declaration.
+template <typename T>
+void foo() { }

Property changes on: test/Parser/cxx/temp/temp-2-def.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: test/Parser/cxx/temp/temp-1.cpp
===================================================================
--- test/Parser/cxx/temp/temp-1.cpp	(revision 0)
+++ test/Parser/cxx/temp/temp-1.cpp	(revision 0)
@@ -0,0 +1,3 @@
+
+template <>
+void foo();

Property changes on: test/Parser/cxx/temp/temp-1.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: test/Parser/cxx/temp/temp-2.cpp
===================================================================
--- test/Parser/cxx/temp/temp-2.cpp	(revision 0)
+++ test/Parser/cxx/temp/temp-2.cpp	(revision 0)
@@ -0,0 +1,3 @@
+
+template <typename T>
+void foo();

Property changes on: test/Parser/cxx/temp/temp-2.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: test/Parser/cxx/temp/temp-3.cpp
===================================================================
--- test/Parser/cxx/temp/temp-3.cpp	(revision 0)
+++ test/Parser/cxx/temp/temp-3.cpp	(revision 0)
@@ -0,0 +1,3 @@
+
+template <typename T, typename U, typename V>
+void foo();

Property changes on: test/Parser/cxx/temp/temp-3.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h	(revision 59242)
+++ include/clang/Parse/Parser.h	(working copy)
@@ -34,21 +34,21 @@
 ///
 class Parser {
   Preprocessor &PP;
-  
+
   /// Tok - The current token we are peeking ahead.  All parsing methods assume
   /// that this is valid.
   Token Tok;
-  
+
   unsigned short ParenCount, BracketCount, BraceCount;
 
   /// Actions - These are the callbacks we invoke as we parse various constructs
   /// in the file.  This refers to the common base class between MinimalActions
   /// and SemaActions for those uses that don't matter.
   Action &Actions;
-  
+
   Scope *CurScope;
   Diagnostic &Diags;
-  
+
   /// ScopeCache - Cache scopes to reduce malloc traffic.
   enum { ScopeCacheSize = 16 };
   unsigned NumCachedScopes;
@@ -67,7 +67,7 @@
   const LangOptions &getLang() const { return PP.getLangOptions(); }
   TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
   Action &getActions() const { return Actions; }
-  
+
   // Type forwarding.  All of these are statically 'void*', but they may all be
   // different actual classes based on the actions in place.
   typedef Action::ExprTy ExprTy;
@@ -79,24 +79,24 @@
   typedef Action::CXXScopeTy CXXScopeTy;
 
   // Parsing methods.
-  
+
   /// ParseTranslationUnit - All in one method that initializes parses, and
   /// shuts down the parser.
   void ParseTranslationUnit();
-  
+
   /// Initialize - Warm up the parser.
   ///
   void Initialize();
-  
-  /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if 
+
+  /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
   /// the EOF was encountered.
   bool ParseTopLevelDecl(DeclTy*& Result);
-  
+
 private:
   //===--------------------------------------------------------------------===//
   // Low-Level token peeking and consumption methods.
   //
-  
+
   /// isTokenParen - Return true if the cur token is '(' or ')'.
   bool isTokenParen() const {
     return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren;
@@ -109,7 +109,7 @@
   bool isTokenBrace() const {
     return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace;
   }
-  
+
   /// isTokenStringLiteral - True if this token is a string-literal.
   ///
   bool isTokenStringLiteral() const {
@@ -127,7 +127,7 @@
             Tok.is(tok::annot_cxxscope) ||
             (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)));
   }
-  
+
   /// isTokenUnqualifiedId - True if token is the start of C++ unqualified-id
   /// or an identifier in C.
   ///
@@ -139,7 +139,7 @@
   /// [C++]   template-id      [TODO]
   ///
   bool isTokenUnqualifiedId() const {
-    return Tok.is(tok::identifier)  ||   // identifier or template-id 
+    return Tok.is(tok::identifier)  ||   // identifier or template-id
            Tok.is(tok::kw_operator) ||   // operator/conversion-function-id or
                                          // template-id
            (Tok.is(tok::tilde) && getLang().CPlusPlus); // '~' class-name
@@ -157,7 +157,7 @@
     PP.Lex(Tok);
     return L;
   }
-  
+
   /// ConsumeAnyToken - Dispatch to the right Consume* method based on the
   /// current token type.  This should only be used in cases where the type of
   /// the token really isn't known, e.g. in error recovery.
@@ -173,7 +173,7 @@
     else
       return ConsumeToken();
   }
-  
+
   /// ConsumeParen - This consume method keeps the paren count up-to-date.
   ///
   SourceLocation ConsumeParen() {
@@ -186,7 +186,7 @@
     PP.Lex(Tok);
     return L;
   }
-  
+
   /// ConsumeBracket - This consume method keeps the bracket count up-to-date.
   ///
   SourceLocation ConsumeBracket() {
@@ -195,12 +195,12 @@
       ++BracketCount;
     else if (BracketCount)
       --BracketCount;     // Don't let unbalanced ]'s drive the count negative.
-    
+
     SourceLocation L = Tok.getLocation();
     PP.Lex(Tok);
     return L;
   }
-      
+
   /// ConsumeBrace - This consume method keeps the brace count up-to-date.
   ///
   SourceLocation ConsumeBrace() {
@@ -209,12 +209,12 @@
       ++BraceCount;
     else if (BraceCount)
       --BraceCount;     // Don't let unbalanced }'s drive the count negative.
-    
+
     SourceLocation L = Tok.getLocation();
     PP.Lex(Tok);
     return L;
   }
-  
+
   /// ConsumeStringToken - Consume the current 'peek token', lexing a new one
   /// and returning the token kind.  This method is specific to strings, as it
   /// handles string literal concatenation, as per C99 5.1.1.2, translation
@@ -226,7 +226,7 @@
     PP.Lex(Tok);
     return L;
   }
-  
+
   /// GetLookAheadToken - This peeks ahead N tokens and returns that token
   /// without consuming any tokens.  LookAhead(0) returns 'Tok', LookAhead(1)
   /// returns the token after Tok, etc.
@@ -296,8 +296,8 @@
       assert(!isActive && "Forgot to call Commit or Revert!");
     }
   };
-  
-  
+
+
   /// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
   /// this helper function matches and consumes the specified RHS token if
   /// present.  If not present, it emits the specified diagnostic indicating
@@ -306,7 +306,7 @@
   /// of the consumed token.
   SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok,
                                      SourceLocation LHSLoc);
-  
+
   /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
   /// input.  If so, it is consumed and false is returned.
   ///
@@ -319,16 +319,16 @@
 
   //===--------------------------------------------------------------------===//
   // Scope manipulation
-  
+
   /// EnterScope - Start a new scope.
   void EnterScope(unsigned ScopeFlags);
-  
+
   /// ExitScope - Pop a scope off the scope stack.
   void ExitScope();
 
   //===--------------------------------------------------------------------===//
   // Diagnostic Emission and Error recovery.
-    
+
   bool Diag(SourceLocation Loc, unsigned DiagID,
             const std::string &Msg = std::string());
   bool Diag(SourceLocation Loc, unsigned DiagID, const SourceRange &R);
@@ -338,15 +338,15 @@
             const std::string &M = std::string()) {
     return Diag(Tok.getLocation(), DiagID, M);
   }
-  
+
   /// SkipUntil - Read tokens until we get to the specified token, then consume
   /// it (unless DontConsume is true).  Because we cannot guarantee that the
   /// token will ever occur, this skips to the next token, or to some likely
   /// good stopping point.  If StopAtSemi is true, skipping will stop at a ';'
   /// character.
-  /// 
+  ///
   /// If SkipUntil finds the specified token, it returns true, otherwise it
-  /// returns false.  
+  /// returns false.
   bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
                  bool DontConsume = false) {
     return SkipUntil(&T, 1, StopAtSemi, DontConsume);
@@ -358,7 +358,7 @@
   }
   bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
                  bool StopAtSemi = true, bool DontConsume = false);
- 
+
   typedef Action::ExprResult    ExprResult;
   typedef Action::StmtResult    StmtResult;
   typedef Action::BaseResult    BaseResult;
@@ -410,20 +410,20 @@
   ExprResult ParseAsmStringLiteral();
 
   // Objective-C External Declarations
-  DeclTy *ParseObjCAtDirectives(); 
+  DeclTy *ParseObjCAtDirectives();
   DeclTy *ParseObjCAtClassDeclaration(SourceLocation atLoc);
-  DeclTy *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, 
+  DeclTy *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
                                           AttributeList *prefixAttrs = 0);
-  void ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, 
+  void ParseObjCClassInstanceVariables(DeclTy *interfaceDecl,
                                        SourceLocation atLoc);
   bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclTy*> &P,
-                                   bool WarnOnDeclarations, 
+                                   bool WarnOnDeclarations,
                                    SourceLocation &EndProtoLoc);
   void ParseObjCInterfaceDeclList(DeclTy *interfaceDecl,
                                   tok::ObjCKeywordKind contextKey);
   DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
                                          AttributeList *prefixAttrs = 0);
-  
+
   DeclTy *ObjCImpDecl;
 
   DeclTy *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
@@ -431,7 +431,7 @@
   DeclTy *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
   DeclTy *ParseObjCPropertySynthesize(SourceLocation atLoc);
   DeclTy *ParseObjCPropertyDynamic(SourceLocation atLoc);
-  
+
   IdentifierInfo *ParseObjCSelector(SourceLocation &MethodLocation);
   // Definitions for Objective-c context sensitive keywords recognition.
   enum ObjCTypeQual {
@@ -439,7 +439,7 @@
     objc_NumQuals
   };
   IdentifierInfo *ObjCTypeQuals[objc_NumQuals];
-  
+
   bool isTokIdentifier_in() const;
 
   TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS);
@@ -450,16 +450,16 @@
                               DeclTy *classDecl,
             tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
   void ParseObjCPropertyAttribute(ObjCDeclSpec &DS);
-  
+
   DeclTy *ParseObjCMethodDefinition();
-  
+
   //===--------------------------------------------------------------------===//
   // C99 6.5: Expressions.
 
   ExprResult ParseExpression();
   ExprResult ParseConstantExpression();
   ExprResult ParseAssignmentExpression();  // Expr that doesn't include commas.
-  
+
   ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
 
   ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec);
@@ -473,7 +473,7 @@
 
   /// ParseExpressionList - Used for C/C++ (argument-)expression-list.
   bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs);
-  
+
   /// ParenParseOption - Control what ParseParenExpression will parse.
   enum ParenParseOption {
     SimpleExpr,      // Only parse '(' expression ')'
@@ -483,7 +483,7 @@
   };
   ExprResult ParseParenExpression(ParenParseOption &ExprType, TypeTy *&CastTy,
                                   SourceLocation &RParenLoc);
-  
+
   ExprResult ParseSimpleParenExpression() {  // Parse SimpleExpr only.
     SourceLocation RParenLoc;
     return ParseSimpleParenExpression(RParenLoc);
@@ -499,7 +499,7 @@
   // C++ Expressions
   ExprResult ParseCXXIdExpression();
   void ParseCXXScopeSpecifier(CXXScopeSpec &SS);
-  
+
   //===--------------------------------------------------------------------===//
   // C++ 5.2p1: C++ Casts
   ExprResult ParseCXXCasts();
@@ -540,7 +540,7 @@
 
   //===--------------------------------------------------------------------===//
   // C99 6.7.8: Initialization.
-  
+
   /// ParseInitializer
   ///       initializer: [C99 6.7.8]
   ///         assignment-expression
@@ -553,25 +553,25 @@
   ExprResult ParseBraceInitializer();
   ExprResult ParseInitializerWithPotentialDesignator(InitListDesignations &D,
                                                      unsigned InitNum);
-  
+
   //===--------------------------------------------------------------------===//
   // clang Expressions
-  
+
   ExprResult ParseBlockLiteralExpression();  // ^{...}
 
   //===--------------------------------------------------------------------===//
   // Objective-C Expressions
-  
+
   bool isTokObjCMessageIdentifierReceiver() const {
     if (!Tok.is(tok::identifier))
       return false;
-    
+
     if (Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
       return true;
-    
+
     return Tok.getIdentifierInfo() == Ident_super;
   }
-  
+
   ExprResult ParseObjCAtExpression(SourceLocation AtLocation);
   ExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
   ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
@@ -584,10 +584,10 @@
   ExprResult ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracloc,
                                                          IdentifierInfo *ReceiverName,
                                                          ExprTy *ReceiverExpr);
-    
+
   //===--------------------------------------------------------------------===//
   // C99 6.8: Statements and Blocks.
-  
+
   StmtResult ParseStatement() { return ParseStatementOrDeclaration(true); }
   StmtResult ParseStatementOrDeclaration(bool OnlyStatement = false);
   StmtResult ParseLabeledStatement();
@@ -617,17 +617,17 @@
 
   //===--------------------------------------------------------------------===//
   // C99 6.7: Declarations.
-  
+
   DeclTy *ParseDeclaration(unsigned Context);
   DeclTy *ParseSimpleDeclaration(unsigned Context);
   DeclTy *ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D);
-  DeclTy *ParseFunctionStatementBody(DeclTy *Decl, 
+  DeclTy *ParseFunctionStatementBody(DeclTy *Decl,
                                      SourceLocation L, SourceLocation R);
   void ParseDeclarationSpecifiers(DeclSpec &DS);
-  bool MaybeParseTypeSpecifier(DeclSpec &DS, int &isInvalid, 
+  bool MaybeParseTypeSpecifier(DeclSpec &DS, int &isInvalid,
                                const char *&PrevSpec);
   void ParseSpecifierQualifierList(DeclSpec &DS);
-  
+
   void ParseObjCTypeQualifierList(ObjCDeclSpec &DS);
 
   void ParseEnumSpecifier(DeclSpec &DS);
@@ -636,7 +636,7 @@
                             DeclTy *TagDecl);
   void ParseStructDeclaration(DeclSpec &DS,
                               llvm::SmallVectorImpl<FieldDeclarator> &Fields);
-                              
+
   bool isDeclarationSpecifier();
   bool isTypeSpecifierQualifier();
   bool isTypeQualifier() const;
@@ -774,7 +774,7 @@
         P.Actions.ActOnCXXExitDeclaratorScope(SS);
     }
   };
-  
+
   /// ParseDeclarator - Parse and verify a newly-initialized declarator.
   void ParseDeclarator(Declarator &D);
   void ParseDeclaratorInternal(Declarator &D, bool PtrOperator = false);
@@ -787,10 +787,10 @@
   void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
                                              Declarator &D);
   void ParseBracketDeclarator(Declarator &D);
-  
+
   //===--------------------------------------------------------------------===//
   // C++ 7: Declarations [dcl.dcl]
-  
+
   DeclTy *ParseNamespace(unsigned Context);
   DeclTy *ParseLinkage(unsigned Context);
 
@@ -814,6 +814,14 @@
   // C++ 13.5: Overloaded operators [over.oper]
   IdentifierInfo *MaybeParseOperatorFunctionId();
   TypeTy *ParseConversionFunctionId();
+
+  //===--------------------------------------------------------------------===//
+  // C++ 14: Templates [temp]
+  // C++ 14.1: Template Parameters [temp.param]
+  DeclTy *ParseTemplateDeclaration(unsigned Context);
+  void ParseTemplateParameterList(DeclTy *TmpDecl);
+  DeclTy *ParseTemplateParameter();
+  DeclTy *ParseTypeParameter();
 };
 
 }  // end namespace clang
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp	(revision 59242)
+++ lib/Parse/ParseDecl.cpp	(working copy)
@@ -29,11 +29,11 @@
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
   ParseSpecifierQualifierList(DS);
-  
+
   // Parse the abstract-declarator, if present.
   Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
   ParseDeclarator(DeclaratorInfo);
-  
+
   return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
 }
 
@@ -62,10 +62,10 @@
 ///          typespec
 ///          typequal
 ///          storageclass
-///          
+///
 /// FIXME: The GCC grammar/code for this construct implies we need two
-/// token lookahead. Comment from gcc: "If they start with an identifier 
-/// which is followed by a comma or close parenthesis, then the arguments 
+/// token lookahead. Comment from gcc: "If they start with an identifier
+/// which is followed by a comma or close parenthesis, then the arguments
 /// start with that identifier; otherwise they are an expression list."
 ///
 /// At the moment, I am not doing 2 token lookahead. I am also unaware of
@@ -75,9 +75,9 @@
 
 AttributeList *Parser::ParseAttributes() {
   assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
-  
+
   AttributeList *CurrAttr = 0;
-  
+
   while (Tok.is(tok::kw___attribute)) {
     ConsumeToken();
     if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
@@ -92,8 +92,8 @@
     // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
     while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
            Tok.is(tok::comma)) {
-           
-      if (Tok.is(tok::comma)) { 
+
+      if (Tok.is(tok::comma)) {
         // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
         ConsumeToken();
         continue;
@@ -101,26 +101,26 @@
       // we have an identifier or declaration specifier (const, int, etc.)
       IdentifierInfo *AttrName = Tok.getIdentifierInfo();
       SourceLocation AttrNameLoc = ConsumeToken();
-      
+
       // check if we have a "paramterized" attribute
       if (Tok.is(tok::l_paren)) {
         ConsumeParen(); // ignore the left paren loc for now
-        
+
         if (Tok.is(tok::identifier)) {
           IdentifierInfo *ParmName = Tok.getIdentifierInfo();
           SourceLocation ParmLoc = ConsumeToken();
-          
-          if (Tok.is(tok::r_paren)) { 
+
+          if (Tok.is(tok::r_paren)) {
             // __attribute__(( mode(byte) ))
             ConsumeParen(); // ignore the right paren loc for now
-            CurrAttr = new AttributeList(AttrName, AttrNameLoc, 
+            CurrAttr = new AttributeList(AttrName, AttrNameLoc,
                                          ParmName, ParmLoc, 0, 0, CurrAttr);
           } else if (Tok.is(tok::comma)) {
             ConsumeToken();
             // __attribute__(( format(printf, 1, 2) ))
             llvm::SmallVector<ExprTy*, 8> ArgExprs;
             bool ArgExprsOk = true;
-            
+
             // now parse the non-empty comma separated list of expressions
             while (1) {
               ExprResult ArgExpr = ParseAssignmentExpression();
@@ -137,22 +137,22 @@
             }
             if (ArgExprsOk && Tok.is(tok::r_paren)) {
               ConsumeParen(); // ignore the right paren loc for now
-              CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, 
+              CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
                            ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr);
             }
           }
         } else { // not an identifier
           // parse a possibly empty comma separated list of expressions
-          if (Tok.is(tok::r_paren)) { 
+          if (Tok.is(tok::r_paren)) {
             // __attribute__(( nonnull() ))
             ConsumeParen(); // ignore the right paren loc for now
-            CurrAttr = new AttributeList(AttrName, AttrNameLoc, 
+            CurrAttr = new AttributeList(AttrName, AttrNameLoc,
                                          0, SourceLocation(), 0, 0, CurrAttr);
-          } else { 
+          } else {
             // __attribute__(( aligned(16) ))
             llvm::SmallVector<ExprTy*, 8> ArgExprs;
             bool ArgExprsOk = true;
-            
+
             // now parse the list of expressions
             while (1) {
               ExprResult ArgExpr = ParseAssignmentExpression();
@@ -170,19 +170,19 @@
             // Match the ')'.
             if (ArgExprsOk && Tok.is(tok::r_paren)) {
               ConsumeParen(); // ignore the right paren loc for now
-              CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, 
-                           SourceLocation(), &ArgExprs[0], ArgExprs.size(), 
+              CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+                           SourceLocation(), &ArgExprs[0], ArgExprs.size(),
                            CurrAttr);
             }
           }
         }
       } else {
-        CurrAttr = new AttributeList(AttrName, AttrNameLoc, 
+        CurrAttr = new AttributeList(AttrName, AttrNameLoc,
                                      0, SourceLocation(), 0, 0, CurrAttr);
       }
     }
     if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
-      SkipUntil(tok::r_paren, false); 
+      SkipUntil(tok::r_paren, false);
     if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
       SkipUntil(tok::r_paren, false);
   }
@@ -197,11 +197,16 @@
 ///         block-declaration ->
 ///           simple-declaration
 ///           others                   [FIXME]
+/// [C++]   template-declaration
 /// [C++]   namespace-definition
 ///         others... [FIXME]
 ///
 Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
   switch (Tok.getKind()) {
+  case tok::kw_export:
+  case tok::kw_template:
+    // TODO There's also the case of 'export template'. Can I look ahead?
+    return ParseTemplateDeclaration(Context);
   case tok::kw_namespace:
     return ParseNamespace(Context);
   default:
@@ -217,17 +222,17 @@
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
   ParseDeclarationSpecifiers(DS);
-  
+
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
   // declaration-specifiers init-declarator-list[opt] ';'
   if (Tok.is(tok::semi)) {
     ConsumeToken();
     return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
   }
-  
+
   Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
   ParseDeclarator(DeclaratorInfo);
-  
+
   return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
 }
 
@@ -253,11 +258,11 @@
 ///
 Parser::DeclTy *Parser::
 ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
-  
+
   // Declarators may be grouped together ("int X, *Y, Z();").  Provide info so
   // that they can be chained properly if the actions want this.
   Parser::DeclTy *LastDeclInGroup = 0;
-  
+
   // At this point, we know that it is not a function definition.  Parse the
   // rest of the init-declarator-list.
   while (1) {
@@ -268,17 +273,17 @@
         SkipUntil(tok::semi);
         return 0;
       }
-      
+
       D.setAsmLabel(AsmLabel.Val);
     }
-    
+
     // If attributes are present, parse them.
     if (Tok.is(tok::kw___attribute))
       D.AddAttributes(ParseAttributes());
 
     // Inform the current actions module that we just parsed this declarator.
     LastDeclInGroup = Actions.ActOnDeclarator(CurScope, D, LastDeclInGroup);
-        
+
     // Parse declarator '=' initializer.
     if (Tok.is(tok::equal)) {
       ConsumeToken();
@@ -312,18 +317,18 @@
     } else {
       Actions.ActOnUninitializedDecl(LastDeclInGroup);
     }
-    
+
     // If we don't have a comma, it is either the end of the list (a ';') or an
     // error, bail out.
     if (Tok.isNot(tok::comma))
       break;
-    
+
     // Consume the comma.
     ConsumeToken();
-    
+
     // Parse the next declarator.
     D.clear();
-    
+
     // Accept attributes in an init-declarator.  In the first declarator in a
     // declaration, these would be part of the declspec.  In subsequent
     // declarators, they become part of the declarator itself, so that they
@@ -333,10 +338,10 @@
     //    short x, __attribute__((common)) var;    -> declarator
     if (Tok.is(tok::kw___attribute))
       D.AddAttributes(ParseAttributes());
-    
+
     ParseDeclarator(D);
   }
-  
+
   if (Tok.is(tok::semi)) {
     ConsumeToken();
     return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
@@ -365,12 +370,12 @@
   /// specifier-qualifier-list is a subset of declaration-specifiers.  Just
   /// parse declaration-specifiers and complain about extra stuff.
   ParseDeclarationSpecifiers(DS);
-  
+
   // Validate declspec for type-name.
   unsigned Specs = DS.getParsedSpecifiers();
   if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers())
     Diag(Tok, diag::err_typename_requires_specqual);
-  
+
   // Issue diagnostic and remove storage class if present.
   if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
     if (DS.getStorageClassSpecLoc().isValid())
@@ -379,7 +384,7 @@
       Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
     DS.ClearStorageClassSpecs();
   }
-  
+
   // Issue diagnostic and remove function specfier if present.
   if (Specs & DeclSpec::PQ_FunctionSpecifier) {
     if (DS.isInlineSpecified())
@@ -421,9 +426,9 @@
     // Only annotate C++ scope. Allow class-name as an identifier in case
     // it's a constructor.
     TryAnnotateScopeToken();
-    
+
     switch (Tok.getKind()) {
-    default: 
+    default:
       // Try to parse a type-specifier; if we found one, continue.
       if (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec))
         continue;
@@ -465,7 +470,7 @@
                                      TypeRep);
       if (isInvalid)
         break;
-      
+
       DS.SetRangeEnd(Tok.getLocation());
       ConsumeToken(); // The typename.
 
@@ -479,19 +484,19 @@
       //  typedef int X; struct Y { short X; };  as 'short int'.
       if (DS.hasTypeSpecifier())
         goto DoneWithDeclSpec;
-      
+
       // It has to be available as a typedef too!
       TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
       if (TypeRep == 0)
         goto DoneWithDeclSpec;
-      
+
       // C++: If the identifier is actually the name of the class type
       // being defined and the next token is a '(', then this is a
       // constructor declaration. We're done with the decl-specifiers
       // and will treat this token as an identifier.
-      if (getLang().CPlusPlus && 
+      if (getLang().CPlusPlus &&
           CurScope->isCXXClassScope() &&
-          Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && 
+          Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
           NextToken().getKind() == tok::l_paren)
         goto DoneWithDeclSpec;
 
@@ -499,7 +504,7 @@
                                      TypeRep);
       if (isInvalid)
         break;
-      
+
       DS.SetRangeEnd(Tok.getLocation());
       ConsumeToken(); // The identifier
 
@@ -509,12 +514,12 @@
       // just a normal reference to a typedef name.
       if (!Tok.is(tok::less) || !getLang().ObjC1)
         continue;
-      
+
       SourceLocation EndProtoLoc;
       llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
       ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
       DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
-      
+
       DS.SetRangeEnd(EndProtoLoc);
 
       // Need to support trailing type qualifiers (e.g. "id<p> const").
@@ -525,7 +530,7 @@
     case tok::kw___attribute:
       DS.AddAttributes(ParseAttributes());
       continue;
-      
+
     // storage-class-specifier
     case tok::kw_typedef:
       isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
@@ -553,9 +558,9 @@
     case tok::kw___thread:
       isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
       break;
-      
+
       continue;
-          
+
     // function-specifier
     case tok::kw_inline:
       isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
@@ -568,14 +573,14 @@
     case tok::kw_explicit:
       isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec);
       break;
-      
+
     case tok::less:
       // GCC ObjC supports types like "<SomeProtocol>" as a synonym for
       // "id<SomeProtocol>".  This is hopelessly old fashioned and dangerous,
       // but we support it.
       if (DS.hasTypeSpecifier() || !getLang().ObjC1)
         goto DoneWithDeclSpec;
-        
+
       {
         SourceLocation EndProtoLoc;
         llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
@@ -658,19 +663,19 @@
                                    Tok.getAnnotationValue());
     DS.SetRangeEnd(Tok.getAnnotationEndLoc());
     ConsumeToken(); // The typename
-    
+
     // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
     // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
     // Objective-C interface.  If we don't have Objective-C or a '<', this is
     // just a normal reference to a typedef name.
     if (!Tok.is(tok::less) || !getLang().ObjC1)
       return true;
-    
+
     SourceLocation EndProtoLoc;
     llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
     ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
     DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
-    
+
     DS.SetRangeEnd(EndProtoLoc);
     return true;
   }
@@ -803,11 +808,11 @@
     ConsumeToken();
     return ParseStructDeclaration(DS, Fields);
   }
-  
+
   // Parse the common specifier-qualifiers-list piece.
   SourceLocation DSStart = Tok.getLocation();
   ParseSpecifierQualifierList(DS);
-  
+
   // If there are no declarators, issue a warning.
   if (Tok.is(tok::semi)) {
     Diag(DSStart, diag::w_no_declarators);
@@ -818,12 +823,12 @@
   Fields.push_back(FieldDeclarator(DS));
   while (1) {
     FieldDeclarator &DeclaratorInfo = Fields.back();
-    
+
     /// struct-declarator: declarator
     /// struct-declarator: declarator[opt] ':' constant-expression
     if (Tok.isNot(tok::colon))
       ParseDeclarator(DeclaratorInfo.D);
-    
+
     if (Tok.is(tok::colon)) {
       ConsumeToken();
       ExprResult Res = ParseConstantExpression();
@@ -832,22 +837,22 @@
       else
         DeclaratorInfo.BitfieldSize = Res.Val;
     }
-    
+
     // If attributes exist after the declarator, parse them.
     if (Tok.is(tok::kw___attribute))
       DeclaratorInfo.D.AddAttributes(ParseAttributes());
-    
+
     // If we don't have a comma, it is either the end of the list (a ';')
     // or an error, bail out.
     if (Tok.isNot(tok::comma))
       return;
-    
+
     // Consume the comma.
     ConsumeToken();
-    
+
     // Parse the next declarator.
     Fields.push_back(FieldDeclarator(DS));
-    
+
     // Attributes are only allowed on the second declarator.
     if (Tok.is(tok::kw___attribute))
       Fields.back().D.AddAttributes(ParseAttributes());
@@ -867,11 +872,11 @@
 void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
                                   unsigned TagType, DeclTy *TagDecl) {
   SourceLocation LBraceLoc = ConsumeBrace();
-  
+
   // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
   // C++.
   if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
-    Diag(Tok, diag::ext_empty_struct_union_enum, 
+    Diag(Tok, diag::ext_empty_struct_union_enum,
          DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
 
   llvm::SmallVector<DeclTy*, 32> FieldDecls;
@@ -880,7 +885,7 @@
   // While we still have something to read, read the declarations in the struct.
   while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
     // Each iteration of this loop reads one struct-declaration.
-    
+
     // Check for extraneous top-level semicolon.
     if (Tok.is(tok::semi)) {
       Diag(Tok, diag::ext_extra_struct_semi);
@@ -893,7 +898,7 @@
     FieldDeclarators.clear();
     if (!Tok.is(tok::at)) {
       ParseStructDeclaration(DS, FieldDeclarators);
-      
+
       // Convert them all to fields.
       for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
         FieldDeclarator &FD = FieldDeclarators[i];
@@ -923,7 +928,7 @@
       FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
       ConsumeToken();
       ExpectAndConsume(tok::r_paren, diag::err_expected_rparen);
-    } 
+    }
 
     if (Tok.is(tok::semi)) {
       ConsumeToken();
@@ -936,9 +941,9 @@
       SkipUntil(tok::r_brace, true, true);
     }
   }
-  
+
   SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
-  
+
   AttributeList *AttrList = 0;
   // If attributes exist after struct contents, parse them.
   if (Tok.is(tok::kw___attribute))
@@ -947,7 +952,7 @@
   Actions.ActOnFields(CurScope,
                       RecordLoc,TagDecl,&FieldDecls[0],FieldDecls.size(),
                       LBraceLoc, RBraceLoc,
-                      AttrList);  
+                      AttrList);
 }
 
 
@@ -966,7 +971,7 @@
 void Parser::ParseEnumSpecifier(DeclSpec &DS) {
   assert(Tok.is(tok::kw_enum) && "Not an enum specifier");
   SourceLocation StartLoc = ConsumeToken();
-  
+
   // Parse the tag portion of this.
 
   AttributeList *Attr = 0;
@@ -987,16 +992,16 @@
       }
     }
   }
-  
+
   // Must have either 'enum name' or 'enum {...}'.
   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
     Diag(Tok, diag::err_expected_ident_lbrace);
-    
+
     // Skip the rest of this declarator, up until the comma or semicolon.
     SkipUntil(tok::comma, true);
     return;
   }
-  
+
   // If an identifier is present, consume and remember it.
   IdentifierInfo *Name = 0;
   SourceLocation NameLoc;
@@ -1004,7 +1009,7 @@
     Name = Tok.getIdentifierInfo();
     NameLoc = ConsumeToken();
   }
-  
+
   // There are three options here.  If we have 'enum foo;', then this is a
   // forward declaration.  If we have 'enum foo {...' then this is a
   // definition. Otherwise we have something like 'enum foo xyz', a reference.
@@ -1022,10 +1027,10 @@
     TK = Action::TK_Reference;
   DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc,
                                      SS, Name, NameLoc, Attr);
-  
+
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);
-  
+
   // TODO: semantic analysis on the declspec for enums.
   const char *PrevSpec = 0;
   if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl))
@@ -1044,20 +1049,20 @@
 ///
 void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) {
   SourceLocation LBraceLoc = ConsumeBrace();
-  
+
   // C does not allow an empty enumerator-list, C++ does [dcl.enum].
   if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
     Diag(Tok, diag::ext_empty_struct_union_enum, "enum");
-  
+
   llvm::SmallVector<DeclTy*, 32> EnumConstantDecls;
 
   DeclTy *LastEnumConstDecl = 0;
-  
+
   // Parse the enumerator-list.
   while (Tok.is(tok::identifier)) {
     IdentifierInfo *Ident = Tok.getIdentifierInfo();
     SourceLocation IdentLoc = ConsumeToken();
-    
+
     SourceLocation EqualLoc;
     ExprTy *AssignedVal = 0;
     if (Tok.is(tok::equal)) {
@@ -1068,7 +1073,7 @@
       else
         AssignedVal = Res.Val;
     }
-    
+
     // Install the enumerator constant into EnumDecl.
     DeclTy *EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
                                                       LastEnumConstDecl,
@@ -1076,21 +1081,21 @@
                                                       EqualLoc, AssignedVal);
     EnumConstantDecls.push_back(EnumConstDecl);
     LastEnumConstDecl = EnumConstDecl;
-    
+
     if (Tok.isNot(tok::comma))
       break;
     SourceLocation CommaLoc = ConsumeToken();
-    
+
     if (Tok.isNot(tok::identifier) && !getLang().C99)
       Diag(CommaLoc, diag::ext_c99_enumerator_list_comma);
   }
-  
+
   // Eat the }.
   MatchRHSPunctuation(tok::r_brace, LBraceLoc);
 
   Actions.ActOnEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0],
                         EnumConstantDecls.size());
-  
+
   DeclTy *AttrList = 0;
   // If attributes exist after the identifier list, parse them.
   if (Tok.is(tok::kw___attribute))
@@ -1122,7 +1127,7 @@
   case tok::kw___attribute:
     // GNU typeof support.
   case tok::kw_typeof:
-  
+
     // type-specifiers
   case tok::kw_short:
   case tok::kw_long:
@@ -1141,14 +1146,14 @@
   case tok::kw__Decimal32:
   case tok::kw__Decimal64:
   case tok::kw__Decimal128:
-    
+
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
-    
+
     // type-qualifier
   case tok::kw_const:
   case tok::kw_volatile:
@@ -1157,7 +1162,7 @@
     // typedef-name
   case tok::annot_qualtypename:
     return true;
-      
+
     // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
   case tok::less:
     return getLang().ObjC1;
@@ -1180,7 +1185,7 @@
   case tok::kw_auto:
   case tok::kw_register:
   case tok::kw___thread:
-    
+
     // type-specifiers
   case tok::kw_short:
   case tok::kw_long:
@@ -1199,14 +1204,14 @@
   case tok::kw__Decimal32:
   case tok::kw__Decimal64:
   case tok::kw__Decimal128:
-  
+
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
-    
+
     // type-qualifier
   case tok::kw_const:
   case tok::kw_volatile:
@@ -1222,11 +1227,11 @@
 
     // GNU typeof support.
   case tok::kw_typeof:
-    
+
     // GNU attributes.
   case tok::kw___attribute:
     return true;
-  
+
     // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
   case tok::less:
     return getLang().ObjC1;
@@ -1269,7 +1274,7 @@
       DS.AddAttributes(ParseAttributes());
       continue; // do *not* consume the next token!
     }
-    
+
     // If the specifier combination wasn't legal, issue a diagnostic.
     if (isInvalid) {
       assert(PrevSpec && "Method did not return previous specifier!");
@@ -1320,16 +1325,16 @@
       ParseDirectDeclarator(D);
     return;
   }
-  
+
   // Otherwise, '*' -> pointer, '^' -> block, '&' -> reference.
   SourceLocation Loc = ConsumeToken();  // Eat the * or &.
 
   if (Kind == tok::star || (Kind == tok::caret && getLang().Blocks)) {
     // Is a pointer.
     DeclSpec DS;
-    
+
     ParseTypeQualifierListOpt(DS);
-  
+
     // Recursively parse the declarator.
     ParseDeclaratorInternal(D, PtrOperator);
     if (Kind == tok::star)
@@ -1338,8 +1343,8 @@
                                                 DS.TakeAttributes()));
     else
       // Remember that we parsed a Block type, and remember the type-quals.
-      D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), 
-                                                     Loc));	
+      D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
+                                                     Loc));
   } else {
     // Is a reference
     DeclSpec DS;
@@ -1412,10 +1417,10 @@
 ///         qualified-id            [TODO]
 ///
 ///       unqualified-id: [C++ 5.1]
-///         identifier 
+///         identifier
 ///         operator-function-id
 ///         conversion-function-id  [TODO]
-///          '~' class-name         
+///          '~' class-name
 ///         template-id             [TODO]
 ///
 void Parser::ParseDirectDeclarator(Declarator &D) {
@@ -1434,10 +1439,10 @@
     assert(Tok.getIdentifierInfo() && "Not an identifier?");
     // Determine whether this identifier is a C++ constructor name or
     // a normal identifier.
-    if (getLang().CPlusPlus && 
+    if (getLang().CPlusPlus &&
         Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
       D.SetConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope),
-                       &PP.getIdentifierTable().getConstructorId(), 
+                       &PP.getIdentifierTable().getConstructorId(),
                        Tok.getLocation());
     else
       D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
@@ -1448,7 +1453,7 @@
     SourceLocation TildeLoc = ConsumeToken();
     if (Tok.is(tok::identifier)) {
       if (TypeTy *Type = ParseClassName())
-        D.SetDestructor(Type, &PP.getIdentifierTable().getDestructorId(), 
+        D.SetDestructor(Type, &PP.getIdentifierTable().getDestructorId(),
                         TildeLoc);
       else
         D.SetIdentifier(0, TildeLoc);
@@ -1465,8 +1470,8 @@
     } else {
       // This must be a conversion function (C++ [class.conv.fct]).
       if (TypeTy *ConvType = ParseConversionFunctionId()) {
-        D.SetConversionFunction(ConvType, 
-                                &PP.getIdentifierTable().getConversionFunctionId(), 
+        D.SetConversionFunction(ConvType,
+                                &PP.getIdentifierTable().getConversionFunctionId(),
                                 OperatorLoc);
       }
     }
@@ -1487,10 +1492,10 @@
     D.SetIdentifier(0, Tok.getLocation());
     D.setInvalidType(true);
   }
-  
+
   assert(D.isPastIdentifier() &&
          "Haven't past the location of the identifier yet?");
-  
+
   while (1) {
     if (Tok.is(tok::l_paren)) {
       // The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -1514,7 +1519,7 @@
 
 /// ParseParenDeclarator - We parsed the declarator D up to a paren.  This is
 /// only called before the identifier, so these are most likely just grouping
-/// parens for precedence.  If we find that these are actually function 
+/// parens for precedence.  If we find that these are actually function
 /// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator.
 ///
 ///       direct-declarator:
@@ -1528,7 +1533,7 @@
 void Parser::ParseParenDeclarator(Declarator &D) {
   SourceLocation StartLoc = ConsumeParen();
   assert(!D.isPastIdentifier() && "Should be called before passing identifier");
-  
+
   // Eat any attributes before we look at whether this is a grouping or function
   // declarator paren.  If this is a grouping paren, the attribute applies to
   // the type being built up, for example:
@@ -1543,18 +1548,18 @@
   bool RequiresArg = false;
   if (Tok.is(tok::kw___attribute)) {
     AttrList = ParseAttributes();
-    
+
     // We require that the argument list (if this is a non-grouping paren) be
     // present even if the attribute list was empty.
     RequiresArg = true;
   }
-  
+
   // If we haven't past the identifier yet (or where the identifier would be
   // stored, if this is an abstract declarator), then this is probably just
   // grouping parens. However, if this could be an abstract-declarator, then
   // this could also be the start of function arguments (consider 'void()').
   bool isGrouping;
-  
+
   if (!D.mayOmitIdentifier()) {
     // If this can't be an abstract-declarator, this *must* be a grouping
     // paren, because we haven't seen the identifier yet.
@@ -1569,7 +1574,7 @@
     // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'.
     isGrouping = true;
   }
-  
+
   // If this is a grouping paren, handle:
   // direct-declarator: '(' declarator ')'
   // direct-declarator: '(' attributes declarator ')'
@@ -1586,7 +1591,7 @@
     D.setGroupingParens(hadGroupingParens);
     return;
   }
-  
+
   // Okay, if this wasn't a grouping paren, it must be the start of a function
   // argument list.  Recognize that this declarator will never have an
   // identifier (and remember where it would have been), then call into
@@ -1619,8 +1624,8 @@
 ///         declaration-specifiers declarator
 /// [C++]   declaration-specifiers declarator '=' assignment-expression
 /// [GNU]   declaration-specifiers declarator attributes
-///         declaration-specifiers abstract-declarator[opt] 
-/// [C++]   declaration-specifiers abstract-declarator[opt] 
+///         declaration-specifiers abstract-declarator[opt]
+/// [C++]   declaration-specifiers abstract-declarator[opt]
 ///           '=' assignment-expression
 /// [GNU]   declaration-specifiers abstract-declarator[opt] attributes
 ///
@@ -1632,7 +1637,7 @@
                                      bool RequiresArg) {
   // lparen is already consumed!
   assert(D.isPastIdentifier() && "Should not call before identifier!");
-  
+
   // This parameter list may be empty.
   if (Tok.is(tok::r_paren)) {
     if (RequiresArg) {
@@ -1657,8 +1662,8 @@
                                                DS.getTypeQualifiers(),
                                                LParenLoc));
     return;
-  } 
-  
+  }
+
   // Alternatively, this parameter list may be an identifier list form for a
   // K&R-style function:  void foo(a,b,c)
   if (!getLang().CPlusPlus && Tok.is(tok::identifier) &&
@@ -1669,26 +1674,26 @@
       Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
       delete AttrList;
     }
-    
+
     // Identifier list.  Note that '(' identifier-list ')' is only allowed for
     // normal declarators, not for abstract-declarators.
     return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
   }
-  
+
   // Finally, a normal, non-empty parameter type list.
-  
+
   // Build up an array of information about the parsed arguments.
   llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
 
   // Enter function-declaration scope, limiting any declarators to the
   // function prototype scope, including parameter declarators.
   EnterScope(Scope::FnScope|Scope::DeclScope);
-  
+
   bool IsVariadic = false;
   while (1) {
     if (Tok.is(tok::ellipsis)) {
       IsVariadic = true;
-      
+
       // Check to see if this is "void(...)" which is not allowed.
       if (!getLang().CPlusPlus && ParamInfo.empty()) {
         // Otherwise, parse parameter type list.  If it starts with an
@@ -1700,9 +1705,9 @@
       ConsumeToken();     // Consume the ellipsis.
       break;
     }
-    
+
     SourceLocation DSStart = Tok.getLocation();
-    
+
     // Parse the declaration-specifiers.
     DeclSpec DS;
 
@@ -1721,20 +1726,20 @@
     // Parse GNU attributes, if present.
     if (Tok.is(tok::kw___attribute))
       ParmDecl.AddAttributes(ParseAttributes());
-    
+
     // Remember this parsed parameter in ParamInfo.
     IdentifierInfo *ParmII = ParmDecl.getIdentifier();
-    
+
     // If no parameter was specified, verify that *something* was specified,
     // otherwise we have a missing type and identifier.
-    if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && 
+    if (DS.getParsedSpecifiers() == DeclSpec::PQ_None &&
         ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) {
       // Completely missing, emit error.
       Diag(DSStart, diag::err_missing_param);
     } else {
       // Otherwise, we have something.  Add it and let semantic analysis try
       // to grok it and add the result to the ParamInfo we are building.
-      
+
       // Inform the actions module about the parameter declarator, so it gets
       // added to the current scope.
       DeclTy *Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
@@ -1745,10 +1750,10 @@
       // C.
       if (Tok.is(tok::equal)) {
         SourceLocation EqualLoc = Tok.getLocation();
-        
+
         // Consume the '='.
         ConsumeToken();
-        
+
         // Parse the default argument
         ExprResult DefArgResult = ParseAssignmentExpression();
         if (DefArgResult.isInvalid) {
@@ -1758,21 +1763,21 @@
           Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.Val);
         }
       }
-      
-      ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, 
+
+      ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
                              ParmDecl.getIdentifierLoc(), Param));
     }
 
     // If the next token is a comma, consume it and keep reading arguments.
     if (Tok.isNot(tok::comma)) break;
-    
+
     // Consume the comma.
     ConsumeToken();
   }
-  
+
   // Leave prototype scope.
   ExitScope();
-  
+
   // If we have the closing ')', eat it.
   MatchRHSPunctuation(tok::r_paren, LParenLoc);
 
@@ -1803,7 +1808,7 @@
   // Build up an array of information about the parsed arguments.
   llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
   llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
-  
+
   // If there was no identifier specified for the declarator, either we are in
   // an abstract-declarator, or we are in a parameter declarator which was found
   // to be abstract.  In abstract-declarators, identifier lists are not valid:
@@ -1816,13 +1821,13 @@
   ParamsSoFar.insert(Tok.getIdentifierInfo());
   ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
                                                  Tok.getLocation(), 0));
-  
+
   ConsumeToken();  // eat the first identifier.
-  
+
   while (Tok.is(tok::comma)) {
     // Eat the comma.
     ConsumeToken();
-    
+
     // If this isn't an identifier, report the error and skip until ')'.
     if (Tok.isNot(tok::identifier)) {
       Diag(Tok, diag::err_expected_ident);
@@ -1835,7 +1840,7 @@
     // Reject 'typedef int y; int test(x, y)', but continue parsing.
     if (Actions.isTypeName(*ParmII, CurScope))
       Diag(Tok, diag::err_unexpected_typedef_ident, ParmII->getName());
-    
+
     // Verify that the argument identifier has not already been mentioned.
     if (!ParamsSoFar.insert(ParmII)) {
       Diag(Tok.getLocation(), diag::err_param_redefinition, ParmII->getName());
@@ -1844,18 +1849,18 @@
       ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
                                                      Tok.getLocation(), 0));
     }
-    
+
     // Eat the identifier.
     ConsumeToken();
   }
-  
+
   // Remember that we parsed a function type, and remember the attributes.  This
   // function type is always a K&R style function type, which is not varargs and
   // has no prototype.
   D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
                                              &ParamInfo[0], ParamInfo.size(),
                                              /*TypeQuals*/0, LParenLoc));
-  
+
   // If we have the closing ')', eat it and we're done.
   MatchRHSPunctuation(tok::r_paren, LParenLoc);
 }
@@ -1867,25 +1872,25 @@
 /// [C99]   direct-declarator '[' type-qual-list[opt] '*' ']'
 void Parser::ParseBracketDeclarator(Declarator &D) {
   SourceLocation StartLoc = ConsumeBracket();
-  
+
   // If valid, this location is the position where we read the 'static' keyword.
   SourceLocation StaticLoc;
   if (Tok.is(tok::kw_static))
     StaticLoc = ConsumeToken();
-  
+
   // If there is a type-qualifier-list, read it now.
   DeclSpec DS;
   ParseTypeQualifierListOpt(DS);
-  
+
   // If we haven't already read 'static', check to see if there is one after the
   // type-qualifier-list.
   if (!StaticLoc.isValid() && Tok.is(tok::kw_static))
     StaticLoc = ConsumeToken();
-  
+
   // Handle "direct-declarator [ type-qual-list[opt] * ]".
   bool isStar = false;
   ExprResult NumElements(false);
-  
+
   // Handle the case where we have '[*]' as the array size.  However, a leading
   // star could be the start of an expression, for example 'X[*p + 4]'.  Verify
   // the the token after the star is a ']'.  Since stars in arrays are
@@ -1901,16 +1906,16 @@
     // Parse the assignment-expression now.
     NumElements = ParseAssignmentExpression();
   }
-  
+
   // If there was an error parsing the assignment-expression, recover.
   if (NumElements.isInvalid) {
     // If the expression was invalid, skip it.
     SkipUntil(tok::r_square);
     return;
   }
-  
+
   MatchRHSPunctuation(tok::r_square, StartLoc);
-    
+
   // If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if
   // it was not a constant expression.
   if (!getLang().C99) {
@@ -1948,7 +1953,7 @@
 
     const char *PrevSpec = 0;
     // Check for duplicate type specifiers.
-    if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, 
+    if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
                            Result.Val))
       Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
 
@@ -1958,7 +1963,7 @@
   }
 
   SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
-  
+
   if (isTypeIdInParens()) {
     TypeTy *Ty = ParseTypeName();
 
@@ -1975,7 +1980,7 @@
       Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
   } else { // we have an expression.
     ExprResult Result = ParseExpression();
-    
+
     if (Result.isInvalid || Tok.isNot(tok::r_paren)) {
       MatchRHSPunctuation(tok::r_paren, LParenLoc);
       return;
@@ -1983,7 +1988,7 @@
     RParenLoc = ConsumeParen();
     const char *PrevSpec = 0;
     // Check for duplicate type specifiers (e.g. "int typeof(int)").
-    if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, 
+    if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
                            Result.Val))
       Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
   }
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp	(revision 0)
+++ lib/Parse/ParseTemplate.cpp	(revision 0)
@@ -0,0 +1,127 @@
+
+#include <iostream>
+
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+
+using namespace clang;
+
+/// Parse a template declaration, which includes the template parameter list
+/// and either a function of class declaration.
+///
+///       template-declaration: [C++ 14: temp]
+///         'export'[opt] 'template' '<' template-parameter-list '>' declaration
+///
+///       template-parameter-list:
+///         template-parameter
+///         template-paraemeter-list ',' template-parameter
+Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context)
+{
+    assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Not in template");
+
+    // Consume the optional export token, if it exists, followed by the
+    // namespace token.
+    if(Tok.is(tok::kw_export)) {
+        SourceLocation ExportLoc = ConsumeToken();
+        if(!Tok.is(tok::kw_template)) {
+            // TODO: Create a better error message here.
+            Diag(Tok.getLocation(), diag::err_parse_error);
+            return 0;
+        }
+    }
+    SourceLocation TemplateLoc = ConsumeToken();
+
+    // Get the template parameter list.
+    if(!Tok.is(tok::less)) {
+        Diag(Tok.getLocation(), diag::err_expected_less_after, "template");
+        return 0;
+    }
+    SourceLocation LAngle = ConsumeToken();
+
+    ParseTemplateParameterList(0);
+
+     if(!Tok.is(tok::greater)) {
+        Diag(Tok.getLocation(), diag::err_expected_greater);
+        return 0;
+    }
+    SourceLocation RAngle = ConsumeToken();
+
+    // Recursively parse the underlying declaration.
+    // return 0;
+
+    // For some reason, this is generating a compiler error when parsing the
+    // declaration. Apparently, ParseDeclaration doesn't want to match a
+    // function-definition, but will match a function declaration. Odd..
+    return ParseDeclaration(Context);
+}
+
+///       template-parameter-list:
+///         template-parameter
+///         template-paraemeter-list ',' template-parameter
+void Parser::ParseTemplateParameterList(DeclTy* TmpDecl)
+{
+    // For now, this is just going to consume the template parameters.
+    // Eventually, we should pass the template decl AST node as a parameter and
+    // apply template parameters as we find them.
+    while(1) {
+        DeclTy* TmpParam = ParseTemplateParameter();
+        if(!TmpParam) {
+            // If we failed to parse a template parameter, skip until we find
+            // a comma or closing brace.
+            SkipUntil(tok::comma, tok::greater, true, true);
+        }
+
+        // Did we find a comma or the end of the template parmeter list?
+        if(Tok.is(tok::comma)) {
+            ConsumeToken();
+        }
+        else if(Tok.is(tok::greater)) {
+            // Don't consume this...
+            break;
+        }
+    }
+}
+
+/// C++ 14.1 Template parameters [temp]
+///
+///       template-parameter:
+///         type-parameter
+///         parameter-declaration
+///
+Parser::DeclTy *Parser::ParseTemplateParameter()
+{
+    // TODO: Note that if we fail to parse a type parameter, then this should
+    // fall back to parsing a parameter-declaration (e.g., T Value or some such).
+    return ParseTypeParameter();
+}
+
+/// C++ 14.1 Template parameters [temp]
+///       type-parameter:
+///         'class' identifier[opt]
+///         'class' identifier[opt] '=' type-id
+///         'typename' identifier[opt]
+///         'typename' identifier[opt] '=' type-id
+///         'template' '<' template-parameter-list '>' class identifier[opt]
+///         'template' '<' template-parameter-list '>' class identifier[opt] = id-expression
+Parser::DeclTy *Parser::ParseTypeParameter()
+{
+    if(Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) {
+        SourceLocation KeyLoc = ConsumeToken();
+        if(!Tok.is(tok::identifier)) {
+            Diag(Tok.getLocation(), diag::err_expected_ident);
+            return 0;
+        }
+        IdentifierInfo* info = Tok.getIdentifierInfo();
+        std::cout << "tparam: "<< info->getName() << std::endl;
+        ConsumeToken();
+    }
+    else if(Tok.is(tok::kw_template)) {
+        // std::cout << "template template parameter" << std::endl;
+    }
+    else {
+        // TODO C++0x, this can be a concept-id
+    }
+    return 0;
+}

Property changes on: lib/Parse/ParseTemplate.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp	(revision 59242)
+++ lib/Parse/ParseDeclCXX.cpp	(working copy)
@@ -36,28 +36,28 @@
 ///
 ///       extension-namespace-definition:
 ///         'namespace' original-namespace-name '{' namespace-body '}'
-///  
+///
 ///       namespace-alias-definition:  [C++ 7.3.2: namespace.alias]
 ///         'namespace' identifier '=' qualified-namespace-specifier ';'
 ///
 Parser::DeclTy *Parser::ParseNamespace(unsigned Context) {
   assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
   SourceLocation NamespaceLoc = ConsumeToken();  // eat the 'namespace'.
-  
+
   SourceLocation IdentLoc;
   IdentifierInfo *Ident = 0;
-  
+
   if (Tok.is(tok::identifier)) {
     Ident = Tok.getIdentifierInfo();
     IdentLoc = ConsumeToken();  // eat the identifier.
   }
-  
+
   // Read label attributes, if present.
   DeclTy *AttrList = 0;
   if (Tok.is(tok::kw___attribute))
     // FIXME: save these somewhere.
     AttrList = ParseAttributes();
-  
+
   if (Tok.is(tok::equal)) {
     // FIXME: Verify no attributes were present.
     // FIXME: parse this.
@@ -73,7 +73,7 @@
 
     while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
       ParseExternalDeclaration();
-    
+
     // Leave the namespace scope.
     ExitScope();
 
@@ -81,13 +81,13 @@
     Actions.ActOnFinishNamespaceDef(NamespcDecl, RBrace);
 
     return NamespcDecl;
-    
+
   } else {
-    unsigned D = Ident ? diag::err_expected_lbrace : 
+    unsigned D = Ident ? diag::err_expected_lbrace :
                          diag::err_expected_ident_lbrace;
     Diag(Tok.getLocation(), D);
   }
-  
+
   return 0;
 }
 
@@ -109,7 +109,7 @@
   SourceLocation Loc = ConsumeStringToken();
   DeclTy *D = 0;
   SourceLocation LBrace, RBrace;
-  
+
   if (Tok.isNot(tok::l_brace)) {
     D = ParseDeclaration(Context);
   } else {
@@ -137,7 +137,7 @@
 ///       class-name: [C++ 9.1]
 ///         identifier
 ///         template-id   [TODO]
-/// 
+///
 Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) {
   // Parse the class-name.
   // FIXME: Alternatively, parse a simple-template-id.
@@ -173,9 +173,9 @@
 ///         class-key nested-name-specifier[opt] simple-template-id
 ///                          base-clause[opt]
 /// [GNU]   class-key attributes[opt] identifier[opt] base-clause[opt]
-/// [GNU]   class-key attributes[opt] nested-name-specifier 
+/// [GNU]   class-key attributes[opt] nested-name-specifier
 ///                          identifier base-clause[opt]
-/// [GNU]   class-key attributes[opt] nested-name-specifier[opt] 
+/// [GNU]   class-key attributes[opt] nested-name-specifier[opt]
 ///                          simple-template-id base-clause[opt]
 ///       class-key:
 ///         'class'
@@ -183,9 +183,9 @@
 ///         'union'
 ///
 ///       elaborated-type-specifier: [C++ dcl.type.elab]
-///         class-key ::[opt] nested-name-specifier[opt] identifier 
-///         class-key ::[opt] nested-name-specifier[opt] 'template'[opt] 
-///                          simple-template-id 
+///         class-key ::[opt] nested-name-specifier[opt] identifier
+///         class-key ::[opt] nested-name-specifier[opt] 'template'[opt]
+///                          simple-template-id
 ///
 ///  Note that the C++ class-specifier and elaborated-type-specifier,
 ///  together, subsume the C99 struct-or-union-specifier:
@@ -200,13 +200,13 @@
 ///         'struct'
 ///         'union'
 void Parser::ParseClassSpecifier(DeclSpec &DS) {
-  assert((Tok.is(tok::kw_class) || 
-          Tok.is(tok::kw_struct) || 
+  assert((Tok.is(tok::kw_class) ||
+          Tok.is(tok::kw_struct) ||
           Tok.is(tok::kw_union)) &&
          "Not a class specifier");
   DeclSpec::TST TagType =
-    Tok.is(tok::kw_class) ? DeclSpec::TST_class : 
-    Tok.is(tok::kw_struct) ? DeclSpec::TST_struct : 
+    Tok.is(tok::kw_class) ? DeclSpec::TST_class :
+    Tok.is(tok::kw_struct) ? DeclSpec::TST_struct :
     DeclSpec::TST_union;
 
   SourceLocation StartLoc = ConsumeToken();
@@ -247,7 +247,7 @@
 
   if (!Name && TK != Action::TK_Definition) {
     // We have a declaration or reference to an anonymous class.
-    Diag(StartLoc, diag::err_anon_type_definition, 
+    Diag(StartLoc, diag::err_anon_type_definition,
          DeclSpec::getSpecifierName(TagType));
 
     // Skip the rest of this declarator, up until the comma or semicolon.
@@ -256,7 +256,7 @@
   }
 
   // Parse the tag portion of this.
-  DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, 
+  DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name,
                                      NameLoc, Attr);
 
   // Parse the optional base clause (C++ only).
@@ -281,7 +281,7 @@
     Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
 }
 
-/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. 
+/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
 ///
 ///       base-clause : [C++ class.derived]
 ///         ':' base-specifier-list
@@ -311,7 +311,7 @@
     // If the next token is a comma, consume it and keep reading
     // base-specifiers.
     if (Tok.isNot(tok::comma)) break;
-    
+
     // Consume the comma.
     ConsumeToken();
   }
@@ -346,14 +346,14 @@
   AccessSpecifier Access = getAccessSpecifierIfPresent();
   if (Access)
     ConsumeToken();
-  
+
   // Parse the 'virtual' keyword (again!), in case it came after the
   // access specifier.
   if (Tok.is(tok::kw_virtual))  {
     SourceLocation VirtualLoc = ConsumeToken();
     if (IsVirtual) {
       // Complain about duplicate 'virtual'
-      Diag(VirtualLoc, diag::err_dup_virtual, 
+      Diag(VirtualLoc, diag::err_dup_virtual,
            SourceRange(VirtualLoc, VirtualLoc));
     }
 
@@ -372,10 +372,10 @@
   TypeTy *BaseType = ParseClassName(&SS);
   if (!BaseType)
     return true;
-  
-  // Find the complete source range for the base-specifier.  
+
+  // Find the complete source range for the base-specifier.
   SourceRange Range(StartLoc, BaseLoc);
-  
+
   // Notify semantic analysis that we have parsed a complete
   // base-specifier.
   return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType,
@@ -509,7 +509,7 @@
       else
         BitfieldSize = Res.Val;
     }
-    
+
     // pure-specifier:
     //   '= 0'
     //
@@ -542,14 +542,14 @@
     // or an error, bail out.
     if (Tok.isNot(tok::comma))
       break;
-    
+
     // Consume the comma.
     ConsumeToken();
-    
+
     // Parse the next declarator.
     DeclaratorInfo.clear();
     BitfieldSize = Init = 0;
-    
+
     // Attributes are only allowed on the second declarator.
     if (Tok.is(tok::kw___attribute))
       DeclaratorInfo.AddAttributes(ParseAttributes());
@@ -610,7 +610,7 @@
   // While we still have something to read, read the member-declarations.
   while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
     // Each iteration of this loop reads one member-declaration.
-    
+
     // Check for extraneous top-level semicolon.
     if (Tok.is(tok::semi)) {
       Diag(Tok, diag::ext_extra_struct_semi);
@@ -630,9 +630,9 @@
     // Parse all the comma separated declarators.
     ParseCXXClassMemberDeclaration(CurAS);
   }
-  
+
   SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
-  
+
   AttributeList *AttrList = 0;
   // If attributes exist after class contents, parse them.
   if (Tok.is(tok::kw___attribute))
@@ -683,19 +683,19 @@
 /// };
 /// @endcode
 ///
-/// [C++]  ctor-initializer: 
-///          ':' mem-initializer-list 
+/// [C++]  ctor-initializer:
+///          ':' mem-initializer-list
 ///
-/// [C++]  mem-initializer-list: 
-///          mem-initializer 
-///          mem-initializer , mem-initializer-list 
+/// [C++]  mem-initializer-list:
+///          mem-initializer
+///          mem-initializer , mem-initializer-list
 void Parser::ParseConstructorInitializer(DeclTy *ConstructorDecl) {
   assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
 
   SourceLocation ColonLoc = ConsumeToken();
-  
+
   llvm::SmallVector<MemInitTy*, 4> MemInitializers;
-  
+
   do {
     MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
     if (!MemInit.isInvalid)
@@ -712,7 +712,7 @@
     }
   } while (true);
 
-  Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, 
+  Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
                                &MemInitializers[0], MemInitializers.size());
 }
 
@@ -723,7 +723,7 @@
 ///
 /// [C++] mem-initializer:
 ///         mem-initializer-id '(' expression-list[opt] ')'
-/// 
+///
 /// [C++] mem-initializer-id:
 ///         '::'[opt] nested-name-specifier[opt] class-name
 ///         identifier
@@ -757,7 +757,7 @@
 
   SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
 
-  return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc, 
-                                     LParenLoc, &ArgExprs[0], ArgExprs.size(), 
+  return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc,
+                                     LParenLoc, &ArgExprs[0], ArgExprs.size(),
                                      &CommaLocs[0], RParenLoc);
 }
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp	(revision 59242)
+++ lib/Parse/Parser.cpp	(working copy)
@@ -300,7 +300,7 @@
   DeclTy *Res;
   while (!ParseTopLevelDecl(Res))
     /*parse them all*/;
-  
+
   ExitScope();
   assert(CurScope == 0 && "Scope imbalance!");
 }
@@ -359,6 +359,8 @@
     return 0;
   case tok::kw_namespace:
   case tok::kw_typedef:
+  case tok::kw_template:
+  case tok::kw_export:    // As in 'export template'
     // A function definition cannot start with a these keywords.
     return ParseDeclaration(Declarator::FileContext);
   default:
@@ -398,7 +400,7 @@
   // attributes here, no types, etc.
   if (getLang().ObjC2 && Tok.is(tok::at)) {
     SourceLocation AtLoc = ConsumeToken(); // the "@"
-    if (!Tok.isObjCAtKeyword(tok::objc_interface) && 
+    if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
         !Tok.isObjCAtKeyword(tok::objc_protocol)) {
       Diag(Tok, diag::err_objc_unexpected_attr);
       SkipUntil(tok::semi); // FIXME: better skip?
@@ -509,7 +511,7 @@
     ParseKNRParamDeclarations(D);
 
   if (getLang().CPlusPlus && Tok.is(tok::colon)) {
-    
+
   }
 
   // We should have either an opening brace or, in a C++ constructor,
