[cfe-commits] r130022 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Driver/ include/clang/Parse/ include/clang/Sema/ lib/AST/ lib/CodeGen/ lib/Driver/ lib/Frontend/ lib/Parse/ lib/Sema/ test/Parser/ tools/libclang/

Francois Pichet pichet2000 at gmail.com
Fri Apr 22 15:18:13 PDT 2011


Author: fpichet
Date: Fri Apr 22 17:18:13 2011
New Revision: 130022

URL: http://llvm.org/viewvc/llvm-project?rev=130022&view=rev
Log:
Add -fdelayed-template-parsing option. Using this option all templated function definitions are parsed at the end of the translation unit only if it is required by an actual instantiation. As such all the symbols of the TU are available during name lookup.

Using this flag is necessary for compatibility with Microsoft template code.
This also provides some parsing speed improvement.

Added:
    cfe/trunk/test/Parser/DelayedTemplateParsing.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Apr 22 17:18:13 2011
@@ -1294,6 +1294,7 @@
   bool IsDeleted : 1;
   bool IsTrivial : 1; // sunk from CXXMethodDecl
   bool HasImplicitReturnZero : 1;
+  bool IsLateTemplateParsed : 1;
 
   /// \brief End part of this FunctionDecl's source range.
   ///
@@ -1375,7 +1376,8 @@
       IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
       IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
       HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
-      HasImplicitReturnZero(false), EndRangeLoc(NameInfo.getEndLoc()),
+      HasImplicitReturnZero(false), IsLateTemplateParsed(false),
+      EndRangeLoc(NameInfo.getEndLoc()),
       TemplateOrSpecialization(),
       DNLoc(NameInfo.getInfo()) {}
 
@@ -1458,7 +1460,9 @@
   /// previous definition); for that information, use getBody.
   /// FIXME: Should return true if function is deleted or defaulted. However,
   /// CodeGenModule.cpp uses it, and I don't know if this would break it.
-  bool isThisDeclarationADefinition() const { return Body; }
+  bool isThisDeclarationADefinition() const {
+    return Body || IsLateTemplateParsed;
+  }
 
   void setBody(Stmt *B);
   void setLazyBody(uint64_t Offset) { Body = Offset; }
@@ -1475,6 +1479,10 @@
   bool isPure() const { return IsPure; }
   void setPure(bool P = true);
 
+  /// Whether this templated function will be late parsed.
+  bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
+  void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
+
   /// Whether this function is "trivial" in some specialized C++ senses.
   /// Can only be true for default constructors, copy constructors,
   /// copy assignment operators, and destructors.  Not meaningful until

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Fri Apr 22 17:18:13 2011
@@ -130,6 +130,7 @@
                                     // testing languages such as OpenCL.
 
   unsigned MRTD : 1;            // -mrtd calling convention
+  unsigned DelayedTemplateParsing : 1;  // Delayed template parsing
 
 private:
   // We declare multibit enums as unsigned because MSVC insists on making enums
@@ -225,6 +226,7 @@
     NoBitFieldTypeAlign = 0;
     FakeAddressSpaceMap = 0;
     MRTD = 0;
+    DelayedTemplateParsing = 0;
     ParseUnknownAnytype = 0;
   }
 

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Fri Apr 22 17:18:13 2011
@@ -532,6 +532,9 @@
   HelpText<"Enable some traditional CPP emulation">;
 def ffake_address_space_map : Flag<"-ffake-address-space-map">,
   HelpText<"Use a fake address space map; OpenCL testing purposes only">;
+def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">,
+  HelpText<"Parse templated function definitions at the end of the "
+           "translation unit ">;
 def funknown_anytype : Flag<"-funknown-anytype">,
   HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">;
 

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Fri Apr 22 17:18:13 2011
@@ -314,6 +314,7 @@
 def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
 def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>;
 def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>;
+def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, Group<f_Group>;
 def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
 def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
 def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
@@ -349,6 +350,7 @@
 def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
 def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
 def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
+def fno_delayed_template_parsing : Flag<"-fno-delayed-template-parsing">, Group<f_Group>;
 def fno_objc_default_synthesize_properties 
   : Flag<"-fno-objc-default-synthesize-properties">, Group<f_Group>;
 def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>;

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Apr 22 17:18:13 2011
@@ -919,6 +919,27 @@
     SourceRange getSourceRange() const;
   };
 
