[MS] Push outermost class DeclContexts only in -fdelayed-template-parsing

This is more or less a complete rewrite of r347627, and it fixes PR38460
I added a reduced test case to DelayedTemplateParsing.cpp.

llvm-svn: 347713
This commit is contained in:
Reid Kleckner 2018-11-27 21:20:42 +00:00
parent 6052d09c05
commit 229eee49fc
2 changed files with 53 additions and 12 deletions

View File

@ -1381,26 +1381,37 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
SmallVector<ParseScope*, 4> TemplateParamScopeStack; SmallVector<ParseScope*, 4> TemplateParamScopeStack;
// Get the list of DeclContexts to reenter. // Get the list of DeclContexts to reenter. For inline methods, we only want
SmallVector<DeclContext*, 4> DeclContextsToReenter; // to push the DeclContext of the outermost class. This matches the way the
// parser normally parses bodies of inline methods when the outermost class is
// complete.
struct ContainingDC {
ContainingDC(DeclContext *DC, bool ShouldPush) : Pair(DC, ShouldPush) {}
llvm::PointerIntPair<DeclContext *, 1, bool> Pair;
DeclContext *getDC() { return Pair.getPointer(); }
bool shouldPushDC() { return Pair.getInt(); }
};
SmallVector<ContainingDC, 4> DeclContextsToReenter;
DeclContext *DD = FunD; DeclContext *DD = FunD;
DeclContext *NextContaining = Actions.getContainingDC(DD);
while (DD && !DD->isTranslationUnit()) { while (DD && !DD->isTranslationUnit()) {
DeclContextsToReenter.push_back(DD); bool ShouldPush = DD == NextContaining;
DeclContextsToReenter.push_back({DD, ShouldPush});
if (ShouldPush)
NextContaining = Actions.getContainingDC(DD);
DD = DD->getLexicalParent(); DD = DD->getLexicalParent();
} }
// Reenter template scopes from outermost to innermost. // Reenter template scopes from outermost to innermost.
SmallVectorImpl<DeclContext *>::reverse_iterator II = for (ContainingDC CDC : reverse(DeclContextsToReenter)) {
DeclContextsToReenter.rbegin(); TemplateParamScopeStack.push_back(
for (; II != DeclContextsToReenter.rend(); ++II) { new ParseScope(this, Scope::TemplateParamScope));
TemplateParamScopeStack.push_back(new ParseScope(this, unsigned NumParamLists = Actions.ActOnReenterTemplateScope(
Scope::TemplateParamScope)); getCurScope(), cast<Decl>(CDC.getDC()));
unsigned NumParamLists =
Actions.ActOnReenterTemplateScope(getCurScope(), cast<Decl>(*II));
CurTemplateDepthTracker.addDepth(NumParamLists); CurTemplateDepthTracker.addDepth(NumParamLists);
if (*II != FunD) { if (CDC.shouldPushDC()) {
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
Actions.PushDeclContext(Actions.getCurScope(), *II); Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC());
} }
} }

View File

@ -181,3 +181,33 @@ static void h() {
} }
} }
struct PR38460 {
template <typename>
struct T {
static void foo() {
struct U {
void dummy() {
use_delayed_identifier();
}
};
}
};
};
void use_delayed_identifier();
void trigger_PR38460() {
PR38460::T<int>::foo();
}
template <typename> struct PR38460_2 {
struct p {
struct G {
bool operator()(int) {}
};
};
static void as() {
typename p::G g;
g(0);
}
};
template struct PR38460_2<int>;