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();