Refactor the way we handle operator overloading and template
instantiation for binary operators. This change moves most of the
operator-overloading code from the parser action ActOnBinOp to a new,
parser-independent semantic checking routine CreateOverloadedBinOp. 

Of particular importance is the fact that CreateOverloadedBinOp does
*not* perform any name lookup based on the current parsing context (it
doesn't take a Scope*), since it has to be usable during template
instantiation, when there is no scope information. Rather, it takes a
pre-computed set of functions that are visible from the context or via
argument-dependent lookup, and adds to that set any member operators
and built-in operator candidates. The set of functions is computed in
the parser action ActOnBinOp based on the current context (both
operator name lookup and argument-dependent lookup). Within a
template, the set computed by ActOnBinOp is saved within the
type-dependent AST node and is augmented with the results of
argument-dependent name lookup at instantiation time (see
TemplateExprInstantiator::VisitCXXOperatorCallExpr).

Sadly, we can't fully test this yet. I'll follow up with template
instantiation for sizeof so that the real fun can begin.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66923 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4a31452..0855932 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1324,8 +1324,7 @@
 
     // Build the candidate set for overloading
     OverloadCandidateSet CandidateSet;
-    if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
-      return ExprError();
+    AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -1361,8 +1360,9 @@
         UsualUnaryConversions(FnExpr);
 
         Input.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
-                                                       ResultTy, OpLoc));
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
+                                                       Args, 2, ResultTy, 
+                                                       OpLoc));
       } else {
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in
@@ -1424,9 +1424,8 @@
     // to the candidate set.
     OverloadCandidateSet CandidateSet;
     Expr *Args[2] = { LHSExp, RHSExp };
-    if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
-                              SourceRange(LLoc, RLoc)))
-      return ExprError();
+    AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
+                          SourceRange(LLoc, RLoc));
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -1469,7 +1468,8 @@
 
         Base.release();
         Idx.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+                                                       FnExpr, Args, 2, 
                                                        ResultTy, LLoc));
       } else {
         // We matched a built-in operator. Convert the arguments, then
@@ -3977,32 +3977,6 @@
                                                       CompTy, OpLoc));
 }
 
-static OverloadedOperatorKind 
-getOverloadedOperator(BinaryOperator::Opcode Opc) {
-  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,
-    OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
-    OO_EqualEqual, OO_ExclaimEqual,
-    OO_Amp,
-    OO_Caret,
-    OO_Pipe,
-    OO_AmpAmp,
-    OO_PipePipe,
-    OO_Equal, OO_StarEqual,
-    OO_SlashEqual, OO_PercentEqual,
-    OO_PlusEqual, OO_MinusEqual,
-    OO_LessLessEqual, OO_GreaterGreaterEqual,
-    OO_AmpEqual, OO_CaretEqual,
-    OO_PipeEqual,
-    OO_Comma
-  };
-  return OverOps[Opc];
-}
-
 // Binary Operators.  'Tok' is the token for the operator.
 Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
                                           tok::TokenKind Kind,
@@ -4013,139 +3987,27 @@
   assert((lhs != 0) && "ActOnBinOp(): missing left expression");
   assert((rhs != 0) && "ActOnBinOp(): missing right expression");
 
