aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-05-27 23:11:45 +0000
committerDouglas Gregor <dgregor@apple.com>2009-05-27 23:11:45 +0000
commit6569d68745c8213709740337d2be52b031384f58 (patch)
treeb21a07fae6dd3ea152e433bcf3720d65285aa56e /lib
parent26fa0edd63c0f34953ba22f519d0fa68ee572341 (diff)
Reimplement much of the way that we track nested classes in the
parser. Rather than placing all of the delayed member function declarations and inline definitions into a single bucket corresponding to the top-level class, we instead mirror the nesting structure of the nested classes and place the delayed member functions into their appropriate place. Then, when we actually parse the delayed member function declarations, set up the scope stack the same way as it was when we originally saw the declaration, so that we can find, e.g., template parameters that are in scope. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72502 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp47
-rw-r--r--lib/Parse/ParseDeclCXX.cpp91
-rw-r--r--lib/Parse/Parser.cpp3
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDeclCXX.cpp17
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp3
6 files changed, 124 insertions, 38 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 525b088714..af6fab7cb1 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -31,8 +31,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
// Consume the tokens and store them for later parsing.
- getCurTopClassStack().MethodDefs.push_back(LexedMethod(FnD));
- CachedTokens &Toks = getCurTopClassStack().MethodDefs.back().Toks;
+ getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
+ CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks;
tok::TokenKind kind = Tok.getKind();
// We may have a constructor initializer or function-try-block here.
@@ -46,7 +46,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
// don't try to parse this method later.
Diag(Tok.getLocation(), diag::err_expected_lbrace);
ConsumeAnyToken();
- getCurTopClassStack().MethodDefs.pop_back();
+ getCurrentClass().MethodDefs.pop_back();
return FnD;
}
}
@@ -74,11 +74,22 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
/// delayed (such as default arguments) and parse them.
-void Parser::ParseLexedMethodDeclarations() {
- for (; !getCurTopClassStack().MethodDecls.empty();
- getCurTopClassStack().MethodDecls.pop_front()) {
- LateParsedMethodDeclaration &LM = getCurTopClassStack().MethodDecls.front();
+void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
+ LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
+ // FIXME: For member function templates, we'll need to introduce a
+ // scope for the template parameters.
+
// Start the delayed C++ method declaration
Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
@@ -117,15 +128,26 @@ void Parser::ParseLexedMethodDeclarations() {
// Finish the delayed C++ method declaration.
Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);
}
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
}
/// ParseLexedMethodDefs - We finished parsing the member specification of a top
/// (non-nested) C++ class. Now go over the stack of lexed methods that were
/// collected during its parsing and parse them all.
-void Parser::ParseLexedMethodDefs() {
- for (; !getCurTopClassStack().MethodDefs.empty();
- getCurTopClassStack().MethodDefs.pop_front()) {
- LexedMethod &LM = getCurTopClassStack().MethodDefs.front();
+void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
+ LexedMethod &LM = Class.MethodDefs.front();
assert(!LM.Toks.empty() && "Empty body!");
// Append the current token at the end of the new token stream so that it
@@ -152,6 +174,9 @@ void Parser::ParseLexedMethodDefs() {
// FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
}
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDefs(*Class.NestedClasses[I]);
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index ee14213876..a7d3b52bd2 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -921,9 +921,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
if (!LateMethod) {
// Push this method onto the stack of late-parsed method
// declarations.
- getCurTopClassStack().MethodDecls.push_back(
+ getCurrentClass().MethodDecls.push_back(
LateParsedMethodDeclaration(ThisDecl));
- LateMethod = &getCurTopClassStack().MethodDecls.back();
+ LateMethod = &getCurrentClass().MethodDecls.back();
// Add all of the parameters prior to this one (they don't
// have default arguments).
@@ -1000,16 +1000,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation LBraceLoc = ConsumeBrace();
- if (!CurScope->isClassScope() && // Not about to define a nested class.
- CurScope->isInCXXInlineMethodScope()) {
- // We will define a local class of an inline method.
- // Push a new LexedMethodsForTopClass for its inline methods.
- PushTopClassStack();
- }
+ // Determine whether this is a top-level (non-nested) class.
+ bool TopLevelClass = ClassStack.empty() ||
+ CurScope->isInCXXInlineMethodScope();
// Enter a scope for the class.
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+ // Note that we are parsing a new (potentially-nested) class definition.
+ ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass);
+
if (TagDecl)
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
else {
@@ -1067,26 +1067,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
//
// FIXME: Only function bodies and constructor ctor-initializers are
// parsed correctly, fix the rest.
- if (!CurScope->getParent()->isClassScope() &&
- !(CurScope->getParent()->isTemplateParamScope() &&
- CurScope->getParent()->getParent()->isClassScope())) {
+ if (TopLevelClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
- ParseLexedMethodDeclarations();
- ParseLexedMethodDefs();
-
- // For a local class of inline method, pop the LexedMethodsForTopClass that
- // was previously pushed.
-
- assert((CurScope->isInCXXInlineMethodScope() ||
- TopClassStacks.size() == 1) &&
- "MethodLexers not getting popped properly!");
- if (CurScope->isInCXXInlineMethodScope())
- PopTopClassStack();
+ ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMethodDefs(getCurrentClass());
}
// Leave the class scope.
+ ParsingDef.Pop();
ClassScope.Exit();
Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
@@ -1236,3 +1226,60 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
return false;
}
+
+/// \brief We have just started parsing the definition of a new class,
+/// so push that class onto our stack of classes that is currently
+/// being parsed.
+void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) {
+ assert((TopLevelClass || !ClassStack.empty()) &&
+ "Nested class without outer class");
+ ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
+}
+
+/// \brief Deallocate the given parsed class and all of its nested
+/// classes.
+void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
+ for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I)
+ DeallocateParsedClasses(Class->NestedClasses[I]);
+ delete Class;
+}
+
+/// \brief Pop the top class of the stack of classes that are
+/// currently being parsed.
+///
+/// This routine should be called when we have finished parsing the
+/// definition of a class, but have not yet popped the Scope
+/// associated with the class's definition.
+///
+/// \returns true if the class we've popped is a top-level class,
+/// false otherwise.
+void Parser::PopParsingClass() {
+ assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
+
+ ParsingClass *Victim = ClassStack.top();
+ ClassStack.pop();
+ if (Victim->TopLevelClass) {
+ // Deallocate all of the nested classes of this class,
+ // recursively: we don't need to keep any of this information.
+ DeallocateParsedClasses(Victim);
+ return;
+ }
+ assert(!ClassStack.empty() && "Missing top-level class?");
+
+ if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() &&
+ Victim->NestedClasses.empty()) {
+ // The victim is a nested class, but we will not need to perform
+ // any processing after the definition of this class since it has
+ // no members whose handling was delayed. Therefore, we can just
+ // remove this nested class.
+ delete Victim;
+ return;
+ }
+
+ // This nested class has some members that will need to be processed
+ // after the top-level class is completely defined. Therefore, add
+ // it to the list of nested classes within its parent.
+ assert(CurScope->isClassScope() && "Nested class outside of class scope?");
+ ClassStack.top()->NestedClasses.push_back(Victim);
+ Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 12e584377d..1c2e8a62e1 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -39,9 +39,6 @@ Parser::Parser(Preprocessor &pp, Action &actions)
PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions,
*this));
PP.AddPragmaHandler(0, UnusedHandler.get());
-
- // Instantiate a LexedMethodsForTopClass for all the non-nested classes.
- PushTopClassStack();
}
/// If a crash happens while the parser is active, print out a line indicating
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3825b7cc06..0a285bd309 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1731,6 +1731,7 @@ public:
SourceLocation LBrac,
SourceLocation RBrac);
+ virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
DeclPtrTy Method);
virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6edb29044c..0bf97f560d 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1205,6 +1205,23 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
}
+void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
+ TemplateDecl *Template = TemplateD.getAs<TemplateDecl>();
+ if (!Template)
+ return;
+
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ NamedDecl *Named = cast<NamedDecl>(*Param);
+ if (Named->getDeclName()) {
+ S->AddDecl(DeclPtrTy::make(Named));
+ IdResolver.AddDecl(Named);
+ }
+ }
+}
+
/// ActOnStartDelayedCXXMethodDeclaration - We have completed
/// parsing a top-level (non-nested) C++ class, and we are now
/// parsing those parts of the given Method declaration that could
diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp
index 6d2e28aff8..a62607d116 100644
--- a/lib/Sema/SemaTemplateInstantiateStmt.cpp
+++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp
@@ -69,8 +69,7 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitDeclStmt(DeclStmt *S) {
return SemaRef.StmtError();
Decls.push_back(Instantiated);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(cast<VarDecl>(*D),
- cast<VarDecl>(Instantiated));
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(*D, Instantiated);
}
return SemaRef.Owned(new (SemaRef.Context) DeclStmt(