Implement dereferencing of pointers-to-member.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63983 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index d627ab0..89fdbe3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -496,6 +496,12 @@
         BinOp->getOpcode() == BinaryOperator::Comma)
       return BinOp->getRHS()->isLvalue(Ctx);
 
+    // C++ [expr.mptr.oper]p6
+    if ((BinOp->getOpcode() == BinaryOperator::PtrMemD ||
+         BinOp->getOpcode() == BinaryOperator::PtrMemI) &&
+        !BinOp->getType()->isFunctionType())
+      return BinOp->getLHS()->isLvalue(Ctx);
+
     if (!BinOp->isAssignmentOp())
       return LV_InvalidExpression;
 
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 597c50c..7c0b439 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -33,20 +33,21 @@
 /// productions.  Low precedences numbers bind more weakly than high numbers.
 namespace prec {
   enum Level {
-    Unknown        = 0,    // Not binary operator.
-    Comma          = 1,    // ,
-    Assignment     = 2,    // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
-    Conditional    = 3,    // ?
-    LogicalOr      = 4,    // ||
-    LogicalAnd     = 5,    // &&
-    InclusiveOr    = 6,    // |
-    ExclusiveOr    = 7,    // ^
-    And            = 8,    // &
-    Equality       = 9,    // ==, !=
-    Relational     = 10,   //  >=, <=, >, <
-    Shift          = 11,   // <<, >>
-    Additive       = 12,   // -, +
-    Multiplicative = 13    // *, /, %
+    Unknown         = 0,    // Not binary operator.
+    Comma           = 1,    // ,
+    Assignment      = 2,    // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+    Conditional     = 3,    // ?
+    LogicalOr       = 4,    // ||
+    LogicalAnd      = 5,    // &&
+    InclusiveOr     = 6,    // |
+    ExclusiveOr     = 7,    // ^
+    And             = 8,    // &
+    Equality        = 9,    // ==, !=
+    Relational      = 10,   //  >=, <=, >, <
+    Shift           = 11,   // <<, >>
+    Additive        = 12,   // -, +
+    Multiplicative  = 13,   // *, /, %
+    PointerToMember = 14    // .*, ->*
   };
 }
 
@@ -88,6 +89,8 @@
   case tok::percent:
   case tok::slash:
   case tok::star:                 return prec::Multiplicative;
+  case tok::periodstar:
+  case tok::arrowstar:            return prec::PointerToMember;
   }
 }
 
@@ -104,7 +107,13 @@
 /// consistency, we parse the LHS as a conditional-expression, then check for
 /// l-value-ness in semantic analysis stages.
 ///
+///       pm-expression: [C++ 5.5]
+///         cast-expression
+///         pm-expression '.*' cast-expression
+///         pm-expression '->*' cast-expression
+///
 ///       multiplicative-expression: [C99 6.5.5]
+///     Note: in C++, apply pm-expression instead of cast-expression
 ///         cast-expression
 ///         multiplicative-expression '*' cast-expression
 ///         multiplicative-expression '/' cast-expression
@@ -270,7 +279,7 @@
     // Consume the operator, saving the operator token for error reporting.
     Token OpToken = Tok;
     ConsumeToken();
-    
+
     // Special case handling for the ternary operator.
     OwningExprResult TernaryMiddle(Actions, true);
     if (NextTokPrec == prec::Conditional) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 33b3781..4878403 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1788,16 +1788,18 @@
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const StandardConversionSequence& SCS,
                                  const char *Flavor);
-  
+
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).
-    
-  /// type checking binary operators (subroutines of ActOnBinOp).
+
+  /// type checking binary operators (subroutines of CreateBuiltinBinOp).
   inline QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+  inline QualType CheckPointerToMemberOperands( // C++ 5.5
+    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect);
   inline QualType CheckMultiplyDivideOperands( // C99 6.5.5
-    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); 
+    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
   inline QualType CheckRemainderOperands( // C99 6.5.5
-    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); 
+    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
   inline QualType CheckAdditionOperands( // C99 6.5.6
     Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
   inline QualType CheckSubtractionOperands( // C99 6.5.6
@@ -1807,7 +1809,7 @@
   inline QualType CheckCompareOperands( // C99 6.5.8/9
     Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational);
   inline QualType CheckBitwiseOperands( // C99 6.5.[10...12]
-    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); 
+    Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
   inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
     Expr *&lex, Expr *&rex, SourceLocation OpLoc);
   // CheckAssignmentOperands is used for both simple and compound assignment.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 8c8207a..3de916f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "SemaInherit.h"
 #include "Sema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
@@ -2701,7 +2702,73 @@
     << lex->getType() << rex->getType()
     << lex->getSourceRange() << rex->getSourceRange();
   return QualType();
-}    
+}
+
+inline QualType Sema::CheckPointerToMemberOperands(
+  Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect)
+{
+  const char *OpSpelling = isIndirect ? "->*" : ".*";
+  // C++ 5.5p2
+  //   The binary operator .* [p3: ->*] binds its second operand, which shall
+  //   be of type "pointer to member of T" (where T is a completely-defined
+  //   class type) [...]
+  QualType RType = rex->getType();
+  const MemberPointerType *MemPtr = RType->getAsMemberPointerType();
+  if (!MemPtr || MemPtr->getClass()->isIncompleteType()) {
+    Diag(Loc, diag::err_bad_memptr_rhs)
+      << OpSpelling << RType << rex->getSourceRange();
+    return QualType();
+  }
+  QualType Class(MemPtr->getClass(), 0);
+
+  // C++ 5.5p2
+  //   [...] to its first operand, which shall be of class T or of a class of
+  //   which T is an unambiguous and accessible base class. [p3: a pointer to
+  //   such a class]
+  QualType LType = lex->getType();
+  if (isIndirect) {
+    if (const PointerType *Ptr = LType->getAsPointerType())
+      LType = Ptr->getPointeeType().getNonReferenceType();
+    else {
+      Diag(Loc, diag::err_bad_memptr_lhs)
+        << 1 << LType << lex->getSourceRange();
+      return QualType();
+    }
+  }
+
+  if (Context.getCanonicalType(Class).getUnqualifiedType() !=
+      Context.getCanonicalType(LType).getUnqualifiedType()) {
+    BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+                    /*DetectVirtual=*/false);
+    // FIXME: Would it be useful to print full ambiguity paths,
+    // or is that overkill?
+    if (!IsDerivedFrom(LType, Class, Paths) ||
+        Paths.isAmbiguous(Context.getCanonicalType(Class))) {
+      Diag(Loc, diag::err_bad_memptr_lhs)
+        << (int)isIndirect << lex->getType() << lex->getSourceRange();
+      return QualType();
+    }
+  }
+
+  // C++ 5.5p2
+  //   The result is an object or a function of the type specified by the
+  //   second operand.
+  // The cv qualifiers are the union of those in the pointer and the left side,
+  // in accordance with 5.5p5 and 5.2.5.
+  // FIXME: This returns a dereferenced member function pointer as a normal
+  // function type. However, the only operation valid on such functions is
+  // calling them. There's also a GCC extension to get a function pointer to
+  // the thing, which is another complication, because this type - unlike the
+  // type that is the result of this expression - takes the class as the first
+  // argument.
+  // We probably need a "MemberFunctionClosureType" or something like that.
+  QualType Result = MemPtr->getPointeeType();
+  if (LType.isConstQualified())
+    Result.addConst();
+  if (LType.isVolatileQualified())
+    Result.addVolatile();
+  return Result;
+}
 
 inline QualType Sema::CheckMultiplyDivideOperands(
   Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) 
