Support for calling overloaded function call operators (operator())

with function call syntax, e.g.,

  Functor f;
  f(x, y);

This is the easy part of handling calls to objects of class type 
(C++ [over.call.object]). The hard part (coping with conversions from
f to function pointer or reference types) will come later. Nobody uses
that stuff anyway, right? :)

llvm-svn: 59663
This commit is contained in:
Douglas Gregor 2008-11-19 21:05:33 +00:00
parent 4fb443f81b
commit 91cea0ad1e
6 changed files with 183 additions and 5 deletions

View File

@ -890,6 +890,12 @@ DIAG(err_ovl_ambiguous_init, ERROR,
"call to constructor of '%0' is ambiguous; candidates are:")
DIAG(err_ovl_ambiguous_oper, ERROR,
"use of overloaded operator '%0' is ambiguous; candidates are:")
DIAG(err_ovl_no_viable_object_call, ERROR,
"no matching function for call to object of type '%0'")
DIAG(err_ovl_no_viable_object_call_with_cands, ERROR,
"no matching function for call to object of type '%0'; candidates are:")
DIAG(err_ovl_ambiguous_object_call, ERROR,
"call to object of type '%0' is ambiguous; candidates are:")
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name '%0': expected expression")

View File

@ -453,6 +453,11 @@ public:
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
ExprResult
BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
/// Helpers for dealing with function parameters
bool CheckParmsForFunctionDef(FunctionDecl *FD);

View File

@ -1291,8 +1291,8 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
// resolution to pick the function.
if (Ovl) {
OverloadCandidateSet CandidateSet;
OverloadCandidateSet::iterator Best;
AddOverloadCandidates(Ovl, Args, NumArgs, CandidateSet);
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Best)) {
case OR_Success:
{
@ -1327,6 +1327,10 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
}
}
if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType())
return BuildCallToObjectOfClassType(Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
// Promote the function operand.
UsualUnaryConversions(Fn);

View File

@ -17,6 +17,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Compiler.h"
@ -2853,6 +2854,155 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
}
/// BuildCallToObjectOfClassType - Build a call to an object of class
/// type (C++ [over.call.object]), which can end up invoking an
/// overloaded function call operator (@c operator()) or performing a
/// user-defined conversion on the object argument.
Action::ExprResult
Sema::BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(Object->getType()->isRecordType() && "Requires object type argument");
const RecordType *Record = Object->getType()->getAsRecordType();
// C++ [over.call.object]p1:
// If the primary-expression E in the function call syntax
// evaluates to a class object of type “cv T”, then the set of
// candidate functions includes at least the function call
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
OverloadCandidateSet CandidateSet;
IdentifierResolver::iterator I
= IdResolver.begin(Context.DeclarationNames.getCXXOperatorName(OO_Call),
cast<CXXRecordType>(Record)->getDecl(),
/*LookInParentCtx=*/false);
NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I;
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps))
AddMethodCandidate(Method, Object, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
else if (OverloadedFunctionDecl *Ovl
= dyn_cast_or_null<OverloadedFunctionDecl>(MemberOps)) {
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*F))
AddMethodCandidate(Method, Object, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
}
}
CXXMethodDecl *Method = 0;
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Best)) {
case OR_Success:
// We found a method. We'll build a call to it below.
Method = cast<CXXMethodDecl>(Best->Function);
break;
case OR_No_Viable_Function:
if (CandidateSet.empty())
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_no_viable_object_call)
<< Object->getType().getAsString() << Object->getSourceRange();
else {
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_no_viable_object_call_with_cands)
<< Object->getType().getAsString() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
}
break;
case OR_Ambiguous:
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_object_call)
<< Object->getType().getAsString() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
}
if (!Method) {
// We had an error; delete all of the subexpressions and return
// the error.
delete Object;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
delete Args[ArgIdx];
return true;
}
// Build a CXXOperatorCallExpr that calls this method, using Object for
// the implicit object parameter and passing along the remaining
// arguments.
const FunctionTypeProto *Proto = Method->getType()->getAsFunctionTypeProto();
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
// Build the full argument list for the method call (the
// implicit object parameter is placed at the beginning of the
// list).
Expr **MethodArgs;
if (NumArgs < NumArgsInProto) {
NumArgsToCheck = NumArgsInProto;
MethodArgs = new Expr*[NumArgsInProto + 1];
} else {
MethodArgs = new Expr*[NumArgs + 1];
}
MethodArgs[0] = Object;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
Expr *NewFn = new DeclRefExpr(Method, Method->getType(),
SourceLocation());
UsualUnaryConversions(NewFn);
// Once we've built TheCall, all of the expressions are properly
// owned.
QualType ResultTy = Method->getResultType().getNonReferenceType();
llvm::OwningPtr<CXXOperatorCallExpr>
TheCall(new CXXOperatorCallExpr(NewFn, MethodArgs, NumArgs + 1,
ResultTy, RParenLoc));
delete [] MethodArgs;
// Initialize the implicit object parameter.
if (!PerformObjectArgumentInitialization(Object, Method))
return true;
TheCall->setArg(0, Object);
// Check the argument types.
for (unsigned i = 0; i != NumArgsToCheck; i++) {
QualType ProtoArgType = Proto->getArgType(i);
Expr *Arg;
if (i < NumArgs)
Arg = Args[i];
else
Arg = new CXXDefaultArgExpr(Method->getParamDecl(i));
QualType ArgType = Arg->getType();
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
TheCall->setArg(i + 1, Arg);
}
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
// Promote the arguments (C99 6.5.2.2p7).
for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
Expr *Arg = Args[i];
DefaultArgumentPromotion(Arg);
TheCall->setArg(i + 1, Arg);
}
}
return CheckFunctionCall(Method, TheCall.take());
}
/// FixOverloadedFunctionReference - E is an expression that refers to
/// a C++ overloaded function (possibly with some parentheses and
/// perhaps a '&' around it). We have resolved the overloaded function

View File

@ -121,3 +121,16 @@ void test_comma(X x, Y y) {
bool& b1 = (x, y);
X& xr = (x, x);
}
struct Callable {
int& operator()(int, double = 2.71828); // expected-note{{candidate function}}
float& operator()(int, double, long, ...); // expected-note{{candidate function}}
};
void test_callable(Callable c) {
int &ir = c(1);
float &fr = c(1, 3.14159, 17, 42);
c(); // expected-error{{no matching function for call to object of type 'struct Callable'; candidates are:}}
}

View File

@ -818,8 +818,8 @@ welcome!</p>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1.2 [over.call.object]</td>
<td class="complete" align="center">&#x2713;</td>
<td class="broken" align="center"></td>
<td class="broken" align="center"></td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
@ -973,7 +973,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td>
<td class="na" align="center">N/A</td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="advanced" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
@ -989,7 +989,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td>
<td class="na" align="center">N/A</td>
<td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>