[cfe-commits] r52956 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/CXXFieldCollector.h lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/Sema/cxx-class.cpp test/Sema/cxx-this.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Tue Jul 1 03:37:31 PDT 2008


Author: akirtzidis
Date: Tue Jul  1 05:37:29 2008
New Revision: 52956

URL: http://llvm.org/viewvc/llvm-project?rev=52956&view=rev
Log:
Add Sema support for C++ classes.

Added:
    cfe/trunk/lib/Sema/CXXFieldCollector.h
    cfe/trunk/test/Sema/cxx-class.cpp
    cfe/trunk/test/Sema/cxx-this.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Jul  1 05:37:29 2008
@@ -223,6 +223,7 @@
     Func,
     Function,
     PrettyFunction,
+    CXXThis,
     ObjCSuper // super
   };
   

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Jul  1 05:37:29 2008
@@ -589,6 +589,18 @@
 DIAG(err_bad_language, ERROR,
      "unknown linkage language")
 
+// C++ class members
+DIAG(err_storageclass_invalid_for_member, ERROR,
+     "storage class specified for a member declaration")
+DIAG(err_not_bitfield_type, ERROR,
+     "cannot declare '%0' to be a bit-field type")
+DIAG(err_static_not_bitfield, ERROR,
+     "static member '%0' cannot be a bit-field")
+DIAG(err_not_integral_type_bitfield, ERROR,
+     "bit-field '%0' with non-integral type")
+DIAG(err_member_initialization, ERROR,
+    "'%0' can only be initialized if it is a static const integral data member")
+
 // Attributes
 DIAG(err_attribute_wrong_number_arguments, ERROR,
      "attribute requires %0 argument(s)")
@@ -898,6 +910,13 @@
 DIAG(err_typecheck_assign_const, ERROR,
      "read-only variable is not assignable")
 
+DIAG(err_invalid_this_use, ERROR,
+     "invalid use of 'this' outside of a nonstatic member function")
+DIAG(err_invalid_member_use_in_static_method, ERROR,
+     "invalid use of member '%0' in static member function")
+DIAG(err_invalid_non_static_member_use, ERROR,
+     "invalid use of nonstatic data member '%0'")
+
 // assignment related diagnostics (also for argument passing, returning, etc).
 DIAG(err_typecheck_convert_incompatible, ERROR,
      "incompatible type %2 '%1', expected '%0'")

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Jul  1 05:37:29 2008
@@ -420,7 +420,9 @@
   case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
     return LV_Valid;
   case PreDefinedExprClass:
-    return LV_Valid;
+    return (cast<PreDefinedExpr>(this)->getIdentType() == PreDefinedExpr::CXXThis
+            ? LV_InvalidExpression
+            : LV_Valid);
   case CXXDefaultArgExprClass:
     return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue();
   default:

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Jul  1 05:37:29 2008
@@ -229,11 +229,9 @@
 
   // If there is a body, parse it and inform the actions module.
   if (Tok.is(tok::l_brace))
-    // FIXME: Temporarily disable parsing for C++ classes until the Sema support
-    // is in place.
-    //if (getLang().CPlusPlus)
-    //  ParseCXXMemberSpecification(StartLoc, TagType, TagDecl);
-    //else
+    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
@@ -411,7 +409,7 @@
         return 0;
     }
   }
