Fix PR9025 and add a diagnostic (and sometimes a fixit) for an overloaded
function name used as the base of a member expression. Early feedback from
Chandler Carruth, and code review from Nick Lewycky.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125714 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 760d5d5..0a95607 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3995,6 +3995,8 @@
// There's a possible road to recovery for function types.
const FunctionType *Fun = 0;
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr->getLocEnd());
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
@@ -4029,7 +4031,53 @@
if (Fun || BaseType == Context.OverloadTy) {
bool TryCall;
if (BaseType == Context.OverloadTy) {
- TryCall = true;
+ // Plunder the overload set for something that would make the member
+ // expression valid.
+ const OverloadExpr *Overloads = cast<OverloadExpr>(BaseExpr);
+ UnresolvedSet<4> CandidateOverloads;
+ bool HasZeroArgCandidateOverload = false;
+ for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
+ DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
+ QualType ResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType())) {
+ CandidateOverloads.addDecl(*it);
+ if (OverloadDecl->getNumParams() == 0) {
+ HasZeroArgCandidateOverload = true;
+ }
+ }
+ }
+ if (HasZeroArgCandidateOverload && CandidateOverloads.size() == 1) {
+ // We have one reasonable overload, and there's only one way to call it,
+ // so emit a fixit and try to recover
+ Diag(ParenInsertionLoc, diag::err_member_reference_needs_call)
+ << 1
+ << BaseExpr->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ TryCall = true;
+ } else {
+ Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ << 0
+ << BaseExpr->getSourceRange();
+ int CandidateOverloadCount = CandidateOverloads.size();
+ int I;
+ for (I = 0; I < CandidateOverloadCount; ++I) {
+ // FIXME: Magic number for max shown overloads stolen from
+ // OverloadCandidateSet::NoteCandidates.
+ if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ break;
+ }
+ Diag(CandidateOverloads[I].getDecl()->getSourceRange().getBegin(),
+ diag::note_member_ref_possible_intended_overload);
+ }
+ if (I != CandidateOverloadCount) {
+ Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
+ << int(CandidateOverloadCount - I);
+ }
+ return ExprError();
+ }
} else {
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
TryCall = (FPT->getNumArgs() == 0);
@@ -4047,13 +4095,16 @@
if (TryCall) {
- SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
- Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
- << QualType(Fun, 0)
- << FixItHint::CreateInsertion(Loc, "()");
+ if (Fun) {
+ Diag(BaseExpr->getExprLoc(),
+ diag::err_member_reference_needs_call_zero_arg)
+ << QualType(Fun, 0)
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ }
ExprResult NewBase
- = ActOnCallExpr(0, BaseExpr, Loc, MultiExprArg(*this, 0, 0), Loc);
+ = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0), ParenInsertionLoc);
if (NewBase.isInvalid())
return ExprError();
BaseExpr = NewBase.takeAs<Expr>();