r184612 - Provide suggested no-arg calls for overloaded member functions missing calls

David Blaikie dblaikie at gmail.com
Fri Jun 21 16:54:45 PDT 2013


Author: dblaikie
Date: Fri Jun 21 18:54:45 2013
New Revision: 184612

URL: http://llvm.org/viewvc/llvm-project?rev=184612&view=rev
Log:
Provide suggested no-arg calls for overloaded member functions missing calls

Reviewed by Richard Smith.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/SemaCXX/addr-of-overloaded-function.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=184612&r1=184611&r2=184612&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 21 18:54:45 2013
@@ -3083,8 +3083,8 @@ public:
                             bool (*IsPlausibleResult)(QualType) = 0);
 
   /// \brief Figure out if an expression could be turned into a call.
-  bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
-                      UnresolvedSetImpl &NonTemplateOverloads);
+  bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
+                     UnresolvedSetImpl &NonTemplateOverloads);
 
   /// \brief Conditionally issue a diagnostic based on the current
   /// evaluation context.

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=184612&r1=184611&r2=184612&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Jun 21 18:54:45 2013
@@ -1136,12 +1136,13 @@ void PrettyDeclStackTraceEntry::print(ra
 ///  call; otherwise, it is set to an empty QualType.
 /// \param OverloadSet - If the expression is an overloaded function
 ///  name, this parameter is populated with the decls of the various overloads.
-bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
-                          UnresolvedSetImpl &OverloadSet) {
+bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
+                         UnresolvedSetImpl &OverloadSet) {
   ZeroArgCallReturnTy = QualType();
   OverloadSet.clear();
 
   const OverloadExpr *Overloads = NULL;
+  bool IsMemExpr = false;
   if (E.getType() == Context.OverloadTy) {
     OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E));
 
@@ -1152,15 +1153,20 @@ bool Sema::isExprCallable(const Expr &E,
     Overloads = FR.Expression;
   } else if (E.getType() == Context.BoundMemberTy) {
     Overloads = dyn_cast<UnresolvedMemberExpr>(E.IgnoreParens());
+    IsMemExpr = true;
   }