@@ -3535,6 +3602,8 @@
   BinaryOperator::Opcode Opc;
   switch (Kind) {
   default: assert(0 && "Unknown binop!");
+  case tok::periodstar:           Opc = BinaryOperator::PtrMemD; break;
+  case tok::arrowstar:            Opc = BinaryOperator::PtrMemI; break;
   case tok::star:                 Opc = BinaryOperator::Mul; break;
   case tok::slash:                Opc = BinaryOperator::Div; break;
   case tok::percent:              Opc = BinaryOperator::Rem; break;
@@ -3605,7 +3674,12 @@
   case BinaryOperator::Assign:
     ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType());
     break;
-  case BinaryOperator::Mul: 
+  case BinaryOperator::PtrMemD:
+  case BinaryOperator::PtrMemI:
+    ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc,
+                                            Opc == BinaryOperator::PtrMemI);
+    break;
+  case BinaryOperator::Mul:
   case BinaryOperator::Div:
     ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc);
     break;
@@ -3618,7 +3692,7 @@
   case BinaryOperator::Sub:
     ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc);
     break;
-  case BinaryOperator::Shl: 
+  case BinaryOperator::Shl:
   case BinaryOperator::Shr:
     ResultTy = CheckShiftOperands(lhs, rhs, OpLoc);
     break;
@@ -3707,11 +3781,11 @@
                                               Context.DependentTy,
                                               Context.DependentTy, TokLoc));
     else
-      return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, Context.DependentTy,
-                                                TokLoc));
+      return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
+                                                Context.DependentTy, TokLoc));
   }
 
-  if (getLangOptions().CPlusPlus &&
+  if (getLangOptions().CPlusPlus && Opc != BinaryOperator::PtrMemD &&
       (lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||
        rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) {
     // If this is one of the assignment operators, we only perform
@@ -3724,6 +3798,8 @@
 
     // Determine which overloaded operator we're dealing with.
     static const OverloadedOperatorKind OverOps[] = {
+      // Overloading .* is not possible.
+      static_cast<OverloadedOperatorKind>(0), OO_ArrowStar,
       OO_Star, OO_Slash, OO_Percent,
       OO_Plus, OO_Minus,
       OO_LessLess, OO_GreaterGreater,
diff --git a/lib/Sema/SemaInherit.h b/lib/Sema/SemaInherit.h
index eb169a2..311c136 100644
--- a/lib/Sema/SemaInherit.h
+++ b/lib/Sema/SemaInherit.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_CLANG_SEMA_INHERIT_H
 #define LLVM_CLANG_SEMA_INHERIT_H
 
+#include "Sema.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/Type.h"
@@ -25,7 +26,6 @@
 #include <map>
 
 namespace clang {
-  class Sema;
   class CXXBaseSpecifier;
   class CXXRecordType;
 
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 78b2626..ee4c14d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -610,8 +610,8 @@
         // using-directives later.
         for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext();
              OutOfLineCtx = OutOfLineCtx->getParent()) {
-          if (R = LookupQualifiedName(OutOfLineCtx, Name, NameKind,
-                                      RedeclarationOnly))
+          if ((R = LookupQualifiedName(OutOfLineCtx, Name, NameKind,
+                                      RedeclarationOnly)))
             return std::make_pair(true, R);
         }
       }
@@ -638,7 +638,7 @@
   // context as well as walking through the scopes.
 
   LookupResultsTy LookupResults;
-  assert(!OutOfLineCtx || OutOfLineCtx->isFileContext() &&
+  assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) &&
          "We should have been looking only at file context here already.");
   bool LookedInCtx = false;
   LookupResult Result;