Add support for member references (E1.E2, E1->E2) with C++ semantics,
which can refer to static data members, enumerators, and member
functions as well as to non-static data members.

Implement correct lvalue computation for member references in C++. 
Compute the result type of non-static data members of reference type properly.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61294 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 8aaea7a..adad2a4 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -407,8 +407,43 @@
       return LV_Valid;
     break;
   }
-  case MemberExprClass: { // C99 6.5.2.3p4
+  case MemberExprClass: { 
     const MemberExpr *m = cast<MemberExpr>(this);
+    if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4:
+      NamedDecl *Member = m->getMemberDecl();
+      // C++ [expr.ref]p4:
+      //   If E2 is declared to have type "reference to T", then E1.E2
+      //   is an lvalue.
+      if (ValueDecl *Value = dyn_cast<ValueDecl>(Member))
+        if (Value->getType()->isReferenceType())
+          return LV_Valid;
+
+      //   -- If E2 is a static data member [...] then E1.E2 is an lvalue.
+      if (isa<CXXClassVarDecl>(Member))
+        return LV_Valid;
+
+      //   -- If E2 is a non-static data member [...]. If E1 is an
+      //      lvalue, then E1.E2 is an lvalue.
+      if (isa<FieldDecl>(Member))
+        return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
+
+      //   -- If it refers to a static member function [...], then
+      //      E1.E2 is an lvalue.
+      //   -- Otherwise, if E1.E2 refers to a non-static member
+      //      function [...], then E1.E2 is not an lvalue.
+      if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member))
+        return Method->isStatic()? LV_Valid : LV_MemberFunction;
+
+      //   -- If E2 is a member enumerator [...], the expression E1.E2
+      //      is not an lvalue.
+      if (isa<EnumConstantDecl>(Member))
+        return LV_InvalidExpression;
+
+        // Not an lvalue.
+      return LV_InvalidExpression;
+    } 
+
+    // C99 6.5.2.3p4
     return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
   }
   case UnaryOperatorClass:
@@ -542,6 +577,7 @@
       if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid)
         return MLV_LValueCast;
     return MLV_InvalidExpression;
+  case LV_MemberFunction: return MLV_MemberFunction;
   }
   
   QualType CT = Ctx.getCanonicalType(getType());
@@ -1113,7 +1149,8 @@
 bool Expr::isBitField() {
   Expr *E = this->IgnoreParenCasts();
   if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
-    return MemRef->getMemberDecl()->isBitField();
+    if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
+        return Field->isBitField();
   return false;
 }
 
@@ -1245,21 +1282,21 @@
     
     RecordDecl *RD = Ty->getAsRecordType()->getDecl();
     const ASTRecordLayout &RL = C.getASTRecordLayout(RD);
-    FieldDecl *FD = ME->getMemberDecl();
-    
-    // FIXME: This is linear time. And the fact that we're indexing
-    // into the layout by position in the record means that we're
-    // either stuck numbering the fields in the AST or we have to keep
-    // the linear search (yuck and yuck).
-    unsigned i = 0;
-    for (RecordDecl::field_iterator Field = RD->field_begin(),
-                                 FieldEnd = RD->field_end();
-         Field != FieldEnd; (void)++Field, ++i) {
-      if (*Field == FD)
-        break;
+    if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+      // FIXME: This is linear time. And the fact that we're indexing
+      // into the layout by position in the record means that we're
+      // either stuck numbering the fields in the AST or we have to keep
+      // the linear search (yuck and yuck).
+      unsigned i = 0;
+      for (RecordDecl::field_iterator Field = RD->field_begin(),
+                                   FieldEnd = RD->field_end();
+           Field != FieldEnd; (void)++Field, ++i) {
+        if (*Field == FD)
+          break;
+      }
+      
+      return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase());
     }
-    
-    return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase());
   } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
     const Expr *Base = ASE->getBase();
     
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6810167..11f07fb 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -153,7 +153,10 @@
 
   RecordDecl *RD = Ty->getAsRecordType()->getDecl();
   const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
-  FieldDecl *FD = E->getMemberDecl();
+
+  FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+  if (!FD) // FIXME: deal with other kinds of member expressions
+    return APValue();
     
   // FIXME: This is linear time.
   unsigned i = 0;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 94bca63..4061aa1 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -702,10 +702,7 @@
 void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
   PrintExpr(Node->getBase());
   OS << (Node->isArrow() ? "->" : ".");
-  
-  FieldDecl *Field = Node->getMemberDecl();
-  assert(Field && "MemberExpr should alway reference a field!");
-  OS << Field->getNameAsString();
+  OS << Node->getMemberDecl()->getNameAsString();
 }
 void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
   PrintExpr(Node->getBase());
diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp
index 686ee68..d12ecd0 100644
--- a/lib/AST/StmtSerialization.cpp
+++ b/lib/AST/StmtSerialization.cpp
@@ -761,7 +761,7 @@
 
 MemberExpr* MemberExpr::CreateImpl(Deserializer& D, ASTContext& C) {
   SourceLocation L = SourceLocation::ReadVal(D);
-  FieldDecl* MemberDecl = cast<FieldDecl>(D.ReadPtr<Decl>());
+  NamedDecl* MemberDecl = cast<NamedDecl>(D.ReadPtr<Decl>());
   bool IsArrow = D.ReadBool();
   QualType T = QualType::ReadVal(D);
   Expr* base = D.ReadOwnedPtr<Expr>(C);