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/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3f7756e..aea03cc 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -648,9 +648,11 @@
 
 Sema::OwningExprResult 
 TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
-  // FIXME: HACK HACK HACK. This is so utterly and completely wrong
-  // that I don't want to explain it here. I'll just fix it tomorrow
-  // instead.
+  // FIXME: Only handles binary operators at the moment.
+
+  // FIXME: Can we optimize this further if neither the left- nor the
+  // right-hand sides are type-dependent? It depends on whether we
+  // need to perform ADL again
   Sema::OwningExprResult LHS = Visit(E->getArg(0));
   if (LHS.isInvalid())
     return SemaRef.ExprError();
@@ -659,11 +661,56 @@
   if (RHS.isInvalid())
     return SemaRef.ExprError();
 
-  Sema::OwningExprResult Result
-    = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), 
-                                 BinaryOperator::Add,
-                                 (Expr *)LHS.get(),
-                                 (Expr *)RHS.get());
+  Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
+  Expr *Args[2] = { lhs, rhs };
+
+  if (!E->isTypeDependent()) { 
+    // Since our original expression was not type-dependent, we do not
+    // perform lookup again at instantiation time (C++ [temp.dep]p1).
+    // Instead, we just build the new overloaded operator call
+    // expression.
+    LHS.release();
+    RHS.release();
+    return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
+                                                       SemaRef.Context, 
+                                                       E->getOperator(),
+                                                       E->getCallee(), 
+                                                       Args, 2, E->getType(), 
+                                                       E->getOperatorLoc()));
+  }
+
+  BinaryOperator::Opcode Opc = 
+    BinaryOperator::getOverloadedOpcode(E->getOperator());
+  Sema::OwningExprResult Result(SemaRef);
+  if (!lhs->getType()->isOverloadableType() && 
+      !rhs->getType()->isOverloadableType()) {
+    // Neither LHS nor RHS is an overloadable type, so try create a
+    // built-in binary operation.
+    Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, 
+                                        lhs, rhs);
+  } else {
+    // Compute the set of functions that were found at template
+    // definition time.
+    Sema::FunctionSet Functions;
+    DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
+    OverloadedFunctionDecl *Overloads 
+      = cast<OverloadedFunctionDecl>(DRE->getDecl());
+    for (OverloadedFunctionDecl::function_iterator 
+           F = Overloads->function_begin(),
+           FEnd = Overloads->function_end();
+         F != FEnd; ++F)
+      Functions.insert(*F);
+
+    // Add any functions found via argument-dependent lookup.
+    DeclarationName OpName 
+      = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
+    SemaRef.ArgumentDependentLookup(OpName, Args, 2, Functions);
+
+    // Create the overloaded operator.
+    Result = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, 
+                                           Functions, lhs, rhs);
+  }
+
   if (Result.isInvalid())
     return SemaRef.ExprError();