Skip to content

Commit 3c27391

Browse files
author
Matt Beaumont-Gay
committed
Implement Sema::isExprCallable.
We can use this to produce nice diagnostics (and try to fixit-and-recover) in various cases where we might see "MyFunction" instead of "MyFunction()". The changes in SemaExpr are an example of how to use isExprCallable. llvm-svn: 130878
1 parent 0fe4608 commit 3c27391

File tree

4 files changed

+156
-111
lines changed

4 files changed

+156
-111
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,14 @@ class Sema {
20742074
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
20752075
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
20762076
void MarkDeclarationsReferencedInExpr(Expr *E);
2077-
2077+
2078+
/// \brief Figure out if an expression could be turned into a call.
2079+
bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
2080+
UnresolvedSetImpl &NonTemplateOverloads);
2081+
/// \brief Give notes for a set of overloads.
2082+
void NoteOverloads(const UnresolvedSetImpl &Overloads,
2083+
const SourceLocation FinalNoteLoc);
2084+
20782085
/// \brief Conditionally issue a diagnostic based on the current
20792086
/// evaluation context.
20802087
///

clang/lib/Sema/Sema.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "clang/AST/DeclCXX.h"
3232
#include "clang/AST/DeclObjC.h"
3333
#include "clang/AST/Expr.h"
34+
#include "clang/AST/ExprCXX.h"
3435
#include "clang/AST/StmtCXX.h"
3536
#include "clang/Lex/Preprocessor.h"
3637
#include "clang/Basic/PartialDiagnostic.h"
@@ -766,3 +767,102 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
766767

767768
OS << '\n';
768769
}
770+
771+
/// \brief Figure out if an expression could be turned into a call.
772+
///
773+
/// Use this when trying to recover from an error where the programmer may have
774+
/// written just the name of a function instead of actually calling it.
775+
///
776+
/// \param E - The expression to examine.
777+
/// \param ZeroArgCallReturnTy - If the expression can be turned into a call
778+
/// with no arguments, this parameter is set to the type returned by such a
779+
/// call; otherwise, it is set to an empty QualType.
780+
/// \param NonTemplateOverloads - If the expression is an overloaded function
781+
/// name, this parameter is populated with the decls of the various overloads.
782+
bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
783+
UnresolvedSetImpl &NonTemplateOverloads) {
784+
ZeroArgCallReturnTy = QualType();
785+
NonTemplateOverloads.clear();
786+
if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) {
787+
for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
788+
DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
789+
// Our overload set may include TemplateDecls, which we'll ignore for our
790+
// present purpose.
791+
if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
792+
NonTemplateOverloads.addDecl(*it);
793+
if (OverloadDecl->getMinRequiredArguments() == 0)
794+
ZeroArgCallReturnTy = OverloadDecl->getResultType();
795+
}
796+
}
797+
return true;
798+
}
799+
800+
if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) {
801+
if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
802+
if (Fun->getMinRequiredArguments() == 0)
803+
ZeroArgCallReturnTy = Fun->getResultType();
804+
return true;
805+
}
806+
}
807+
808+
// We don't have an expression that's convenient to get a FunctionDecl from,
809+
// but we can at least check if the type is "function of 0 arguments".
810+
QualType ExprTy = E.getType();
811+
const FunctionType *FunTy = NULL;
812+
if (const PointerType *Ptr = ExprTy->getAs<PointerType>())
813+
FunTy = Ptr->getPointeeType()->getAs<FunctionType>();
814+
else if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
815+
FunTy = Ref->getPointeeType()->getAs<FunctionType>();
816+
if (!FunTy)
817+
FunTy = ExprTy->getAs<FunctionType>();
818+
if (!FunTy && ExprTy == Context.BoundMemberTy) {
819+
// Look for the bound-member type. If it's still overloaded, give up,
820+
// although we probably should have fallen into the OverloadExpr case above
821+
// if we actually have an overloaded bound member.
822+
QualType BoundMemberTy = Expr::findBoundMemberType(&E);
823+
if (!BoundMemberTy.isNull())
824+
FunTy = BoundMemberTy->castAs<FunctionType>();
825+
}
826+
827+
if (const FunctionProtoType *FPT =
828+
dyn_cast_or_null<FunctionProtoType>(FunTy)) {
829+
if (FPT->getNumArgs() == 0)
830+
ZeroArgCallReturnTy = FunTy->getResultType();
831+
return true;
832+
}
833+
return false;
834+
}
835+
836+
/// \brief Give notes for a set of overloads.
837+
///
838+
/// A companion to isExprCallable. In cases when the name that the programmer
839+
/// wrote was an overloaded function, we may be able to make some guesses about
840+
/// plausible overloads based on their return types; such guesses can be handed
841+
/// off to this method to be emitted as notes.
842+
///
843+
/// \param Overloads - The overloads to note.
844+
/// \param FinalNoteLoc - If we've suppressed printing some overloads due to
845+
/// -fshow-overloads=best, this is the location to attach to the note about too
846+
/// many candidates. Typically this will be the location of the original
847+
/// ill-formed expression.
848+
void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads,
849+
const SourceLocation FinalNoteLoc) {
850+
int ShownOverloads = 0;
851+
int SuppressedOverloads = 0;
852+
for (UnresolvedSetImpl::iterator It = Overloads.begin(),
853+
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
854+
// FIXME: Magic number for max shown overloads stolen from
855+
// OverloadCandidateSet::NoteCandidates.
856+
if (ShownOverloads >= 4 &&
857+
Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
858+
++SuppressedOverloads;
859+
continue;
860+
}
861+
Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(),
862+
diag::note_member_ref_possible_intended_overload);
863+
++ShownOverloads;
864+
}
865+
if (SuppressedOverloads)
866+
Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
867+
<< SuppressedOverloads;
868+
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 39 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4377,120 +4377,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
43774377

