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>();