-  
+
   Declarator DeclaratorInfo(DS, Declarator::MemberContext);
 
   if (Tok.isNot(tok::colon)) {
@@ -492,6 +490,10 @@
     if (Tok.is(tok::kw___attribute))
       DeclaratorInfo.AddAttributes(ParseAttributes());
 
+    // NOTE: If Sema is the Action module and declarator is an instance field,
+    // this call will *not* return the created decl; LastDeclInGroup will be
+    // returned instead.
+    // See Sema::ActOnCXXMemberDeclarator for details.
     LastDeclInGroup = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
                                                        DeclaratorInfo,
                                                        BitfieldSize, Init,

Added: cfe/trunk/lib/Sema/CXXFieldCollector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CXXFieldCollector.h?rev=52956&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/CXXFieldCollector.h (added)
+++ cfe/trunk/lib/Sema/CXXFieldCollector.h Tue Jul  1 05:37:29 2008
@@ -0,0 +1,76 @@
+//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file provides CXXFieldCollector that is used during parsing & semantic
+//  analysis of C++ classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+  class CXXFieldDecl;
+
+/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of
+/// C++ classes.
+class CXXFieldCollector {
+  /// Fields - Contains all CXXFieldDecls collected during parsing of a C++
+  /// class. When a nested class is entered, its fields are appended to the
+  /// fields of its parent class, when it is exited its fields are removed.
+  llvm::SmallVector<CXXFieldDecl*, 32> Fields;
+
+  /// FieldCount - Each entry represents the number of fields collected during
+  /// the parsing of a C++ class. When a nested class is entered, a new field
+  /// count is pushed, when it is exited, the field count is popped.
+  llvm::SmallVector<size_t, 4> FieldCount;
+
+  // Example:
+  //
+  // class C {
+  //   int x,y;
+  //   class NC {
+  //     int q;
+  //     // At this point, Fields contains [x,y,q] decls and FieldCount contains
+  //     // [2,1].
+  //   };
+  //   int z;
+  //   // At this point, Fields contains [x,y,z] decls and FieldCount contains
+  //   // [3].
+  // };
+
+public:
+  /// StartClass - Called by Sema::ActOnStartCXXClassDef.
+  void StartClass() { FieldCount.push_back(0); }
+
+  /// Add - Called by Sema::ActOnCXXMemberDeclarator.
+  void Add(CXXFieldDecl *D) {
+    Fields.push_back(D);
+    ++FieldCount.back();
+  }
+
+  /// getNumField - The number of fields added to the currently parsed class.
+  size_t getCurNumFields() const { return FieldCount.back(); }
+
+  /// getFields - Pointer to array of fields added to the currently parsed
+  /// class.
+  CXXFieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); }
+
+  /// FinishClass - Called by Sema::ActOnFinishCXXClassDef.
+  void FinishClass() {
+    Fields.resize(Fields.size() - getCurNumFields());
+    FieldCount.pop_back();
+  }
+};
+
+} // end namespace clang
+
+#endif

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Jul  1 05:37:29 2008
@@ -116,6 +116,8 @@
   KnownFunctionIDs[id_vprintf]   = &IT.get("vprintf");
 
   TUScope = 0;
+  if (getLangOptions().CPlusPlus)
+    FieldCollector.reset(new CXXFieldCollector());
 }
 
 /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jul  1 05:37:29 2008
@@ -16,11 +16,13 @@
 #define LLVM_CLANG_AST_SEMA_H
 
 #include "IdentifierResolver.h"
+#include "CXXFieldCollector.h"
 #include "clang/Parse/Action.h"
 #include "clang/Parse/DeclSpec.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
 #include <vector>
 #include <string>
 
@@ -109,6 +111,9 @@
                          ObjCCompatibleAliasDecl*> ObjCAliasTy;
   ObjCAliasTy ObjCAliasDecls;
 
+  /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
+  llvm::OwningPtr<CXXFieldCollector> FieldCollector;
+
   IdentifierResolver IdResolver;
 
   // Enum values used by KnownFunctionIDs (see below).
@@ -215,9 +220,7 @@
   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 DeclTy *ActOnStartOfFunctionDef(Scope *S, DeclTy *D);
   virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D);
   
   virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
@@ -258,6 +261,8 @@
   virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
                              DeclTy **Elements, unsigned NumElements);
 private:
+  DeclContext *getDCParent(DeclContext *DC);
+
   /// Set the current declaration context until it gets popped.
   void PushDeclContext(DeclContext *DC);
   void PopDeclContext();
@@ -545,6 +550,9 @@
                                    SourceLocation LParenLoc, ExprTy *E,
                                    SourceLocation RParenLoc);
 
+  //// ActOnCXXThis -  Parse 'this' pointer.
+  virtual ExprResult ActOnCXXThis(SourceLocation ThisLoc);
+
   /// ActOnCXXBoolLiteral - Parse {true,false} literals.
   virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
                                          tok::TokenKind Kind);
@@ -585,6 +593,20 @@
                                   bool Virtual, AccessSpecifier Access,
                                   DeclTy *basetype, SourceLocation BaseLoc);
   
