return;
}
+ /// \brief Called when we re-enter a template parameter scope.
+ ///
+ /// This action occurs when we are going to parse an member
+ /// function's default arguments or inline definition after the
+ /// outermost class definition has been completed, and when one or
+ /// more of the class definitions enclosing the member function is a
+ /// template. The "entity" in the given scope will be set as it was
+ /// when we entered the scope of the template initially, and should
+ /// be used to, e.g., reintroduce the names of template parameters
+ /// into the current scope so that they can be found by name lookup.
+ ///
+ /// \param S The (new) template parameter scope.
+ ///
+ /// \param Template the class template declaration whose template
+ /// parameters should be reintroduced into the current scope.
+ virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template) {
+ }
+
/// 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
/// nested classes are lexed and stored here.
typedef std::list<LexedMethod> LexedMethodsForTopClass;
+ /// \brief Representation of a class that has been parsed, including
+ /// any member function declarations or definitions that need to be
+ /// parsed after the corresponding top-level class is complete.
+ struct ParsingClass {
+ ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : TopLevelClass(TopLevelClass), TemplateScope(false),
+ TagOrTemplate(TagOrTemplate) { }
+
+ /// \brief Whether this is a "top-level" class, meaning that it is
+ /// not nested within another class.
+ bool TopLevelClass : 1;
+
+ /// \brief Whether this class had an associated template
+ /// scope. When true, TagOrTemplate is a template declaration;
+ /// othewise, it is a tag declaration.
+ bool TemplateScope : 1;
+
+ /// \brief The class or class template whose definition we are parsing.
+ DeclPtrTy TagOrTemplate;
- /// TopClass - Contains information about parts of the top
- /// (non-nested) C++ class that will need to be parsed after the
- /// class is fully defined.
- struct TopClass {
/// MethodDecls - Method declarations that contain pieces whose
/// parsing will be delayed until the class is fully defined.
LateParsedMethodDecls MethodDecls;
/// MethodDefs - Methods whose definitions will be parsed once the
/// class has been fully defined.
LexedMethodsForTopClass MethodDefs;
+
+ /// \brief Nested classes inside this class.
+ llvm::SmallVector<ParsingClass*, 4> NestedClasses;
};
- /// TopClassStacks - This is initialized with one TopClass used
- /// for lexing all top classes, until a local class in an inline method is
- /// encountered, at which point a new TopClass is pushed here
- /// and used until the parsing of that local class is finished.
- std::stack<TopClass> TopClassStacks;
+ /// \brief The stack of classes that is currently being
+ /// parsed. Nested and local classes will be pushed onto this stack
+ /// when they are parsed, and removed afterward.
+ std::stack<ParsingClass *> ClassStack;
- TopClass &getCurTopClassStack() {
- assert(!TopClassStacks.empty() && "No lexed method stacks!");
- return TopClassStacks.top();
+ ParsingClass &getCurrentClass() {
+ assert(!ClassStack.empty() && "No lexed method stacks!");
+ return *ClassStack.top();
}
- void PushTopClassStack() {
- TopClassStacks.push(TopClass());
- }
- void PopTopClassStack() { TopClassStacks.pop(); }
+ /// \brief RAII object used to
+ class ParsingClassDefinition {
+ Parser &P;
+ bool Popped;
+
+ public:
+ ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : P(P), Popped(false) {
+ P.PushParsingClass(TagOrTemplate, TopLevelClass);
+ }
+
+ /// \brief Pop this class of the stack.
+ void Pop() {
+ assert(!Popped && "Nested class has already been popped");
+ Popped = true;
+ P.PopParsingClass();
+ }
+
+ ~ParsingClassDefinition() {
+ if (!Popped)
+ P.PopParsingClass();
+ }
+ };
+
+ void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass);
+ void DeallocateParsedClasses(ParsingClass *Class);
+ void PopParsingClass();
DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D);
- void ParseLexedMethodDeclarations();
- void ParseLexedMethodDefs();
+ void ParseLexedMethodDeclarations(ParsingClass &Class);
+ void ParseLexedMethodDefs(ParsingClass &Class);
bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
CachedTokens &Toks,
tok::TokenKind EarlyAbortIf = tok::unknown,
// 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.
// 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;
}
}
/// 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);
// 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
// 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
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).
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 {
//
// 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);
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();
+}
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
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);
}
}
+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
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(
typedef int INT;
template struct N::Outer::Inner::InnerTemplate<INT>::VeryInner;
template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{'UeberInner' does not name a tag member}}
+
+namespace N2 {
+ struct Outer2 {
+ template<typename T>
+ struct Inner {
+ void foo() {
+ enum { K1Val = sizeof(T) } k1;
+ enum K2 { K2Val = sizeof(T)*2 };
+
+ K2 k2 = K2Val;
+
+ Inner i1;
+ i1.foo();
+ Inner<T> i2;
+ i2.foo();
+ }
+ };
+ };
+}
+
+// FIXME: template struct N2::Outer2::Inner<float>;