From: Matt Beaumont-Gay Date: Thu, 17 Feb 2011 02:54:17 +0000 (+0000) Subject: Fix PR9025 and add a diagnostic (and sometimes a fixit) for an overloaded X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=26ae5dd9cfc561527eca418571323d90589a4b92;p=clang 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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 644b509e40..eb8bf590c3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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'">, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 760d5d58bc..0a95607975 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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()) { if ((Fun = Ptr->getPointeeType()->getAs())) { @@ -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(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(*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(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(); diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp index 953ee48aa9..a4a39d7801 100644 --- a/test/SemaCXX/member-expr.cpp +++ b/test/SemaCXX/member-expr.cpp @@ -115,3 +115,18 @@ namespace rdar8231724 { y->N::X1; // 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?}} + } +}