+  virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
+                                     SourceLocation LBrace);
+
+  virtual DeclTy *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+                                           Declarator &D, ExprTy *BitfieldWidth,
+                                           ExprTy *Init, DeclTy *LastInGroup);
+
+  virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+                                                 DeclTy *TagDecl,
+                                                 SourceLocation LBrac,
+                                                 SourceLocation RBrac);
+
+  virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl,SourceLocation RBrace);
+  
 
   // Objective-C declarations.
   virtual DeclTy *ActOnStartClassInterface(

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jul  1 05:37:29 2008
@@ -44,19 +44,38 @@
   return 0;
 }
 
+DeclContext *Sema::getDCParent(DeclContext *DC) {
+  // If CurContext is a ObjC method, getParent() will return NULL.
+  if (isa<ObjCMethodDecl>(DC))
+    return Context.getTranslationUnitDecl();
+
+  // A C++ inline method is parsed *after* the topmost class it was declared in
+  // is fully parsed (it's "complete").
+  // The parsing of a C++ inline method happens at the declaration context of
+  // the topmost (non-nested) class it is declared in.
+  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
+    assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
+    DC = MD->getParent();
+    while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
+      DC = RD;
+
+    // Return the declaration context of the topmost class the inline method is
+    // declared in.
+    return DC;
+  }
+
+  return DC->getParent();
+}
+
 void Sema::PushDeclContext(DeclContext *DC) {
-  assert( ( (isa<ObjCMethodDecl>(DC) && isa<TranslationUnitDecl>(CurContext))
-            || DC->getParent() == CurContext ) &&
-      "The next DeclContext should be directly contained in the current one.");
+  assert(getDCParent(DC) == CurContext &&
+       "The next DeclContext should be directly contained in the current one.");
   CurContext = DC;
 }
 
 void Sema::PopDeclContext() {
   assert(CurContext && "DeclContext imbalance!");
-  // If CurContext is a ObjC method, getParent() will return NULL.
-  CurContext = isa<ObjCMethodDecl>(CurContext)
-               ? Context.getTranslationUnitDecl()
-                 :  CurContext->getParent();
+  CurContext = getDCParent(CurContext);
 }
 
 /// Add this decl to the scope shadowed decl chains.
@@ -646,10 +665,19 @@
     }
 
     bool isInline = D.getDeclSpec().isInlineSpecified();
-    FunctionDecl *NewFD = FunctionDecl::Create(Context, CurContext,
-                                               D.getIdentifierLoc(),
-                                               II, R, SC, isInline,
-                                               LastDeclarator);
+    FunctionDecl *NewFD;
+    if (D.getContext() == Declarator::MemberContext) {
+      // This is a C++ method declaration.
+      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+                                    D.getIdentifierLoc(), II, R,
+                                    (SC == FunctionDecl::Static), isInline,
+                                    LastDeclarator);
+    } else {
+      NewFD = FunctionDecl::Create(Context, CurContext,
+                                   D.getIdentifierLoc(),
+                                   II, R, SC, isInline,
+                                   LastDeclarator);
+    }
     // Handle attributes.
     ProcessDeclAttributes(NewFD, D);
 
@@ -728,19 +756,27 @@
     case DeclSpec::SCS_register:       SC = VarDecl::Register; break;
     case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
     }    
-    if (S->getFnParent() == 0) {
-      // C99 6.9p2: The storage-class specifiers auto and register shall not
-      // appear in the declaration specifiers in an external declaration.
-      if (SC == VarDecl::Auto || SC == VarDecl::Register) {
-        Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
-             R.getAsString());
-        InvalidDecl = true;
-      }
-      NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
-                              II, R, SC, LastDeclarator);
+    if (D.getContext() == Declarator::MemberContext) {
+      assert(SC == VarDecl::Static && "Invalid storage class for member!");
+      // This is a static data member for a C++ class.
+      NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+                                      D.getIdentifierLoc(), II,
+                                      R, LastDeclarator);
     } else {
-      NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
-                              II, R, SC, LastDeclarator);
+      if (S->getFnParent() == 0) {
+        // C99 6.9p2: The storage-class specifiers auto and register shall not
+        // appear in the declaration specifiers in an external declaration.
+        if (SC == VarDecl::Auto || SC == VarDecl::Register) {
+          Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
+               R.getAsString());
+          InvalidDecl = true;
+        }
+        NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+                                II, R, SC, LastDeclarator);
+      } else {
+        NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+                                II, R, SC, LastDeclarator);
+      }
     }
     // Handle attributes prior to checking for duplicates in MergeVarDecl
     ProcessDeclAttributes(NewVD, D);
