[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">&#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 @@
   <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