+
+  bool Ambiguous = false;
+
   if (Overloads) {
-    bool Ambiguous = false;
     for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
          DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
       OverloadSet.addDecl(*it);
 
-      // Check whether the function is a non-template which takes no
+      // Check whether the function is a non-template, non-member which takes no
       // arguments.
+      if (IsMemExpr)
+        continue;
       if (const FunctionDecl *OverloadDecl
             = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) {
         if (OverloadDecl->getMinRequiredArguments() == 0) {
@@ -1173,7 +1179,25 @@ bool Sema::isExprCallable(const Expr &E,
       }
     }
 
-    return !Ambiguous;
+    // If it's not a member, use better machinery to try to resolve the call
+    if (!IsMemExpr)
+      return !ZeroArgCallReturnTy.isNull();
+  }
+
+  // Attempt to call the member with no arguments - this will correctly handle
+  // member templates with defaults/deduction of template arguments, overloads
+  // with default arguments, etc.
+  if (IsMemExpr) {
+    bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
+    getDiagnostics().setSuppressAllDiagnostics(true);
+    ExprResult R = BuildCallToMemberFunction(NULL, &E, SourceLocation(), None,
+                                             SourceLocation());
+    getDiagnostics().setSuppressAllDiagnostics(Suppress);
+    if (R.isUsable()) {
+      ZeroArgCallReturnTy = R.get()->getType();
+      return true;
+    }
+    return false;
   }
 
   if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) {
@@ -1193,14 +1217,6 @@ bool Sema::isExprCallable(const Expr &E,
     FunTy = PointeeTy->getAs<FunctionType>();
   if (!FunTy)
     FunTy = ExprTy->getAs<FunctionType>();
-  if (!FunTy && ExprTy == Context.BoundMemberTy) {
-    // Look for the bound-member type.  If it's still overloaded, give up,
-    // although we probably should have fallen into the OverloadExpr case above
-    // if we actually have an overloaded bound member.
-    QualType BoundMemberTy = Expr::findBoundMemberType(&E);
-    if (!BoundMemberTy.isNull())
-      FunTy = BoundMemberTy->castAs<FunctionType>();
-  }
 
   if (const FunctionProtoType *FPT =
       dyn_cast_or_null<FunctionProtoType>(FunTy)) {
@@ -1213,7 +1229,7 @@ bool Sema::isExprCallable(const Expr &E,
 
 /// \brief Give notes for a set of overloads.
 ///
-/// A companion to isExprCallable. In cases when the name that the programmer
+/// A companion to tryExprAsCall. In cases when the name that the programmer
 /// wrote was an overloaded function, we may be able to make some guesses about
 /// plausible overloads based on their return types; such guesses can be handed
 /// off to this method to be emitted as notes.
@@ -1283,7 +1299,7 @@ bool Sema::tryToRecoverWithCall(ExprResu
 
   QualType ZeroArgCallTy;
   UnresolvedSet<4> Overloads;
-  if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) &&
+  if (tryExprAsCall(*E.get(), ZeroArgCallTy, Overloads) &&
       !ZeroArgCallTy.isNull() &&
       (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) {
     // At this point, we know E is potentially callable with 0

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=184612&r1=184611&r2=184612&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Jun 21 18:54:45 2013
@@ -4871,7 +4871,7 @@ void CheckImplicitConversion(Sema &S, Ex
             << FixItHint::CreateInsertion(E->getExprLoc(), "&");
           QualType ReturnType;
           UnresolvedSet<4> NonTemplateOverloads;
-          S.isExprCallable(*E, ReturnType, NonTemplateOverloads);
+          S.tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
           if (!ReturnType.isNull() 
               && ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
             S.Diag(E->getExprLoc(), diag::note_function_to_bool_call)

Modified: cfe/trunk/test/SemaCXX/addr-of-overloaded-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/addr-of-overloaded-function.cpp?rev=184612&r1=184611&r2=184612&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/addr-of-overloaded-function.cpp (original)
+++ cfe/trunk/test/SemaCXX/addr-of-overloaded-function.cpp Fri Jun 21 18:54:45 2013
@@ -57,7 +57,7 @@ struct B
 
 struct C {
   C &getC() {
-    return makeAC; // expected-error-re{{reference to non-static member function must be called$}}
+    return makeAC; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
   }
 
   // FIXME: filter by const so we can unambiguously suggest '()' & point to just the one candidate, probably
@@ -70,6 +70,32 @@ struct C {
   void g() {
     int (&fp)() = f; // expected-error{{address of overloaded function 'f' does not match required type 'int ()'}}
   }
+
+  template<typename T>
+  void q1(int); // expected-note{{possible target for call}}
+  template<typename T>
+  void q2(T t = T()); // expected-note{{possible target for call}}
+  template<typename T>
+  void q3(); // expected-note{{possible target for call}}
+  template<typename T1, typename T2>
+  void q4(); // expected-note{{possible target for call}}
+  template<typename T1 = int> // expected-warning{{default template arguments for a function template are a C++11 extension}}
+  void q5(); // expected-note{{possible target for call}}
+
+  void h() {
+    // Do not suggest '()' since an int argument is required
+    q1<int>; // expected-error-re{{reference to non-static member function must be called$}}
+    // Suggest '()' since there's a default value for the only argument & the
+    // type argument is already provided
+    q2<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+    // Suggest '()' since no arguments are required & the type argument is
+    // already provided
+    q3<int>; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+    // Do not suggest '()' since another type argument is required
+    q4<int>; // expected-error-re{{reference to non-static member function must be called$}}
+    // Suggest '()' since the type parameter has a default value
+    q5; // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  }
 };
 
 // PR6886





More information about the cfe-commits mailing list