diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 63 | ||||
-rw-r--r-- | clang/test/SemaCXX/member-expr.cpp | 15 |
3 files changed, 77 insertions, 6 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 644b509e40e..eb8bf590c34 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 760d5d58bc4..0a956079750 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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<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>(); diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp index 953ee48aa95..a4a39d78016 100644 --- a/clang/test/SemaCXX/member-expr.cpp +++ b/clang/test/SemaCXX/member-expr.cpp @@ -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?}} + } +} |