@@ -1506,7 +1542,13 @@
       }
     }
   }
-  Decl *decl = static_cast<Decl*>(ActOnDeclarator(GlobalScope, D, 0));
+
+  return ActOnStartOfFunctionDef(FnBodyScope,
+                                 ActOnDeclarator(GlobalScope, D, 0));
+}
+
+Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
+  Decl *decl = static_cast<Decl*>(D);
   FunctionDecl *FD = cast<FunctionDecl>(decl);
   PushDeclContext(FD);
     
@@ -1707,8 +1749,12 @@
 
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // struct X { int A; } D;    D should chain to X.
-    New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
-  }    
+    if (getLangOptions().CPlusPlus)
+      // FIXME: Look for a way to use RecordDecl for simple structs.
+      New = CXXRecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
+    else
+      New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
+  }
   
   // If this has an identifier, add it to the scope stack.
   if (Name) {
@@ -1843,7 +1889,17 @@
     }
   }
   // FIXME: Chain fielddecls together.
-  FieldDecl *NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth);
+  FieldDecl *NewFD;
+
+  if (getLangOptions().CPlusPlus) {
+    // FIXME: Replace CXXFieldDecls with FieldDecls for simple structs.
+    NewFD = CXXFieldDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+                                 Loc, II, T, BitWidth);
+    if (II)
+      PushOnScopeChains(NewFD, S);
+  }
+  else
+    NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth);
   
   ProcessDeclAttributes(NewFD, D);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jul  1 05:37:29 2008
@@ -14,6 +14,7 @@
 #include "Sema.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/StmtVisitor.h"
@@ -307,6 +308,175 @@
   // FIXME: Attach base class to the record.
 }
 
