summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp31
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp124
-rw-r--r--clang/lib/Parse/Parser.cpp47
3 files changed, 202 insertions, 0 deletions
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 93568efebc0..778aa110872 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/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/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 84b37889f4d..f21e09152b0 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/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/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 492b8f53097..6522306dce2 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/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);
OpenPOWER on IntegriCloud