aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
authorFrancois Pichet <pichet2000@gmail.com>2011-04-22 22:18:13 +0000
committerFrancois Pichet <pichet2000@gmail.com>2011-04-22 22:18:13 +0000
commit8387e2a41eef6fa17fb140a18c29b6eee9dd2b8a (patch)
tree56e18603554b83fdb5ca1ccd11b550e4d972c81d /lib/Parse
parent64089cece350472c04b420c497ae391443353325 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130022 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp31
-rw-r--r--lib/Parse/ParseTemplate.cpp124
-rw-r--r--lib/Parse/Parser.cpp47
3 files changed, 202 insertions, 0 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 93568efebc..778aa11087 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -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 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
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);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 84b37889f4..f21e09152b 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -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 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
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);
+ }
+ }
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 492b8f5309..6522306dce 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -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 @@ Parser::~Parser() {
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 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
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 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
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);