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

Reviewed by Richard Smith.

llvm-svn: 184612
This commit is contained in:
David Blaikie 2013-06-21 23:54:45 +00:00
parent 4c280bd3de
commit e5323aa921
4 changed files with 61 additions and 19 deletions

View File

@ -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.

View File

@ -1136,12 +1136,13 @@ void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
/// 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, QualType &ZeroArgCallReturnTy,
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, QualType &ZeroArgCallReturnTy,
}
}
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, QualType &ZeroArgCallReturnTy,
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, QualType &ZeroArgCallReturnTy,
/// \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(ExprResult &E, const PartialDiagnostic &PD,
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

View File

@ -4871,7 +4871,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
<< 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)

View File

@ -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