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/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 51e4e05..7fafb14 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1244,24 +1244,44 @@
                << &Member << BaseExpr->getSourceRange();
     } 
 
-    FieldDecl *MemberDecl = dyn_cast<FieldDecl>(*Lookup.first);
-    if (!MemberDecl) {
-      unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
-                          "Clang only supports references to members");
-      return Diag(MemberLoc, DiagID);
-    }
+    if (FieldDecl *MemberDecl = dyn_cast<FieldDecl>(*Lookup.first)) {
+      // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+      // FIXME: Handle address space modifiers
+      QualType MemberType = MemberDecl->getType();
+      if (const ReferenceType *Ref = MemberType->getAsReferenceType())
+        MemberType = Ref->getPointeeType();
+      else {
+        unsigned combinedQualifiers =
+          MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
+        if (MemberDecl->isMutable())
+          combinedQualifiers &= ~QualType::Const;
+        MemberType = MemberType.getQualifiedType(combinedQualifiers);
+      }
 
-    // Figure out the type of the member; see C99 6.5.2.3p3
-    // FIXME: Handle address space modifiers
-    QualType MemberType = MemberDecl->getType();
-    unsigned combinedQualifiers =
-        MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
-    if (MemberDecl->isMutable())
-      combinedQualifiers &= ~QualType::Const;
-    MemberType = MemberType.getQualifiedType(combinedQualifiers);
+      return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
+                            MemberLoc, MemberType);
+    } else if (CXXClassVarDecl *Var = dyn_cast<CXXClassVarDecl>(*Lookup.first))
+      return new MemberExpr(BaseExpr, OpKind == tok::arrow, Var, MemberLoc,
+                            Var->getType().getNonReferenceType());
+    else if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(*Lookup.first))
+      return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberFn, MemberLoc,
+                            MemberFn->getType());
+    else if (OverloadedFunctionDecl *Ovl 
+             = dyn_cast<OverloadedFunctionDecl>(*Lookup.first))
+      return new MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl, MemberLoc,
+                            Context.OverloadTy);
+    else if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(*Lookup.first))
+      return new MemberExpr(BaseExpr, OpKind == tok::arrow, Enum, MemberLoc,
+                            Enum->getType());
+    else if (isa<TypeDecl>(*Lookup.first))
+      return Diag(MemberLoc, diag::err_typecheck_member_reference_type)
+        << DeclarationName(&Member) << int(OpKind == tok::arrow);
 
-    return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
-                          MemberLoc, MemberType);
+    // We found a declaration kind that we didn't expect. This is a
+    // generic error message that tells the user that she can't refer
+    // to this member with '.' or '->'.
+    return Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+      << DeclarationName(&Member) << int(OpKind == tok::arrow);
   }
   
   // Handle access to Objective-C instance variables, such as "Obj->ivar" and
@@ -2920,10 +2940,12 @@
       return QualType();
     }
   } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(op)) { // C99 6.5.3.2p1
-    if (MemExpr->getMemberDecl()->isBitField()) {
-      Diag(OpLoc, diag::err_typecheck_address_of)
-        << "bit-field" << op->getSourceRange();
-      return QualType();
+    if (FieldDecl *Field = dyn_cast<FieldDecl>(MemExpr->getMemberDecl())) {
+      if (Field->isBitField()) {
+        Diag(OpLoc, diag::err_typecheck_address_of)
+          << "bit-field" << op->getSourceRange();
+        return QualType();
+      }
     }
   // Check for Apple extension for accessing vector components.
   } else if (isa<ArraySubscriptExpr>(op) &&
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index c719f56..fe4b763 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -666,26 +666,27 @@
   // other value of that type for promotion purposes (C++ 4.5p3).
   if (MemberExpr *MemRef = dyn_cast<MemberExpr>(From)) {
     using llvm::APSInt;
-    FieldDecl *MemberDecl = MemRef->getMemberDecl();
-    APSInt BitWidth;
-    if (MemberDecl->isBitField() &&
-        FromType->isIntegralType() && !FromType->isEnumeralType() &&
-        From->isIntegerConstantExpr(BitWidth, Context)) {
-      APSInt ToSize(Context.getTypeSize(ToType));
-
-      // Are we promoting to an int from a bitfield that fits in an int?
-      if (BitWidth < ToSize ||
-          (FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
-        return To->getKind() == BuiltinType::Int;
+    if (FieldDecl *MemberDecl = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) {
+      APSInt BitWidth;
+      if (MemberDecl->isBitField() &&
+          FromType->isIntegralType() && !FromType->isEnumeralType() &&
+          From->isIntegerConstantExpr(BitWidth, Context)) {
+        APSInt ToSize(Context.getTypeSize(ToType));
+        
+        // Are we promoting to an int from a bitfield that fits in an int?
+        if (BitWidth < ToSize ||
+            (FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
+          return To->getKind() == BuiltinType::Int;
+        }
+        
+        // Are we promoting to an unsigned int from an unsigned bitfield
+        // that fits into an unsigned int?
+        if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
+          return To->getKind() == BuiltinType::UInt;
+        }
+        
+        return false;
       }
-
-      // Are we promoting to an unsigned int from an unsigned bitfield
-      // that fits into an unsigned int?
-      if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
-        return To->getKind() == BuiltinType::UInt;
-      }
-
-      return false;
     }
   }