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:
Francois Pichet 2011-04-22 22:18:13 +00:00
Родитель 64089cece3
Коммит 8387e2a41e
20 изменённых файлов: 369 добавлений и 7 удалений

Просмотреть файл

@ -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;