+  /// \brief Contains a late templated function.
+  /// Will be parsed at the end of the translation unit.
+  struct LateParsedTemplatedFunction {
+    explicit LateParsedTemplatedFunction(Parser* P, Decl *MD)
+      : D(MD) {}
+
+    CachedTokens Toks;
+    
+    /// \brief The template function declaration to be late parsed.
+    Decl *D; 
+  };
+
+  void LexTemplateFunctionForLateParsing(CachedTokens &Toks);
+  void ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT);
+  typedef llvm::DenseMap<const FunctionDecl*, LateParsedTemplatedFunction*>
+    LateParsedTemplateMapT;
+  LateParsedTemplateMapT LateParsedTemplateMap;
+
+  static void LateTemplateParserCallback(void *P, FunctionDecl *FD);
+  void LateTemplateParser(FunctionDecl *FD);
+
   Sema::ParsingClassState
   PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
   void DeallocateParsedClasses(ParsingClass *Class);

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Apr 22 17:18:13 2011
@@ -307,6 +307,16 @@
   /// and must warn if not used. Only contains the first declaration.
   llvm::SmallVector<const DeclaratorDecl*, 4> UnusedFileScopedDecls;
 
+  /// \brief Callback to the parser to parse templated functions when needed.
+  typedef void LateTemplateParserCB(void *P, FunctionDecl *FD);
+  LateTemplateParserCB *LateTemplateParser;
+  void *OpaqueParser; 
+
+  void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) {
+    LateTemplateParser = LTP;
+    OpaqueParser = P; 
+  }
+
   class DelayedDiagnostics;
 
   class ParsingDeclState {
@@ -2974,11 +2984,14 @@
                                          AttributeList *AttrList);
 
   void ActOnReenterTemplateScope(Scope *S, Decl *Template);
+  void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D);
   void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
   void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
   void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param);
   void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
   void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
+  void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
+  bool IsInsideALocalClassWithinATemplateFunction();
 
   Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
                                      Expr *AssertExpr,

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Apr 22 17:18:13 2011
@@ -1413,7 +1413,7 @@
 
 bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
   for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
-    if (I->Body) {
+    if (I->Body || I->IsLateTemplateParsed) {
       Definition = *I;
       return true;
     }
@@ -1427,6 +1427,9 @@
     if (I->Body) {
       Definition = *I;
       return I->Body.get(getASTContext().getExternalSource());
+    } else if (I->IsLateTemplateParsed) {
+      Definition = *I;
+      return 0;
     }
   }
 

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Apr 22 17:18:13 2011
@@ -2031,7 +2031,8 @@
   case Decl::CXXMethod:
   case Decl::Function:
     // Skip function templates
-    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
+        cast<FunctionDecl>(D)->isLateTemplateParsed())
       return;
 
     EmitGlobal(cast<FunctionDecl>(D));
@@ -2060,12 +2061,15 @@
     break;
   case Decl::CXXConstructor:
     // Skip function templates
-    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
+        cast<FunctionDecl>(D)->isLateTemplateParsed())
       return;
       
     EmitCXXConstructors(cast<CXXConstructorDecl>(D));
     break;
   case Decl::CXXDestructor:
+    if (cast<FunctionDecl>(D)->isLateTemplateParsed())
+      return;
     EmitCXXDestructors(cast<CXXDestructorDecl>(D));
     break;
 

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Fri Apr 22 17:18:13 2011
@@ -1605,6 +1605,12 @@
                    options::OPT_fno_borland_extensions, false))
     CmdArgs.push_back("-fborland-extensions");
 
+  // -fno-delayed-template-parsing is default.
+  if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
+                   options::OPT_fno_delayed_template_parsing,
+                   false))
+    CmdArgs.push_back("-fdelayed-template-parsing");
+
   // -fgnu-keywords default varies depending on language; only pass if
   // specified.
   if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Apr 22 17:18:13 2011
@@ -692,6 +692,8 @@
     Res.push_back("-ffake-address-space-map");
   if (Opts.ParseUnknownAnytype)
     Res.push_back("-funknown-anytype");
+  if (Opts.DelayedTemplateParsing)
+    Res.push_back("-fdelayed-template-parsing");
 }
 
 static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
@@ -1436,6 +1438,9 @@
   if (Args.hasArg(OPT_pthread))
     Opts.POSIXThreads = 1;
 
