]> granicus.if.org Git - clang/commitdiff
Fix PR9025 and add a diagnostic (and sometimes a fixit) for an overloaded
authorMatt Beaumont-Gay <matthewbg@google.com>
Thu, 17 Feb 2011 02:54:17 +0000 (02:54 +0000)
committerMatt Beaumont-Gay <matthewbg@google.com>
Thu, 17 Feb 2011 02:54:17 +0000 (02:54 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/SemaCXX/member-expr.cpp

index 644b509e40eaa30e16abd73a8fddbb56bf0cb591..eb8bf590c3416dbd1fd7ff60d61e221f0da3f800 100644 (file)
@@ -2364,6 +2364,11 @@ def err_typecheck_member_reference_type : Error<
 def err_typecheck_member_reference_unknown : Error<
   "cannot refer to member %0 in %1 with '%select{.|->}2'">;
 def err_member_reference_needs_call : Error<
+  "base of member reference is an overloaded function; perhaps you meant "
+  "to call %select{it|the 0-argument overload}0?">;
+def note_member_ref_possible_intended_overload : Note<
+  "possibly valid overload here">;
+def err_member_reference_needs_call_zero_arg : Error<
   "base of member reference has function type %0; perhaps you meant to call "
   "this function with '()'?">;
 def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
index 760d5d58bc4c378a0e166fb105afc6aadfcdccc0..0a956079750e8fe05d1abc10a58c89a92457551c 100644 (file)
@@ -3995,6 +3995,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
 
   // 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 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
   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 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
 
 
     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>();
index 953ee48aa959a305de60fd8ece201ee8f7915ff6..a4a39d78016304fda82c19ed7373628d36e8ab4a 100644 (file)
@@ -115,3 +115,18 @@ namespace rdar8231724 {
     y->N::X1<int>; // expected-error{{'rdar8231724::N::X1' is not a member of class 'rdar8231724::Y'}}
   }
 }
+
+namespace PR9025 {
+  struct S { int x; };
+  S fun();
+  int fun(int i);
+  int g() {
+    return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call the 0-argument overload?}}
+  }
+
+  S fun2(); // expected-note{{possibly valid overload here}}
+  S fun2(int i); // expected-note{{possibly valid overload here}}
+  int g2() {
+    return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
+  }
+}