[cfe-commits] r52694 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/Parser.h include/clang/Parse/Scope.h lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h test/Parser/cxx-class.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Tue Jun 24 15:12:16 PDT 2008


Author: akirtzidis
Date: Tue Jun 24 17:12:16 2008
New Revision: 52694

URL: http://llvm.org/viewvc/llvm-project?rev=52694&view=rev
Log:
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.

Added:
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/test/Parser/cxx-class.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Parse/Scope.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.h

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Jun 24 17:12:16 2008
@@ -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
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Jun 24 17:12:16 2008
@@ -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

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Jun 24 17:12:16 2008
@@ -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]

Modified: cfe/trunk/include/clang/Parse/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Scope.h?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Tue Jun 24 17:12:16 2008
@@ -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.
   ///

Added: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=52694&view=auto

==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (added)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Jun 24 17:12:16 2008
@@ -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;
+  }
+}

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Jun 24 17:12:16 2008
@@ -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);
+}

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Jun 24 17:12:16 2008
@@ -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);

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Jun 24 17:12:16 2008
@@ -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);
+}

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Jun 24 17:12:16 2008
@@ -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.

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=52694&r1=52693&r2=52694&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jun 24 17:12:16 2008
@@ -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);

Added: cfe/trunk/test/Parser/cxx-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-class.cpp?rev=52694&view=auto

==============================================================================
--- cfe/trunk/test/Parser/cxx-class.cpp (added)
+++ cfe/trunk/test/Parser/cxx-class.cpp Tue Jun 24 17:12:16 2008
@@ -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();
+};





More information about the cfe-commits mailing list