[cfe-commits] r59674 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overloaded-operator.cpp www/cxx_status.html

Douglas Gregor doug.gregor at gmail.com
Wed Nov 19 14:57:39 PST 2008


Author: dgregor
Date: Wed Nov 19 16:57:39 2008
New Revision: 59674

URL: http://llvm.org/viewvc/llvm-project?rev=59674&view=rev
Log:
Implement the rest of C++ [over.call.object], which permits the object
being called to be converted to a reference-to-function,
pointer-to-function, or reference-to-pointer-to-function. This is done
through "surrogate" candidate functions that model the conversions
from the object to the function (reference/pointer) and the
conversions in the arguments.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h
    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=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Nov 19 16:57:39 2008
@@ -896,6 +896,8 @@
      "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_ovl_surrogate_cand, NOTE,
+     "conversion candidate of type '%0'")
 
 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=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 19 16:57:39 2008
@@ -429,6 +429,10 @@
   void AddConversionCandidate(CXXConversionDecl *Conversion,
                               Expr *From, QualType ToType,
                               OverloadCandidateSet& CandidateSet);
+  void AddSurrogateCandidate(CXXConversionDecl *Conversion,
+                             const FunctionTypeProto *Proto,
+                             Expr *Object, Expr **Args, unsigned NumArgs,
+                             OverloadCandidateSet& CandidateSet);
   void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet);

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 19 16:57:39 2008
@@ -1514,6 +1514,7 @@
   CandidateSet.push_back(OverloadCandidate());
   OverloadCandidate& Candidate = CandidateSet.back();
   Candidate.Function = Function;
+  Candidate.IsSurrogate = false;
 
   unsigned NumArgsInProto = Proto->getNumArgs();
 
@@ -1589,6 +1590,7 @@
   CandidateSet.push_back(OverloadCandidate());
   OverloadCandidate& Candidate = CandidateSet.back();
   Candidate.Function = Method;
+  Candidate.IsSurrogate = false;
 
   unsigned NumArgsInProto = Proto->getNumArgs();
 
@@ -1665,6 +1667,7 @@
   CandidateSet.push_back(OverloadCandidate());
   OverloadCandidate& Candidate = CandidateSet.back();
   Candidate.Function = Conversion;
+  Candidate.IsSurrogate = false;
   Candidate.FinalConversion.setAsIdentityConversion();
   Candidate.FinalConversion.FromTypePtr 
     = Conversion->getConversionType().getAsOpaquePtr();
@@ -1713,6 +1716,89 @@
   }
 }
 
+/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
+/// converts the given @c Object to a function pointer via the
+/// conversion function @c Conversion, and then attempts to call it
+/// with the given arguments (C++ [over.call.object]p2-4). Proto is
+/// the type of function that we'll eventually be calling.
+void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
+                                 const FunctionTypeProto *Proto,
+                                 Expr *Object, Expr **Args, unsigned NumArgs,
+                                 OverloadCandidateSet& CandidateSet) {
+  CandidateSet.push_back(OverloadCandidate());
+  OverloadCandidate& Candidate = CandidateSet.back();
+  Candidate.Function = 0;
+  Candidate.Surrogate = Conversion;
+  Candidate.Viable = true;
+  Candidate.IsSurrogate = true;
+  Candidate.Conversions.resize(NumArgs + 1);
+
+  // Determine the implicit conversion sequence for the implicit
+  // object parameter.
+  ImplicitConversionSequence ObjectInit 
+    = TryObjectArgumentInitialization(Object, Conversion);
+  if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
+    Candidate.Viable = false;
+    return;
+  }
+
+  // The first conversion is actually a user-defined conversion whose
+  // first conversion is ObjectInit's standard conversion (which is
+  // effectively a reference binding). Record it as such.
+  Candidate.Conversions[0].ConversionKind 
+    = ImplicitConversionSequence::UserDefinedConversion;
+  Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
+  Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
+  Candidate.Conversions[0].UserDefined.After 
+    = Candidate.Conversions[0].UserDefined.Before;
+  Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
+
+  // Find the 
+  unsigned NumArgsInProto = Proto->getNumArgs();
+
+  // (C++ 13.3.2p2): A candidate function having fewer than m
+  // parameters is viable only if it has an ellipsis in its parameter
+  // list (8.3.5).
+  if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+    Candidate.Viable = false;
+    return;
+  }
+
+  // Function types don't have any default arguments, so just check if
+  // we have enough arguments.
+  if (NumArgs < NumArgsInProto) {
+    // Not enough arguments.
+    Candidate.Viable = false;
+    return;
+  }
+
+  // Determine the implicit conversion sequences for each of the
+  // arguments.
+  for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+    if (ArgIdx < NumArgsInProto) {
+      // (C++ 13.3.2p3): for F to be a viable function, there shall
+      // exist for each argument an implicit conversion sequence
+      // (13.3.3.1) that converts that argument to the corresponding
+      // parameter of F.
+      QualType ParamType = Proto->getArgType(ArgIdx);
+      Candidate.Conversions[ArgIdx + 1] 
+        = TryCopyInitialization(Args[ArgIdx], ParamType, 
+                                /*SuppressUserConversions=*/false);
+      if (Candidate.Conversions[ArgIdx + 1].ConversionKind 
+            == ImplicitConversionSequence::BadConversion) {
+        Candidate.Viable = false;
+        break;
+      }
+    } else {
+      // (C++ 13.3.2p2): For the purposes of overload resolution, any
+      // argument for which there is no corresponding parameter is
+      // considered to ""match the ellipsis" (C+ 13.3.3.1.3).
+      Candidate.Conversions[ArgIdx + 1].ConversionKind 
+        = ImplicitConversionSequence::EllipsisConversion;
+    }
+  }
+}
+
 /// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
 /// an acceptable non-member overloaded operator for a call whose
 /// arguments have types T1 (and, if non-empty, T2). This routine