+//===----------------------------------------------------------------------===//
+// C++ class member Handling
+//===----------------------------------------------------------------------===//
+
+/// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
+/// definition, when on C++.
+void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) {
+  Decl *Dcl = static_cast<Decl *>(D);
+  PushDeclContext(cast<CXXRecordDecl>(Dcl));
+  FieldCollector->StartClass();
+}
+
+/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
+/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
+/// bitfield width if there is one and 'InitExpr' specifies the initializer if
+/// any. 'LastInGroup' is non-null for cases where one declspec has multiple
+/// declarators on it.
+///
+/// NOTE: Because of CXXFieldDecl's inability to be chained like ScopedDecls, if
+/// an instance field is declared, a new CXXFieldDecl is created but the method
+/// does *not* return it; it returns LastInGroup instead. The other C++ members
+/// (which are all ScopedDecls) are returned after appending them to
+/// LastInGroup.
+Sema::DeclTy *
+Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
+                               ExprTy *BW, ExprTy *InitExpr,
+                               DeclTy *LastInGroup) {
+  const DeclSpec &DS = D.getDeclSpec();
+  IdentifierInfo *II = D.getIdentifier();
+  Expr *BitWidth = static_cast<Expr*>(BW);
+  Expr *Init = static_cast<Expr*>(InitExpr);
+  SourceLocation Loc = D.getIdentifierLoc();
+
+  // C++ 9.2p6: A member shall not be declared to have automatic storage
+  // duration (auto, register) or with the extern storage-class-specifier.
+  switch (DS.getStorageClassSpec()) {
+    case DeclSpec::SCS_unspecified:
+    case DeclSpec::SCS_typedef:
+    case DeclSpec::SCS_static:
+      // FALL THROUGH.
+      break;
+    default:
+      if (DS.getStorageClassSpecLoc().isValid())
+        Diag(DS.getStorageClassSpecLoc(),
+             diag::err_storageclass_invalid_for_member);
+      else
+        Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member);
+      D.getMutableDeclSpec().ClearStorageClassSpecs();
+  }
+
+  QualType T = GetTypeForDeclarator(D, S);
+
+  // T->isFunctionType() is used instead of D.isFunctionDeclarator() to cover
+  // this case:
+  //
+  // typedef int f();
+  // f a;
+  bool isInstField = (DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
+                      !T->isFunctionType());
+
+  Decl *Member;
+  bool InvalidDecl = false;
+
+  if (isInstField)
+    Member = static_cast<Decl*>(ActOnField(S, Loc, D, BitWidth));
+  else
+    Member = static_cast<Decl*>(ActOnDeclarator(S, D, LastInGroup));
+
+  if (!Member) return LastInGroup;
+
+  assert(II || isInstField && "No identifier for non-field ?");
+
+  // set/getAccess is not part of Decl's interface to avoid bloating it with C++
+  // specific methods. Use a wrapper class that can be used with all C++ class
+  // member decls.
+  CXXClassMemberWrapper(Member).setAccess(AS);
+
+  if (BitWidth) {
+    // C++ 9.6p2: Only when declaring an unnamed bit-field may the
+    // constant-expression be a value equal to zero.
+    // FIXME: Check this.
+
+    if (D.isFunctionDeclarator()) {
+      // FIXME: Emit diagnostic about only constructors taking base initializers
+      // or something similar, when constructor support is in place.
+      Diag(Loc, diag::err_not_bitfield_type,
+           II->getName(), BitWidth->getSourceRange());
+      InvalidDecl = true;
+
+    } else if (isInstField || isa<FunctionDecl>(Member)) {
+      // An instance field or a function typedef ("typedef int f(); f a;").
+      // C++ 9.6p3: A bit-field shall have integral or enumeration type.
+      if (!T->isIntegralType()) {
+        Diag(Loc, diag::err_not_integral_type_bitfield,
+             II->getName(), BitWidth->getSourceRange());
+        InvalidDecl = true;
+      }
+
+    } else if (isa<TypedefDecl>(Member)) {
+      // "cannot declare 'A' to be a bit-field type"
+      Diag(Loc, diag::err_not_bitfield_type, II->getName(), 
+           BitWidth->getSourceRange());
+      InvalidDecl = true;
+
+    } else {
+      assert(isa<CXXClassVarDecl>(Member) &&
+             "Didn't we cover all member kinds?");
+      // C++ 9.6p3: A bit-field shall not be a static member.
+      // "static member 'A' cannot be a bit-field"
+      Diag(Loc, diag::err_static_not_bitfield, II->getName(), 
+           BitWidth->getSourceRange());
+      InvalidDecl = true;
+    }
+  }
+
+  if (Init) {
+    // C++ 9.2p4: A member-declarator can contain a constant-initializer only
+    // if it declares a static member of const integral or const enumeration
+    // type.
+    if (CXXClassVarDecl *CVD =
+              dyn_cast<CXXClassVarDecl>(Member)) { // ...static member of...
+      CVD->setInit(Init);
+      QualType MemberTy = CVD->getType().getCanonicalType();
+      // ...const integral or const enumeration type.
+      if (MemberTy.isConstQualified() && MemberTy->isIntegralType()) {
+        if (CheckForConstantInitializer(Init, MemberTy)) // constant-initializer
+          InvalidDecl = true;
+
+      } else {
+        // not const integral.
+        Diag(Loc, diag::err_member_initialization,
+             II->getName(), Init->getSourceRange());
+        InvalidDecl = true;
+      }
+
+    } else {
+      // not static member.
+      Diag(Loc, diag::err_member_initialization,
+           II->getName(), Init->getSourceRange());
+      InvalidDecl = true;
+    }
+  }
+
+  if (InvalidDecl)
+    Member->setInvalidDecl();
+
+  if (isInstField) {
+    FieldCollector->Add(cast<CXXFieldDecl>(Member));
+    return LastInGroup;
+  }
+  return Member;
+}
+
+void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+                                             DeclTy *TagDecl,
+                                             SourceLocation LBrac,
+                                             SourceLocation RBrac) {
+  ActOnFields(S, RLoc, TagDecl,
+              (DeclTy**)FieldCollector->getCurFields(),
+              FieldCollector->getCurNumFields(), LBrac, RBrac);
+}
+
+void Sema::ActOnFinishCXXClassDef(DeclTy *D,SourceLocation RBrace) {
+  Decl *Dcl = static_cast<Decl *>(D);
+  assert(isa<CXXRecordDecl>(Dcl) &&
+         "Invalid parameter, expected CXXRecordDecl");
+  FieldCollector->FinishClass();
+  PopDeclContext();
+}
 
 //===----------------------------------------------------------------------===//
 // Namespace Handling

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jul  1 05:37:29 2008
@@ -14,6 +14,7 @@
 #include "Sema.h"
 #include "SemaUtil.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -130,6 +131,29 @@
       return true;
     return new DeclRefExpr(VD, VD->getType(), Loc);
   }