43784378
// If the user is trying to apply -> or . to a function name, it's probably
43794379
// because they forgot parentheses to call that function.
4380-
bool TryCall = false;
4381-
bool Overloaded = false;
4382-
UnresolvedSet<8> AllOverloads;
4383-
if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) {
4384-
AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
4385-
TryCall = true;
4386-
Overloaded = true;
4387-
} else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) {
4388-
if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
4389-
AllOverloads.addDecl(Fun);
4390-
TryCall = true;
4391-
}
4392-
}
4393-
4394-
if (TryCall) {
4395-
// Plunder the overload set for something that would make the member
4396-
// expression valid.
4397-
UnresolvedSet<4> ViableOverloads;
4398-
bool HasViableZeroArgOverload = false;
4399-
for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
4400-
DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
4401-
// Our overload set may include TemplateDecls, which we'll ignore for the
4402-
// purposes of determining whether we can issue a '()' fixit.
4403-
if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
4404-
QualType ResultTy = OverloadDecl->getResultType();
4405-
if ((!IsArrow && ResultTy->isRecordType()) ||
4406-
(IsArrow && ResultTy->isPointerType() &&
4407-
ResultTy->getPointeeType()->isRecordType())) {
4408-
ViableOverloads.addDecl(*it);
4409-
if (OverloadDecl->getMinRequiredArguments() == 0) {
4410-
HasViableZeroArgOverload = true;
4411-
}
4412-
}
4413-
}
4414-
}
4415-
4416-
if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
4380+
QualType ZeroArgCallTy;
4381+
UnresolvedSet<4> Overloads;
4382+
if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
4383+
if (ZeroArgCallTy.isNull()) {
44174384
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
4418-
<< (AllOverloads.size() > 1) << 0
4419-
<< BaseExpr.get()->getSourceRange();
4420-
int ViableOverloadCount = ViableOverloads.size();
4421-
int I;
4422-
for (I = 0; I < ViableOverloadCount; ++I) {
4423-
// FIXME: Magic number for max shown overloads stolen from
4424-
// OverloadCandidateSet::NoteCandidates.
4425-
if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
4426-
break;
4427-
}
4428-
Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
4429-
diag::note_member_ref_possible_intended_overload);
4430-
}
4431-
if (I != ViableOverloadCount) {
4432-
Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates)
4433-
<< int(ViableOverloadCount - I);
4385+
<< (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
4386+
UnresolvedSet<2> PlausibleOverloads;
4387+
for (OverloadExpr::decls_iterator It = Overloads.begin(),
4388+
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
4389+
const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
4390+
QualType OverloadResultTy = OverloadDecl->getResultType();
4391+
if ((!IsArrow && OverloadResultTy->isRecordType()) ||
4392+
(IsArrow && OverloadResultTy->isPointerType() &&
4393+
OverloadResultTy->getPointeeType()->isRecordType()))
4394+
PlausibleOverloads.addDecl(It.getDecl());
44344395
}
4396+
NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
44354397
return ExprError();
44364398
}
4437-
} else {
4438-
// We don't have an expression that's convenient to get a Decl from, but we
4439-
// can at least check if the type is "function of 0 arguments which returns
4440-
// an acceptable type".
4441-
const FunctionType *Fun = NULL;
4442-
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
4443-
if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
4444-
TryCall = true;
4445-
}
4446-
} else if ((Fun = BaseType->getAs<FunctionType>())) {
4447-
TryCall = true;
4448-
} else if (BaseType == Context.BoundMemberTy) {
4449-
// Look for the bound-member type. If it's still overloaded,
4450-
// give up, although we probably should have fallen into the
4451-
// OverloadExpr case above if we actually have an overloaded
4452-
// bound member.
4453-
QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
4454-
if (!fnType.isNull()) {
4455-
TryCall = true;
4456-
Fun = fnType->castAs<FunctionType>();
4457-
}
4458-
}
4459-
4460-
if (TryCall) {
4461-
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
4462-
if (FPT->getNumArgs() == 0) {
4463-
QualType ResultTy = Fun->getResultType();
4464-
TryCall = (!IsArrow && ResultTy->isRecordType()) ||
4465-
(IsArrow && ResultTy->isPointerType() &&
4466-
ResultTy->getPointeeType()->isRecordType());
4467-
}
4468-
}
4399+
if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
4400+
(IsArrow && ZeroArgCallTy->isPointerType() &&
4401+
ZeroArgCallTy->getPointeeType()->isRecordType())) {
4402+
// At this point, we know BaseExpr looks like it's potentially callable
4403+
// with 0 arguments, and that it returns something of a reasonable type,
4404+
// so we can emit a fixit and carry on pretending that BaseExpr was
4405+
// actually a CallExpr.
4406+
SourceLocation ParenInsertionLoc =
4407+
PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
4408+
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
4409+
<< (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
4410+
<< FixItHint::CreateInsertion(ParenInsertionLoc, "()");
4411+
// FIXME: Try this before emitting the fixit, and suppress diagnostics
4412+
// while doing so.
4413+
ExprResult NewBase =
4414+
ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
4415+
MultiExprArg(*this, 0, 0),
4416+
ParenInsertionLoc.getFileLocWithOffset(1));
4417+
if (NewBase.isInvalid())
4418+
return ExprError();
4419+
BaseExpr = NewBase;
4420+
BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
4421+
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
4422+
ObjCImpDecl, HasTemplateArgs);
44694423
}
44704424
}
44714425