+  if (Args.hasArg(OPT_fdelayed_template_parsing))
+    Opts.DelayedTemplateParsing = 1;
+
   llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
   if (Vis == "default")
     Opts.setVisibilityMode(DefaultVisibility);
@@ -1495,6 +1500,7 @@
   Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
   Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
                                                Diags);
+  Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
   Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy,
                                                     0, Diags);
   Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields);

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Fri Apr 22 17:18:13 2011
@@ -15,6 +15,7 @@
 #include "clang/Parse/Parser.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Scope.h"
+#include "clang/AST/DeclTemplate.h"
 using namespace clang;
 
 /// ParseCXXInlineMethodDef - We parsed and verified that the specified
@@ -46,6 +47,36 @@
 
   D.complete(FnD);
 
+  // In delayed template parsing mode, if we are within a class template
+  // or if we are about to parse function member template then consume
+  // the tokens and store them for parsing at the end of the translation unit.
+  if (getLang().DelayedTemplateParsing && 
+      ((Actions.CurContext->isDependentContext() ||
+        TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && 
+        !Actions.IsInsideALocalClassWithinATemplateFunction()) &&
+        !D.getDeclSpec().isFriendSpecified()) {
+
+    if (FnD) {
+      LateParsedTemplatedFunction *LPT =
+        new LateParsedTemplatedFunction(this, FnD);
+
+      FunctionDecl *FD = 0;
+      if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD))
+        FD = FunTmpl->getTemplatedDecl();
+      else
+        FD = cast<FunctionDecl>(FnD);
+
+      LateParsedTemplateMap[FD] = LPT;
+      Actions.MarkAsLateParsedTemplate(FD);
+      LexTemplateFunctionForLateParsing(LPT->Toks);
+    } else {
+      CachedTokens Toks;
+      LexTemplateFunctionForLateParsing(Toks);
+    }
+
+    return FnD;
+  }
+
   // Consume the tokens and store them for later parsing.
 
   LexedMethod* LM = new LexedMethod(this, FnD);

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Fri Apr 22 17:18:13 2011
@@ -17,6 +17,8 @@
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTConsumer.h"
 using namespace clang;
 
 /// \brief Parse a template declaration, explicit instantiation, or
@@ -1125,3 +1127,125 @@
     R.setBegin(ExternLoc);
   return R;
 }
+
+void Parser::LateTemplateParserCallback(void *P, FunctionDecl *FD) {
+  ((Parser*)P)->LateTemplateParser(FD);
+}
+
+
+void Parser::LateTemplateParser(FunctionDecl *FD) {
+  LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD];
+  if (LPT) {
+    ParseLateTemplatedFuncDef(*LPT);
+    return;
+  }
+
+  llvm_unreachable("Late templated function without associated lexed tokens");
+}
+
+/// \brief Late parse a C++ function template in Microsoft mode.
+void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
+  if(!LMT.D)
+     return;
+
+  // If this is a member template, introduce the template parameter scope.
+  ParseScope TemplateScope(this, Scope::TemplateParamScope);
+
+  // Get the FunctionDecl.
+  FunctionDecl *FD = 0;
+  if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D))
+    FD = FunTmpl->getTemplatedDecl();
+  else
+    FD = cast<FunctionDecl>(LMT.D);
+  
+  // Reinject the template parameters.
+  DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD);
+  if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
+    Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
+    Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+  } else {
+    Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+
+    DeclContext *DD = FD->getLexicalParent();
+    while (DD && DD->isRecord()) {
+      if (ClassTemplatePartialSpecializationDecl* MD =
+                  dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD))
+          Actions.ActOnReenterTemplateScope(getCurScope(), MD);
+      else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD))
+          Actions.ActOnReenterTemplateScope(getCurScope(),
+                                            MD->getDescribedClassTemplate());
+
+      DD = DD->getLexicalParent();
+    }
+  }
+  assert(!LMT.Toks.empty() && "Empty body!");
+
+  // Append the current token at the end of the new token stream so that it
+  // doesn't get lost.
+  LMT.Toks.push_back(Tok);
+  PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
+
+  // Consume the previously pushed token.
+  ConsumeAnyToken();
+  assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
+         && "Inline method not starting with '{', ':' or 'try'");
+
+  // Parse the method body. Function body parsing code is similar enough
+  // to be re-used for method bodies as well.
+  ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+
+  // Recreate the DeclContext.
+  Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD));
+
+  if (FunctionTemplateDecl *FunctionTemplate
+        = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D))
+    Actions.ActOnStartOfFunctionDef(getCurScope(),
+                                   FunctionTemplate->getTemplatedDecl());
+  if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D))
+    Actions.ActOnStartOfFunctionDef(getCurScope(), Function);
+  
+
+  if (Tok.is(tok::kw_try)) {
+    ParseFunctionTryBlock(LMT.D, FnScope);
+    return;
+  }
+  if (Tok.is(tok::colon)) {
+    ParseConstructorInitializer(LMT.D);
+
+    // Error recovery.
+    if (!Tok.is(tok::l_brace)) {
+      Actions.ActOnFinishFunctionBody(LMT.D, 0);
+      return;
+    }
+  } else
+    Actions.ActOnDefaultCtorInitializers(LMT.D);
+
+  ParseFunctionStatementBody(LMT.D, FnScope);
+  Actions.MarkAsLateParsedTemplate(FD, false);
+
+  DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D);
+  if (grp)
+    Actions.getASTConsumer().HandleTopLevelDecl(grp.get());
+}
+
+/// \brief Lex a delayed template function for late parsing.
+void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
+  tok::TokenKind kind = Tok.getKind();
+  // We may have a constructor initializer or function-try-block here.
+  if (kind == tok::colon || kind == tok::kw_try)
+    ConsumeAndStoreUntil(tok::l_brace, Toks);
+  else {
+    Toks.push_back(Tok);
+    ConsumeBrace();
+  }
+  // Consume everything up to (and including) the matching right brace.
+  ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+
+  // If we're in a function-try-block, we need to store all the catch blocks.
+  if (kind == tok::kw_try) {
+    while (Tok.is(tok::kw_catch)) {
+      ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
+      ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+    }
+  }
+}

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Fri Apr 22 17:18:13 2011
@@ -19,6 +19,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "RAIIObjectsForParser.h"
 #include "ParsePragma.h"
