зеркало из https://github.com/microsoft/clang.git
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
This commit is contained in:
Родитель
64089cece3
Коммит
8387e2a41e
|
@ -1294,6 +1294,7 @@ private:
|
|||
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 @@ protected:
|
|||
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 @@ public:
|
|||
/// 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 @@ public:
|
|||
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
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
// 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 @@ public:
|
|||
NoBitFieldTypeAlign = 0;
|
||||
FakeAddressSpaceMap = 0;
|
||||
MRTD = 0;
|
||||
DelayedTemplateParsing = 0;
|
||||
ParseUnknownAnytype = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -532,6 +532,9 @@ def traditional_cpp : Flag<"-traditional-cpp">,
|
|||
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">;
|
||||
|
||||
|
|
|
@ -314,6 +314,7 @@ def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
|
|||
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_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Gr
|
|||
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>;
|
||||
|
|
|
@ -919,6 +919,27 @@ private:
|
|||
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);
|
||||
|
|
|
@ -307,6 +307,16 @@ public:
|
|||
/// 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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -1413,7 +1413,7 @@ bool FunctionDecl::isVariadic() const {
|
|||
|
||||
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 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
|
|||
if (I->Body) {
|
||||
Definition = *I;
|
||||
return I->Body.get(getASTContext().getExternalSource());
|
||||
} else if (I->IsLateTemplateParsed) {
|
||||
Definition = *I;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2031,7 +2031,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
|
|||
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 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
|
|||
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;
|
||||
|
||||
|
|
|
@ -1605,6 +1605,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
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,
|
||||
|
|
|
@ -692,6 +692,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
|
|||
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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -142,6 +142,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
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),
|
||||
|
|
|
@ -5748,8 +5748,13 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
|||
// 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)
|
||||
|
|
|
@ -3166,6 +3166,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -6381,3 +6381,24 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -2262,6 +2262,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
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())
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -788,7 +788,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
|
|||
// 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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче