Add Sema support for C++ classes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52956 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 45affca..8050557 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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