4472-
if (TryCall) {
4473-
// At this point, we know BaseExpr looks like it's potentially callable with
4474-
// 0 arguments, and that it returns something of a reasonable type, so we
4475-
// can emit a fixit and carry on pretending that BaseExpr was actually a
4476-
// CallExpr.
4477-
SourceLocation ParenInsertionLoc =
4478-
PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
4479-
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
4480-
<< int(Overloaded) << 1
4481-
<< BaseExpr.get()->getSourceRange()
4482-
<< FixItHint::CreateInsertion(ParenInsertionLoc, "()");
4483-
ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
4484-
MultiExprArg(*this, 0, 0),
4485-
ParenInsertionLoc);
4486-
if (NewBase.isInvalid())
4487-
return ExprError();
4488-
BaseExpr = NewBase;
4489-
BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
4490-
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
4491-
ObjCImpDecl, HasTemplateArgs);
4492-
}
4493-
44944426
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
44954427
<< BaseType << BaseExpr.get()->getSourceRange();
44964428

clang/test/SemaCXX/member-expr.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ namespace PR9025 {
124124
return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
125125
}
126126

127-
S fun2(); // expected-note{{possibly valid overload here}}
128-
S fun2(int i); // expected-note{{possibly valid overload here}}
127+
S fun2();
128+
S fun2(int i);
129129
int g2() {
130-
return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
130+
return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
131131
}
132132

133133
S fun3(int i=0);
@@ -140,4 +140,10 @@ namespace PR9025 {
140140
int g4() {
141141
return fun4.x; // expected-error{{base of member reference is a function; perhaps you meant to call it?}}
142142
}
143+
144+
S fun5(int i); // expected-note{{possibly valid overload here}}
145+
S fun5(float f); // expected-note{{possibly valid overload here}}
146+
int g5() {
147+
return fun5.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
148+
}
143149
}

0 commit comments

Comments
 (0)