@@ -2742,8 +2828,10 @@
        Cand != CandidateSet.end(); ++Cand) {
     if (Cand->Viable && 
         Cand != Best &&
-        !isBetterOverloadCandidate(*Best, *Cand))
+        !isBetterOverloadCandidate(*Best, *Cand)) {
+      Best = CandidateSet.end();
       return OR_Ambiguous;
+    }
   }
   
   // Best is the best viable function.
@@ -2764,6 +2852,10 @@
       if (Cand->Function) {
         // Normal function
         Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+      } else if (Cand->IsSurrogate) {
+        Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
+          << Context.getCanonicalType(Cand->Surrogate->getConversionType())
+               .getAsString();
       } else {
         // FIXME: We need to get the identifier in here
         // FIXME: Do we want the error message to point at the 
@@ -2893,14 +2985,48 @@
     }
   }
 
-  CXXMethodDecl *Method = 0;
+  // C++ [over.call.object]p2:
+  //   In addition, for each conversion function declared in T of the
+  //   form
+  //
+  //        operator conversion-type-id () cv-qualifier;
+  //
+  //   where cv-qualifier is the same cv-qualification as, or a
+  //   greater cv-qualification than, cv, and where conversion-type-id
+  //   denotes the type “pointer to function of (P1,...,Pn) returning
+  //   R”, or the type “reference to pointer to function of
+  //   (P1,...,Pn) returning R”, or the type “reference to function
+  //   of (P1,...,Pn) returning R”, a surrogate call function [...]
+  //   is also considered as a candidate function. Similarly,
+  //   surrogate call functions are added to the set of candidate
+  //   functions for each conversion function declared in an
+  //   accessible base class provided the function is not hidden
+  //   within T by another intervening declaration.
+  //
+  // FIXME: Look in base classes for more conversion operators!
+  OverloadedFunctionDecl *Conversions 
+    = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+  for (OverloadedFunctionDecl::function_iterator Func 
+         = Conversions->function_begin();
+       Func != Conversions->function_end(); ++Func) {
+    CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+    // Strip the reference type (if any) and then the pointer type (if
+    // any) to get down to what might be a function type.
+    QualType ConvType = Conv->getConversionType().getNonReferenceType();
+    if (const PointerType *ConvPtrType = ConvType->getAsPointerType())
+      ConvType = ConvPtrType->getPointeeType();
+
+    if (const FunctionTypeProto *Proto = ConvType->getAsFunctionTypeProto())
+      AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+  }
 
   // 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);
+    // Overload resolution succeeded; we'll build the appropriate call
+    // below.
     break;
 
   case OR_No_Viable_Function:
@@ -2924,7 +3050,7 @@
     break;
   }    
 