+#include "clang/AST/DeclTemplate.h"
 using namespace clang;
 
 Parser::Parser(Preprocessor &pp, Sema &actions)
@@ -362,6 +363,11 @@
   for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
     delete ScopeCache[i];
 
+  // Free LateParsedTemplatedFunction nodes.
+  for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin();
+      it != LateParsedTemplateMap.end(); ++it)
+    delete it->second;
+
   // Remove the pragma handlers we installed.
   PP.RemovePragmaHandler(AlignHandler.get());
   AlignHandler.reset();
@@ -438,6 +444,10 @@
 
   Result = DeclGroupPtrTy();
   if (Tok.is(tok::eof)) {
+    // Late template parsing can begin.
+    if (getLang().DelayedTemplateParsing)
+      Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
+
     Actions.ActOnEndOfTranslationUnit();
     return true;
   }
@@ -786,6 +796,43 @@
       return 0;
   }
 
+  // In delayed template parsing mode, for function template we consume the
+  // tokens and store them for late parsing at the end of the translation unit.
+  if (getLang().DelayedTemplateParsing &&
+      TemplateInfo.Kind == ParsedTemplateInfo::Template) {
+    MultiTemplateParamsArg TemplateParameterLists(Actions,
+                                         TemplateInfo.TemplateParams->data(),
+                                         TemplateInfo.TemplateParams->size());
+    
+    ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+    Scope *ParentScope = getCurScope()->getParent();
+
+    Decl *DP = Actions.HandleDeclarator(ParentScope, D,
+                                move(TemplateParameterLists),
+                                /*IsFunctionDefinition=*/true);
+    D.complete(DP);
+    D.getMutableDeclSpec().abort();
+
+    if (DP) {
+      LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP);
+
+      FunctionDecl *FnD = 0;
+      if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP))
+        FnD = FunTmpl->getTemplatedDecl();
+      else
+        FnD = cast<FunctionDecl>(DP);
+
+      LateParsedTemplateMap[FnD] = LPT;
+      Actions.MarkAsLateParsedTemplate(FnD);
+      LexTemplateFunctionForLateParsing(LPT->Toks);
+    } else {
+      CachedTokens Toks;
+      LexTemplateFunctionForLateParsing(Toks);
+    }
+    return DP;
+  }
+
+
   // Enter a scope for the function body.
   ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
 

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Apr 22 17:18:13 2011
@@ -142,6 +142,7 @@
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
     ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), 
     PackContext(0), VisContext(0),
