diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-06-24 22:12:16 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-06-24 22:12:16 +0000 |
commit | 4cc18a4d5222e04bd568b1e3e4d86127dbbcdf3f (patch) | |
tree | 64ba80f8bf12837a3a31ea24a4e5fc0acce67ccb | |
parent | 8fdf32822be2238aa7db62d40e75b168b637ab7d (diff) |
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
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 44 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 43 | ||||
-rw-r--r-- | include/clang/Parse/Scope.h | 20 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 159 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 267 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | test/Parser/cxx-class.cpp | 19 |
11 files changed, 578 insertions, 3 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 8742379d7c..4b68c31516 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -516,6 +516,12 @@ DIAG(warn_property_attribute, WARNING, 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 86339977ff..533c6b4846 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -138,7 +138,14 @@ public: /// 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 @@ public: 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 @@ public: 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 3d3e200795..640a2044a8 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 @@ private: 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 @@ private: ExprResult ParseCXXCasts(); //===--------------------------------------------------------------------===// + // C++ 9.3.2: C++ 'this' pointer + ExprResult ParseCXXThis(); + + //===--------------------------------------------------------------------===// // C++ 15: C++ Throw Expression ExprResult ParseThrowExpression(); @@ -486,6 +526,9 @@ private: //===--------------------------------------------------------------------===// // 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 5db9b2dd76..077809132c 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -42,7 +42,10 @@ public: /// 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 @@ public: 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 0000000000..b593f89668 --- /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 0a20911c7d..718cea9586 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -229,7 +229,12 @@ void Parser::ParseClassSpecifier(DeclSpec &DS) { // 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 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const 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 4bccc38266..b1499c9fd6 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -601,6 +601,8 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { 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 a71eb4807b..93eaa2dedd 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -103,3 +103,19 @@ Parser::ExprResult Parser::ParseThrowExpression() { 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 51223a7ccf..8ff7e9f186 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -23,6 +23,8 @@ Parser::Parser(Preprocessor &pp, Action &actions) 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 1d68160813..89d0d4011f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -221,6 +221,9 @@ private: 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 0000000000..f0b419d494 --- /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(); +}; |