Support overloading of the subscript operator[], including support for
built-in operator candidates. Test overloading of '&' and ','.

In C++, a comma expression is an lvalue if its right-hand
subexpression is an lvalue. Update Expr::isLvalue accordingly.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59643 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index a179af8..0614020 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -412,6 +412,11 @@
   case BinaryOperatorClass:
   case CompoundAssignOperatorClass: {
     const BinaryOperator *BinOp = cast<BinaryOperator>(this);
+
+    if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1
+        BinOp->getOpcode() == BinaryOperator::Comma)
+      return BinOp->getRHS()->isLvalue(Ctx);
+
     if (!BinOp->isAssignmentOp())
       return LV_InvalidExpression;
 
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 5f36f0b..74b0715 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -672,7 +672,8 @@
       SourceLocation RLoc = Tok.getLocation();
       
       if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square))
-        LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc);
+        LHS = Actions.ActOnArraySubscriptExpr(CurScope, LHS.Val, Loc, 
+                                              Idx.Val, RLoc);
       else 
         LHS = ExprResult(true);
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b10a98f..983fa30 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -652,8 +652,9 @@
   virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                          tok::TokenKind Kind, ExprTy *Input);
   
-  virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
-                                             ExprTy *Idx, SourceLocation RLoc);
+  virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, 
+                                             SourceLocation LLoc, ExprTy *Idx,
+                                             SourceLocation RLoc);
   virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
                                               tok::TokenKind OpKind,
                                               SourceLocation MemberLoc,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c780372..a780012 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -861,10 +861,93 @@
 }
 
 Action::ExprResult Sema::
-ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, SourceLocation LLoc,
                         ExprTy *Idx, SourceLocation RLoc) {
   Expr *LHSExp = static_cast<Expr*>(Base), *RHSExp = static_cast<Expr*>(Idx);
 
+  if (getLangOptions().CPlusPlus &&
+      LHSExp->getType()->isRecordType() || 
+      LHSExp->getType()->isEnumeralType() ||
+      RHSExp->getType()->isRecordType() ||
+      RHSExp->getType()->isRecordType()) {
+    // Add the appropriate overloaded operators (C++ [over.match.oper]) 
+    // to the candidate set.
+    OverloadCandidateSet CandidateSet;
+    Expr *Args[2] = { LHSExp, RHSExp };
+    AddOperatorCandidates(OO_Subscript, S, Args, 2, CandidateSet);
+    
+    // Perform overload resolution.
+    OverloadCandidateSet::iterator Best;
+    switch (BestViableFunction(CandidateSet, Best)) {
+    case OR_Success: {
+      // We found a built-in operator or an overloaded operator.
+      FunctionDecl *FnDecl = Best->Function;
+
+      if (FnDecl) {
+        // We matched an overloaded operator. Build a call to that
+        // operator.
+
+        // Convert the arguments.
+        if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+          if (PerformObjectArgumentInitialization(LHSExp, Method) ||
+              PerformCopyInitialization(RHSExp, 
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing"))
+            return true;
+        } else {
+          // Convert the arguments.
+          if (PerformCopyInitialization(LHSExp,
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing") ||
+              PerformCopyInitialization(RHSExp,
+                                        FnDecl->getParamDecl(1)->getType(),
+                                        "passing"))
+            return true;
+        }
+
+        // Determine the result type
+        QualType ResultTy 
+          = FnDecl->getType()->getAsFunctionType()->getResultType();
+        ResultTy = ResultTy.getNonReferenceType();
+        
+        // Build the actual expression node.
+        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), 
+                                       SourceLocation());
+        UsualUnaryConversions(FnExpr);
+
+        return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, LLoc);
+      } else {
+        // We matched a built-in operator. Convert the arguments, then
+        // break out so that we will build the appropriate built-in
+        // operator node.
+        if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0],
+                                      "passing") ||
+            PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1],
+                                      "passing"))
+          return true;
+
+        break;
+      }
+    }
+
+    case OR_No_Viable_Function:
+      // No viable function; fall through to handling this as a
+      // built-in operator, which will produce an error message for us.
+      break;
+
+    case OR_Ambiguous:
+      Diag(LLoc,  diag::err_ovl_ambiguous_oper)
+          << "[]"
+          << LHSExp->getSourceRange() << RHSExp->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return true;
+    }
+
+    // Either we found no viable overloaded operator or we matched a
+    // built-in operator. In either case, fall through to trying to
+    // build a built-in operation.
+  }
+
   // Perform default conversions.
   DefaultFunctionArrayConversion(LHSExp);
   DefaultFunctionArrayConversion(RHSExp);
@@ -3009,7 +3092,6 @@
     // built-in operator. In either case, fall through to trying to
     // build a built-in operation.
   } 
-
   
   // Build a built-in binary operation.
   return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);