Provide suggested no-arg calls for overloaded member functions missing calls
Reviewed by Richard Smith.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184612 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index f0bcc40..df46dde 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3083,8 +3083,8 @@
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.
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 954091d..3ddce77 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -1136,12 +1136,13 @@
/// 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 @@
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 @@
}
}
- 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 @@
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 @@
/// \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 @@
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
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 87fe763..96d8742 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -4871,7 +4871,7 @@
<< 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)
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 95223f0..3d007a9 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -57,7 +57,7 @@
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 @@
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