diff options
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r-- | clang/lib/Parse/ParseCXXInlineMethods.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 124 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 47 |
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); |