+
+  if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) {
+    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+      if (MD->isStatic())
+        // "invalid use of member 'x' in static member function"
+        return Diag(Loc, diag::err_invalid_member_use_in_static_method,
+                    FD->getName());
+      if (cast<CXXRecordDecl>(MD->getParent()) != FD->getParent())
+        // "invalid use of nonstatic data member 'x'"
+        return Diag(Loc, diag::err_invalid_non_static_member_use,
+                    FD->getName());
+
+      if (FD->isInvalidDecl())
+        return true;
+
+      // FIXME: Use DeclRefExpr or a new Expr for a direct CXXField reference.
+      ExprResult ThisExpr = ActOnCXXThis(SourceLocation());
+      return new MemberExpr(static_cast<Expr*>(ThisExpr.Val),
+                            true, FD, Loc, FD->getType());
+    }
+
+    return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());
+  }
   
   if (isa<TypedefDecl>(D))
     return Diag(Loc, diag::err_unexpected_typedef, II.getName());

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=52956&r1=52955&r2=52956&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jul  1 05:37:29 2008
@@ -49,3 +49,21 @@
 Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprTy *E) {
   return new CXXThrowExpr((Expr*)E, Context.VoidTy, OpLoc);
 }
+
+Action::ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
+  /// 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.
+
+  if (!isa<FunctionDecl>(CurContext)) {
+    Diag(ThisLoc, diag::err_invalid_this_use);
+    return ExprResult(true);
+  }
+
+  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
+    if (MD->isInstance())
+      return new PreDefinedExpr(ThisLoc, MD->getThisType(Context),
+                                PreDefinedExpr::CXXThis);
+
+  return Diag(ThisLoc, diag::err_invalid_this_use);
+}

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

==============================================================================
--- cfe/trunk/test/Sema/cxx-class.cpp (added)
+++ cfe/trunk/test/Sema/cxx-class.cpp Tue Jul  1 05:37:29 2008
@@ -0,0 +1,70 @@
+// RUN: clang -fsyntax-only -verify %s 
+class C {
+public:
+  auto int errx; // expected-error {{error: storage class specified for a member declaration}}
+  register int erry; // expected-error {{error: storage class specified for a member declaration}}
+  extern int errz; // expected-error {{error: storage class specified for a member declaration}}
+
+  static void sm() {
+    sx = 0;
+    this->x = 0; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+    x = 0; // expected-error {{error: invalid use of member 'x' in static member function}}
+  }
+
+  class NestedC {
+    void m() {
+      sx = 0;
+      x = 0; // expected-error {{error: invalid use of nonstatic data member 'x'}}
+    }
+  };
+
+  int b : 1, w : 2;
+  int : 1, : 2;
+  typedef int E : 1; // expected-error {{error: cannot declare 'E' to be a bit-field type}}
+  static int sb : 1; // expected-error {{error: static member 'sb' cannot be a bit-field}}
+  static int vs;
+
+  typedef int func();
+  func tm;
+  func btm : 1; // expected-error {{error: bit-field 'btm' with non-integral type}}
+  NestedC bc : 1; // expected-error {{error: bit-field 'bc' with non-integral type}}
+
+  enum E { en1, en2 };
+
+  int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
+  static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
+  static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
+  static const int nci = vs; // expected-error {{error: initializer element is not constant}}
+  static const int vi = 0;
+  static const E evi = 0;
+
+  void m() {
+    sx = 0;
+    this->x = 0;
+    y = 0;
+    this = 0; // expected-error {{error: expression is not assignable}}
+  }
+
+  int f1(int p) {
+   A z = 6;
+   return p + x + this->y + z;
+  }
+
+  typedef int A;
+
+private:
+  int x,y;
+  static int sx;
+};
+
+class C2 {
+  void f() {
+    static int lx;
+    class LC1 {
+      int m() { return lx; }
+    };
+    class LC2 {
+      int m() { return lx; }
+    };
+  }
+};

Added: cfe/trunk/test/Sema/cxx-this.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/cxx-this.cpp?rev=52956&view=auto

==============================================================================
--- cfe/trunk/test/Sema/cxx-this.cpp (added)
+++ cfe/trunk/test/Sema/cxx-this.cpp Tue Jul  1 05:37:29 2008
@@ -0,0 +1,6 @@
+// RUN: clang -fsyntax-only -verify %s 
+int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+
+void f() {
+  int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+}





More information about the cfe-commits mailing list