From: Douglas Gregor Date: Fri, 27 Mar 2009 06:00:30 +0000 (+0000) Subject: If the user is trying to apply the -> or . member reference operator X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=214f31a347d7824eb92e6a3f5dce4d4047fd5ae0;p=clang If the user is trying to apply the -> or . member reference operator to a function or function pointer, it's probably because the user forgot to put in parentheses () to call the function. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67826 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 62647ff51c..05b8f512e1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -872,6 +872,9 @@ def err_typecheck_member_reference_type : Error< "cannot refer to type member %0 with '%select{.|->}1'">; def err_typecheck_member_reference_unknown : Error< "cannot refer to member %0 with '%select{.|->}1'">; +def note_member_reference_needs_call : Note< + "perhaps you meant to call this function with '()'?">; + def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_typecheck_no_member : Error<"no member named %0">; def err_member_redeclared : Error<"class member cannot be redeclared">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8922abd20b..8b646e9943 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2101,9 +2101,22 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, MemberLoc)); } - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr->getSourceRange()); + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) + << BaseType << BaseExpr->getSourceRange(); + + // If the user is trying to apply -> or . to a function or function + // pointer, it's probably because they forgot parentheses to call + // the function. Suggest the addition of those parentheses. + if (BaseType == Context.OverloadTy || + BaseType->isFunctionType() || + (BaseType->isPointerType() && + BaseType->getAsPointerType()->isFunctionType())) { + SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); + Diag(Loc, diag::note_member_reference_needs_call) + << CodeModificationHint::CreateInsertion(Loc, "()"); + } + + return ExprError(); } /// ConvertArgumentsForCall - Converts the arguments specified in diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp index 58e5be955f..60ee10df7f 100644 --- a/test/SemaCXX/member-expr.cpp +++ b/test/SemaCXX/member-expr.cpp @@ -20,3 +20,14 @@ void test(X* xp, X x) { float f1 = x.g(); float f2 = xp->g(); } + +struct A { + int f0; +}; +struct B { + A *f0(); +}; +int f0(B *b) { + return b->f0->f0; // expected-error{{member reference base type 'struct A *(void)' is not a structure or union}} \ + // expected-note{{perhaps you meant to call this function}} +}