-  // If either expression is type-dependent, just build the AST.
-  if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
-    // .* cannot be overloaded.
-    if (Opc == BinaryOperator::PtrMemD)
-      return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
-                                                Context.DependentTy, TokLoc));
-    
-    // Find all of the overloaded operators visible from the template
-    // definition. We perform both an operator-name lookup from the
-    // local scope and an argument-dependent lookup based on the types
-    // of the arguments.
+  if (getLangOptions().CPlusPlus &&
+      (lhs->getType()->isOverloadableType() || 
+       rhs->getType()->isOverloadableType())) {
+    // Find all of the overloaded operators visible from this
+    // point. We perform both an operator-name lookup from the local
+    // scope and an argument-dependent lookup based on the types of
+    // the arguments.
     FunctionSet Functions;
-    OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
-    LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
-                                 Functions);
-    Expr *Args[2] = { lhs, rhs };
-    DeclarationName OpName 
-      = Context.DeclarationNames.getCXXOperatorName(OverOp);
-    ArgumentDependentLookup(OpName, Args, 2, Functions);
-
-    OverloadedFunctionDecl *Overloads 
-      = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
-    for (FunctionSet::iterator Func = Functions.begin(), 
-                            FuncEnd = Functions.end();
-         Func != FuncEnd; ++Func)
-      Overloads->addOverload(*Func);
-
-    DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
-                                                TokLoc, false, false);
-    
-    return Owned(new (Context) CXXOperatorCallExpr(Context, Fn,
-                                                   Args, 2, 
-                                                   Context.DependentTy,
-                                                   TokLoc));
-  }
-
-  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
-    // overload resolution if the left-hand side is a class or
-    // enumeration type (C++ [expr.ass]p3).
-    if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
-        !(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {
-      return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
+    OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
+    if (OverOp != OO_None) {
+      LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+                                   Functions);
+      Expr *Args[2] = { lhs, rhs };
+      DeclarationName OpName 
+        = Context.DeclarationNames.getCXXOperatorName(OverOp);
+      ArgumentDependentLookup(OpName, Args, 2, Functions);
     }
 
-    // Determine which overloaded operator we're dealing with.
-
-    // Add the appropriate overloaded operators (C++ [over.match.oper])
-    // to the candidate set.
-    OverloadCandidateSet CandidateSet;
-    OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
-    Expr *Args[2] = { lhs, rhs };
-    if (AddOperatorCandidates(OverOp, S, TokLoc, Args, 2, CandidateSet))
-      return ExprError();
-
-    // 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(lhs, Method) ||
-              PerformCopyInitialization(rhs, FnDecl->getParamDecl(0)->getType(),
-                                        "passing"))
-            return ExprError();
-        } else {
-          // Convert the arguments.
-          if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
-                                        "passing") ||
-              PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
-                                        "passing"))
-            return ExprError();
-        }
-
-        // Determine the result type
-        QualType ResultTy
-          = FnDecl->getType()->getAsFunctionType()->getResultType();
-        ResultTy = ResultTy.getNonReferenceType();
-
-        // Build the actual expression node.
-        Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
-                                                 SourceLocation());
-        UsualUnaryConversions(FnExpr);
-
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
-                                                       ResultTy, TokLoc));
-      } 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 (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
-                                      Best->Conversions[0], "passing") ||
-            PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
-                                      Best->Conversions[1], "passing"))
-          return ExprError();
-
-        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(TokLoc,  diag::err_ovl_ambiguous_oper)
-          << BinaryOperator::getOpcodeStr(Opc)
-          << lhs->getSourceRange() << rhs->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
-      return ExprError();
-
-    case OR_Deleted:
-      Diag(TokLoc, diag::err_ovl_deleted_oper)
-        << Best->Function->isDeleted()
-        << BinaryOperator::getOpcodeStr(Opc)
-        << lhs->getSourceRange() << rhs->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
-      return ExprError();
-    }
-
-    // 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.
+    // Build the (potentially-overloaded, potentially-dependent)
+    // binary operation.
+    return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
   }
 
   // Build a built-in binary operation.
@@ -4178,9 +4040,8 @@
     // Add the appropriate overloaded operators (C++ [over.match.oper])
     // to the candidate set.
     OverloadCandidateSet CandidateSet;
-    if (OverOp != OO_None &&
-        AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
-      return ExprError();
+    if (OverOp != OO_None)
+      AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet);
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -4216,8 +4077,9 @@
         UsualUnaryConversions(FnExpr);
 
         input.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, &Input,
-                                                       1, ResultTy, OpLoc));
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
+                                                       &Input, 1, ResultTy, 
+                                                       OpLoc));
       } else {
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in