Add parsing support for C++ classes.
Note that Parser::ParseCXXMemberSpecification is temporarily disabled until the Sema support is in place.
Once ParseCXXMemberSpecification is enabled, the Parser/cxx-class.cpp test will pass.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52694 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 8742379..4b68c31 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -516,6 +516,12 @@
DIAG(warn_property_type, WARNING,
"property type '%0' does not match property type inherited from '%1'")
+/// C++ parser diagnostics
+DIAG(err_no_declarators, ERROR,
+ "declaration does not declare anything")
+DIAG(err_func_def_no_params, ERROR,
+ "function definition does not declare parameters")
+
//===----------------------------------------------------------------------===//
// Semantic Analysis
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 8633997..533c6b4 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -138,7 +138,14 @@
/// information about formal arguments that are part of this function.
virtual DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
// Default to ActOnDeclarator.
- return ActOnDeclarator(FnBodyScope, D, 0);
+ return ActOnStartOfFunctionDef(FnBodyScope,
+ ActOnDeclarator(FnBodyScope, D, 0));
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
+ return D;
}
virtual void ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) {
@@ -555,6 +562,11 @@
return 0;
}
+ /// ActOnCXXThis - Parse the C++ 'this' pointer.
+ virtual ExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ return 0;
+ }
+
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
tok::TokenKind Kind) {
@@ -574,6 +586,36 @@
DeclTy *basetype, SourceLocation BaseLoc) {
}
+ /// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
+ /// definition, when on C++.
+ virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
+ SourceLocation LBrace) {
+ }
+
+ /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
+ /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth'
+ /// specifies the bitfield width if there is one and 'Init' specifies the
+ /// initializer if any. 'LastInGroup' is non-null for cases where one declspec
+ /// has multiple declarators on it.
+ virtual DeclTy *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+ Declarator &D, ExprTy *BitfieldWidth,
+ ExprTy *Init, DeclTy *LastInGroup) {
+ return 0;
+ }
+
+ /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators
+ /// are parsed but *before* parsing of inline method definitions.
+ virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclTy *TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac) {
+ }
+
+ /// ActOnFinishCXXClassDef - This is called when a class/struct/union has
+ /// completed parsing, when on C++.
+ virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl,SourceLocation RBrace) {
+ }
+
//===----------------------- Obj-C Declarations -------------------------===//
// ActOnStartClassInterface - this action is called immediately after parsing
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 3d3e200..640a204 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Action.h"
+#include <stack>
namespace clang {
class DeclSpec;
@@ -268,6 +269,41 @@
typedef Action::StmtResult StmtResult;
//===--------------------------------------------------------------------===//
+ // Lexing and parsing of C++ inline methods.
+
+ typedef llvm::SmallVector<Token, 32> TokensTy;
+ struct LexedMethod {
+ Action::DeclTy *D;
+ TokensTy Toks;
+ explicit LexedMethod(Action::DeclTy *MD) : D(MD) {}
+ };
+
+ /// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class,
+ /// its inline method definitions and the inline method definitions of its
+ /// nested classes are lexed and stored here.
+ typedef std::stack<LexedMethod> LexedMethodsForTopClass;
+
+ /// TopClassStacks - This is initialized with one LexedMethodsForTopClass used
+ /// for lexing all top classes, until a local class in an inline method is
+ /// encountered, at which point a new LexedMethodsForTopClass is pushed here
+ /// and used until the parsing of that local class is finished.
+ std::stack<LexedMethodsForTopClass> TopClassStacks;
+
+ LexedMethodsForTopClass &getCurTopClassStack() {
+ assert(!TopClassStacks.empty() && "No lexed method stacks!");
+ return TopClassStacks.top();
+ }
+
+ void PushTopClassStack() {
+ TopClassStacks.push(LexedMethodsForTopClass());
+ }
+ void PopTopClassStack() { TopClassStacks.pop(); }
+
+ DeclTy *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D);
+ void ParseLexedMethodDefs();
+ bool ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks);
+
+ //===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
DeclTy *ParseExternalDeclaration();
DeclTy *ParseDeclarationOrFunctionDefinition();
@@ -369,6 +405,10 @@
ExprResult ParseCXXCasts();
//===--------------------------------------------------------------------===//
+ // C++ 9.3.2: C++ 'this' pointer
+ ExprResult ParseCXXThis();
+
+ //===--------------------------------------------------------------------===//
// C++ 15: C++ Throw Expression
ExprResult ParseThrowExpression();
@@ -486,6 +526,9 @@
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
void ParseClassSpecifier(DeclSpec &DS);
+ void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
+ DeclTy *TagDecl);
+ DeclTy *ParseCXXClassMemberDeclaration(AccessSpecifier AS);
//===--------------------------------------------------------------------===//
// C++ 10: Derived classes [class.derived]
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index 5db9b2d..0778091 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -42,7 +42,10 @@
/// DeclScope - This is a scope that can contain a declaration. Some scopes
/// just contain loop constructs but don't contain decls.
- DeclScope = 0x08
+ DeclScope = 0x08,
+
+ /// CXXClassScope - The scope of a C++ struct/union/class definition.
+ CXXClassScope = 0x10
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -119,6 +122,21 @@
bool isDeclScope(Action::DeclTy *D) {
return DeclsInScope.count(D) != 0;
}
+
+ /// isCXXClassScope - Return true if this scope is a C++ class scope.
+ bool isCXXClassScope() const {
+ return (getFlags() & Scope::CXXClassScope);
+ }
+
+ /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline
+ /// method scope or is inside one.
+ bool isInCXXInlineMethodScope() const {
+ if (const Scope *FnS = getFnParent()) {
+ assert(FnS->getParent() && "TUScope not created?");
+ return FnS->getParent()->isCXXClassScope();
+ }
+ return false;
+ }
/// Init - This is used by the parser to implement scope caching.
///
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
new file mode 100644
index 0000000..b593f89
--- /dev/null
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -0,0 +1,159 @@
+//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing for C++ class inline methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// ParseInlineCXXMethodDef - We parsed and verified that the specified
+/// Declarator is a well formed C++ inline method definition. Now lex its body
+/// and store its tokens for parsing after the C++ class is complete.
+Parser::DeclTy *
+Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+
+ DeclTy *FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0, 0);
+
+ // We should have an opening brace now.
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_fn_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.isNot(tok::l_brace))
+ return FnD;
+ }
+
+ // Consume the tokens and store them for later parsing.
+
+ getCurTopClassStack().push(LexedMethod(FnD));
+ TokensTy &Toks = getCurTopClassStack().top().Toks;
+
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ ConsumeAndStoreUntil(tok::r_brace, Toks);
+
+ return FnD;
+}
+
+/// 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() {
+ while (!getCurTopClassStack().empty()) {
+ LexedMethod &LM = getCurTopClassStack().top();
+
+ assert(!LM.Toks.empty() && "Empty body!");
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LM.Toks.push_back(Tok);
+ PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+ assert(Tok.is(tok::l_brace) && "Inline method not starting with '{'");
+
+ // Parse the method body. Function body parsing code is similar enough
+ // to be re-used for method bodies as well.
+ EnterScope(Scope::FnScope|Scope::DeclScope);
+ Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
+
+ ParseFunctionStatementBody(LM.D, Tok.getLocation(), Tok.getLocation());
+
+ getCurTopClassStack().pop();
+ }
+}
+
+/// ConsumeAndStoreUntil - Consume and store the token at the passed token
+/// container until the token 'T' is reached (which gets consumed/stored too).
+/// Returns true if token 'T' was found.
+/// NOTE: This is a specialized version of Parser::SkipUntil.
+bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks) {
+ // We always want this function to consume at least one token if the first
+ // token isn't T and if not at EOF.
+ bool isFirstTokenConsumed = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ if (Tok.is(T)) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ return true;
+ }
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively consume properly-nested parens.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ ConsumeAndStoreUntil(tok::r_paren, Toks);
+ break;
+ case tok::l_square:
+ // Recursively consume properly-nested square brackets.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ ConsumeAndStoreUntil(tok::r_square, Toks);
+ break;
+ case tok::l_brace:
+ // Recursively consume properly-nested braces.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ ConsumeAndStoreUntil(tok::r_brace, Toks);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ Toks.push_back(Tok);
+ ConsumeStringToken();
+ break;
+ default:
+ // consume this token.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenConsumed = false;
+ }
+}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 0a20911..718cea9 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -229,7 +229,12 @@
// If there is a body, parse it and inform the actions module.
if (Tok.is(tok::l_brace))
- ParseStructUnionBody(StartLoc, TagType, TagDecl);
+ // FIXME: Temporarily disable parsing for C++ classes until the Sema support
+ // is in place.
+ //if (getLang().CPlusPlus)
+ // ParseCXXMemberSpecification(StartLoc, TagType, TagDecl);
+ //else
+ ParseStructUnionBody(StartLoc, TagType, TagDecl);
else if (TK == Action::TK_Definition) {
// FIXME: Complain that we have a base-specifier list but no
// definition.
@@ -357,3 +362,263 @@
case tok::kw_public: return AS_public;
}
}
+
+/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
+///
+/// member-declaration:
+/// decl-specifier-seq[opt] member-declarator-list[opt] ';'
+/// function-definition ';'[opt]
+/// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO]
+/// using-declaration [TODO]
+/// [C++0x] static_assert-declaration [TODO]
+/// template-declaration [TODO]
+///
+/// member-declarator-list:
+/// member-declarator
+/// member-declarator-list ',' member-declarator
+///
+/// member-declarator:
+/// declarator pure-specifier[opt]
+/// declarator constant-initializer[opt]
+/// identifier[opt] ':' constant-expression
+///
+/// pure-specifier: [TODO]
+/// '= 0'
+///
+/// constant-initializer:
+/// '=' constant-expression
+///
+Parser::DeclTy *Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
+ SourceLocation DSStart = Tok.getLocation();
+ // decl-specifier-seq:
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ // C++ 9.2p7: The member-declarator-list can be omitted only after a
+ // class-specifier or an enum-specifier or in a friend declaration.
+ // FIXME: Friend declarations.
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_union:
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_enum:
+ return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ default:
+ Diag(DSStart, diag::err_no_declarators);
+ return 0;
+ }
+ }
+
+ // Parse the first declarator.
+ Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (DeclaratorInfo.getIdentifier() == 0) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return 0;
+ }
+
+ // function-definition:
+ if (Tok.is(tok::l_brace)) {
+ if (!DeclaratorInfo.isFunctionDeclarator()) {
+ Diag(Tok, diag::err_func_def_no_params);
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return 0;
+ }
+
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+ // This recovery skips the entire function body. It would be nice
+ // to simply call ParseCXXInlineMethodDef() below, however Sema
+ // assumes the declarator represents a function, not a typedef.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return 0;
+ }
+
+ return ParseCXXInlineMethodDef(AS, DeclaratorInfo);
+ }
+
+ // member-declarator-list:
+ // member-declarator
+ // member-declarator-list ',' member-declarator
+
+ DeclTy *LastDeclInGroup = 0;
+ ExprTy *BitfieldSize = 0;
+ ExprTy *Init = 0;
+
+ while (1) {
+
+ // member-declarator:
+ // declarator pure-specifier[opt]
+ // declarator constant-initializer[opt]
+ // identifier[opt] ':' constant-expression
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ ExprResult Res = ParseConstantExpression();
+ if (Res.isInvalid)
+ SkipUntil(tok::comma, true, true);
+ else
+ BitfieldSize = Res.Val;
+ }
+
+ // pure-specifier:
+ // '= 0'
+ //
+ // constant-initializer:
+ // '=' constant-expression
+
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ ExprResult Res = ParseInitializer();
+ if (Res.isInvalid)
+ SkipUntil(tok::comma, true, true);
+ else
+ Init = Res.Val;
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.is(tok::kw___attribute))
+ DeclaratorInfo.AddAttributes(ParseAttributes());
+
+ LastDeclInGroup = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
+ DeclaratorInfo,
+ BitfieldSize, Init,
+ LastDeclInGroup);
+
+ // If we don't have a comma, it is either the end of the list (a ';')
+ // or an error, bail out.
+ if (Tok.isNot(tok::comma))
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ DeclaratorInfo.clear();
+ BitfieldSize = Init = 0;
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.is(tok::kw___attribute))
+ DeclaratorInfo.AddAttributes(ParseAttributes());
+
+ ParseDeclarator(DeclaratorInfo);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ // Reverse the chain list.
+ return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
+ }
+
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return 0;
+}
+
+/// ParseCXXMemberSpecification - Parse the class definition.
+///
+/// member-specification:
+/// member-declaration member-specification[opt]
+/// access-specifier ':' member-specification[opt]
+///
+void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+ unsigned TagType, DeclTy *TagDecl) {
+ assert(TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_union ||
+ TagType == DeclSpec::TST_class && "Invalid TagType!");
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ if (!CurScope->isCXXClassScope() && // 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();
+ }
+
+ // Enter a scope for the class.
+ EnterScope(Scope::CXXClassScope|Scope::DeclScope);
+
+ Actions.ActOnStartCXXClassDef(CurScope, TagDecl, LBraceLoc);
+
+ // C++ 11p3: Members of a class defined with the keyword class are private
+ // by default. Members of a class defined with the keywords struct or union
+ // are public by default.
+ AccessSpecifier CurAS;
+ if (TagType == DeclSpec::TST_class)
+ CurAS = AS_private;
+ else
+ CurAS = AS_public;
+
+ // While we still have something to read, read the member-declarations.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // Each iteration of this loop reads one member-declaration.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ AccessSpecifier AS = getAccessSpecifierIfPresent();
+ if (AS != AS_none) {
+ // Current token is a C++ access specifier.
+ CurAS = AS;
+ ConsumeToken();
+ ExpectAndConsume(tok::colon, diag::err_expected_colon);
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ ParseCXXClassMemberDeclaration(CurAS);
+ }
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after class contents, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes(); // FIXME: where should I put them?
+
+ Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
+ LBraceLoc, RBraceLoc);
+
+ // C++ 9.2p2: Within the class member-specification, the class is regarded as
+ // complete within function bodies, default arguments,
+ // exception-specifications, and constructor ctor-initializers (including
+ // such things in nested classes).
+ //
+ // FIXME: Only function bodies are parsed correctly, fix the rest.
+ if (!CurScope->getParent()->isCXXClassScope()) {
+ // We are not inside a nested class. This class and its nested classes
+ // are complete and we can parse the lexed inline method definitions.
+ 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();
+ }
+
+ // Leave the class scope.
+ ExitScope();
+
+ Actions.ActOnFinishCXXClassDef(TagDecl, RBraceLoc);
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 4bccc38..b1499c9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -601,6 +601,8 @@
case tok::kw_reinterpret_cast:
case tok::kw_static_cast:
return ParseCXXCasts();
+ case tok::kw_this:
+ return ParseCXXThis();
case tok::at: {
SourceLocation AtLoc = ConsumeToken();
return ParseObjCAtExpression(AtLoc);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index a71eb48..93eaa2d 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -103,3 +103,19 @@
return Actions.ActOnCXXThrow(ThrowLoc, Expr.Val);
}
}
+
+/// ParseCXXThis - This handles the C++ 'this' pointer.
+///
+/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
+/// a non-lvalue expression whose value is the address of the object for which
+/// the function is called.
+Parser::ExprResult Parser::ParseCXXThis() {
+ assert(Tok.is(tok::kw_this) && "Not 'this'!");
+ SourceLocation ThisLoc = ConsumeToken();
+
+ ExprResult Res = Actions.ActOnCXXThis(ThisLoc);
+ if (Res.isInvalid)
+ return Res;
+
+ return ParsePostfixExpressionSuffix(Res);
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 51223a7..8ff7e9f 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -23,6 +23,8 @@
NumCachedScopes = 0;
ParenCount = BracketCount = BraceCount = 0;
ObjCImpDecl = 0;
+ // Instantiate a LexedMethodsForTopClass for all the non-nested classes.
+ PushTopClassStack();
}
/// Out-of-line virtual destructor to provide home for Action class.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1d68160..89d0d40 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -221,6 +221,9 @@
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
+ // Until 'real' implementation is in place, override both
+ // 'ActOnStartOfFunctionDef' to satisfy the compiler.
+ virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, DeclTy *D) { return D; }
virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D);
virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
new file mode 100644
index 0000000..f0b419d
--- /dev/null
+++ b/test/Parser/cxx-class.cpp
@@ -0,0 +1,19 @@
+// RUN: clang -parse-noop -verify %s
+class C {
+public:
+protected:
+ typedef int A,B;
+ static int sf(), u;
+
+ struct S {};
+ enum {};
+ int; // expected-error {{error: declaration does not declare anything}}
+
+public:
+ void m() {
+ int l = 2;
+ }
+
+private:
+ int x,f(),y,g();
+};