[cfe-commits] r59663 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/overloaded-operator.cpp www/cxx_status.html
Douglas Gregor
doug.gregor at gmail.com
Wed Nov 19 13:05:35 PST 2008
Author: dgregor
Date: Wed Nov 19 15:05:33 2008
New Revision: 59663
URL: http://llvm.org/viewvc/llvm-project?rev=59663&view=rev
Log:
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? :)
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/overloaded-operator.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Nov 19 15:05:33 2008
@@ -890,6 +890,12 @@
"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")
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 19 15:05:33 2008
@@ -453,6 +453,11 @@
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);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 19 15:05:33 2008
@@ -1291,8 +1291,8 @@
// 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 @@
}
}
+ if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType())
+ return BuildCallToObjectOfClassType(Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
+
// Promote the function operand.
UsualUnaryConversions(Fn);
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 19 15:05:33 2008
@@ -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 @@
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
Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Wed Nov 19 15:05:33 2008
@@ -121,3 +121,16 @@
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:}}
+}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=59663&r1=59662&r2=59663&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Nov 19 15:05:33 2008
@@ -818,8 +818,8 @@
<tr>
<td> 13.3.1.1.2 [over.call.object]</td>
<td class="complete" align="center">✓</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 @@
<td> 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 @@
<td> 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>
More information about the cfe-commits
mailing list