-  if (!Method) {
+  if (Best == CandidateSet.end()) {
     // We had an error; delete all of the subexpressions and return
     // the error.
     delete Object;
@@ -2933,9 +3059,28 @@
     return true;
   }
 
-  // Build a CXXOperatorCallExpr that calls this method, using Object for
-  // the implicit object parameter and passing along the remaining
-  // arguments.
+  if (Best->Function == 0) {
+    // Since there is no function declaration, this is one of the
+    // surrogate candidates. Dig out the conversion function.
+    CXXConversionDecl *Conv 
+      = cast<CXXConversionDecl>(
+                         Best->Conversions[0].UserDefined.ConversionFunction);
+
+    // We selected one of the surrogate functions that converts the
+    // object parameter to a function pointer. Perform the conversion
+    // on the object argument, then let ActOnCallExpr finish the job.
+    // FIXME: Represent the user-defined conversion in the AST!
+    ImpCastExprToType(Object, 
+                      Conv->getConversionType().getNonReferenceType(),
+                      Conv->getConversionType()->isReferenceType());
+    return ActOnCallExpr((ExprTy*)Object, LParenLoc, (ExprTy**)Args, NumArgs,
+                         CommaLocs, RParenLoc);
+  }
+
+  // We found an overloaded operator(). Build a CXXOperatorCallExpr
+  // that calls this method, using Object for the implicit object
+  // parameter and passing along the remaining arguments.
+  CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
   const FunctionTypeProto *Proto = Method->getType()->getAsFunctionTypeProto();
 
   unsigned NumArgsInProto = Proto->getNumArgs();

Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Wed Nov 19 16:57:39 2008
@@ -199,15 +199,21 @@
   /// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
   struct OverloadCandidate {
     /// Function - The actual function that this candidate
-    /// represents. When NULL, this is a built-in candidate.
+    /// represents. When NULL, this is a built-in candidate 
+    /// (C++ [over.oper]) or a surrogate for a conversion to a 
+    /// function pointer or reference (C++ [over.call.object]).
     FunctionDecl *Function;
-    
+
     // BuiltinTypes - Provides the return and parameter types of a
     // built-in overload candidate. Only valid when Function is NULL.
     struct {
       QualType ResultTy;
       QualType ParamTypes[3];
     } BuiltinTypes;
+    
+    /// Surrogate - The conversion function for which this candidate
+    /// is a surrogate, but only if IsSurrogate is true.
+    CXXConversionDecl *Surrogate;
 
     /// Conversions - The conversion sequences used to convert the
     /// function arguments to the function parameters.
@@ -216,6 +222,11 @@
     /// Viable - True to indicate that this overload candidate is viable.
     bool Viable;
 
+    /// IsSurrogate - True to indicate that this candidate is a
+    /// surrogate for a conversion to a function pointer or reference
+    /// (C++ [over.call.object]).
+    bool IsSurrogate;
+
     /// FinalConversion - For a conversion function (where Function is
     /// a CXXConversionDecl), the standard conversion that occurs
     /// after the call to the overload candidate to convert the result

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Wed Nov 19 16:57:39 2008
@@ -134,3 +134,17 @@
 
   c(); // expected-error{{no matching function for call to object of type 'struct Callable'; candidates are:}}
 }
+
+typedef int& Func1(float, double);
+typedef float& Func2(int, double);
+
+struct ConvertToFunc {
+  operator Func1*(); // expected-note{{conversion candidate of type 'int &(*)(float, double)'}}
+  operator Func2&(); // expected-note{{conversion candidate of type 'float &(&)(int, double)'}}
+};
+
+void test_funcptr_call(ConvertToFunc ctf) {
+  int &i1 = ctf(1.0f, 2.0);
+  float &f2 = ctf((short int)1, 1.0f);
+  ctf((long int)17, 2.0); // expected-error{{error: call to object of type 'struct ConvertToFunc' is ambiguous; candidates are:}}
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=59674&r1=59673&r2=59674&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Nov 19 16:57:39 2008
@@ -818,10 +818,10 @@
 <tr>
   <td>        13.3.1.1.2 [over.call.object]</td>
   <td class="complete" align="center">&#x2713;</td>  
+  <td class="medium" align="center"></td>
   <td class="advanced" align="center"></td>
-  <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
-  <td></td>
+  <td>Missing AST representation for the implicit conversion to a function reference/pointer</td>
 </tr>
 <tr>
   <td>      13.3.1.2 [over.match.oper]</td>





More information about the cfe-commits mailing list