+    LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit),

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Apr 22 17:18:13 2011
@@ -5748,8 +5748,13 @@
   // See if this is a redefinition.
   // But don't complain if we're in GNU89 mode and the previous definition
   // was an extern inline function.
+
+  // FIXME: This code doesn't complain about multiple definition for late
+  // parsed template function.
+  bool IsLateParsingRedefinition = LateTemplateParser &&
+                                   FD->isLateTemplateParsed();
   const FunctionDecl *Definition;
-  if (FD->hasBody(Definition) &&
+  if (FD->hasBody(Definition) && !IsLateParsingRedefinition &&
       !canRedefineFunction(Definition, getLangOptions())) {
     if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
         Definition->getStorageClass() == SC_Extern)

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Apr 22 17:18:13 2011
@@ -3166,6 +3166,25 @@
   }
 }
 
+void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) {
+  if (!D)
+    return;
+
+  int NumParamList = D->getNumTemplateParameterLists();
+  for (int i = 0; i < NumParamList; i++) {
+    TemplateParameterList* Params = D->getTemplateParameterList(i);
+    for (TemplateParameterList::iterator Param = Params->begin(),
+                                      ParamEnd = Params->end();
+          Param != ParamEnd; ++Param) {
+      NamedDecl *Named = cast<NamedDecl>(*Param);
+      if (Named->getDeclName()) {
+        S->AddDecl(Named);
+        IdResolver.AddDecl(Named);
+      }
+    }
+  }
+}
+
 void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
   if (!D)
     return;

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Apr 22 17:18:13 2011
@@ -6381,3 +6381,24 @@
   Out << ']';
   return Out.str();
 }
+
+void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag) {
+  if (!FD)
+    return;
+  FD->setLateTemplateParsed(Flag);
+} 
+
+bool Sema::IsInsideALocalClassWithinATemplateFunction() {
+  DeclContext *DC = CurContext;
+
+  while (DC) {
+    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
+      const FunctionDecl *FD = RD->isLocalClass();
+      return (FD && FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate);
+    } else if (DC->isTranslationUnit() || DC->isNamespace())
+      return false;
+
+    DC = DC->getParent();
+  }
+  return false;
+}

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Apr 22 17:18:13 2011
@@ -2262,6 +2262,21 @@
   if (PatternDecl)
     Pattern = PatternDecl->getBody(PatternDecl);
 
+  // Postpone late parsed template instantiations.
+  if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) {
+    PendingInstantiations.push_back(
+      std::make_pair(Function, PointOfInstantiation));
+    return;
+  }
+
+  // Call the LateTemplateParser callback if there a need to late parse
+  // a templated function definition. 
+  if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() &&
+      LateTemplateParser) {
+    LateTemplateParser(OpaqueParser, (FunctionDecl*)PatternDecl);
+    Pattern = PatternDecl->getBody(PatternDecl);
+  }
+
   if (!Pattern) {
     if (DefinitionRequired) {
       if (Function->getPrimaryTemplate())

Added: cfe/trunk/test/Parser/DelayedTemplateParsing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/DelayedTemplateParsing.cpp?rev=130022&view=auto
==============================================================================
--- cfe/trunk/test/Parser/DelayedTemplateParsing.cpp (added)
+++ cfe/trunk/test/Parser/DelayedTemplateParsing.cpp Fri Apr 22 17:18:13 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fdelayed-template-parsing -fsyntax-only -verify %s
+
+template <class T>
+class A {
+
+   void foo() {
+       undeclared();
+   }
+   
+   void foo2();
+};
+
+template <class T>
+void A<T>::foo2() {
+    undeclared();
+}
+
+
+template <class T>
+void foo3() {
+   undeclared();
+}
+
+template void A<int>::foo2();
+
+
+void undeclared()
+{
+
+}
+

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=130022&r1=130021&r2=130022&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Fri Apr 22 17:18:13 2011
@@ -788,7 +788,7 @@
     // FIXME: Attributes?
   }
   
-  if (ND->isThisDeclarationADefinition()) {
+  if (ND->isThisDeclarationADefinition() && !ND->isLateTemplateParsed()) {
     if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
       // Find the initializers that were written in the source.
       llvm::SmallVector<CXXCtorInitializer *, 4> WrittenInits;





More information about the cfe-commits mailing list