diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 44 | ||||
-rw-r--r-- | test/FixIt/fixit-errors.c | 10 | ||||
-rw-r--r-- | test/SemaCXX/member-expr.cpp | 3 |
4 files changed, 46 insertions, 16 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 729395a32a..a3cce6c163 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1447,8 +1447,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_member_reference_needs_call : 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'">, InGroup<CharSubscript>, DefaultIgnore; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f5bae072ef..031bbe77ac 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1882,6 +1882,38 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, DefaultFunctionArrayConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); + + // If the user is trying to apply -> or . to a function pointer + // type, it's probably because the forgot parentheses to call that + // function. Suggest the addition of those parentheses, build the + // call, and continue on. + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { + if (const FunctionProtoType *Fun + = Ptr->getPointeeType()->getAs<FunctionProtoType>()) { + QualType ResultTy = Fun->getResultType(); + if (Fun->getNumArgs() == 0 && + ((OpKind == tok::period && ResultTy->isRecordType()) || + (OpKind == tok::arrow && ResultTy->isPointerType() && + ResultTy->getAs<PointerType>()->getPointeeType() + ->isRecordType()))) { + SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); + Diag(Loc, diag::err_member_reference_needs_call) + << QualType(Fun, 0) + << CodeModificationHint::CreateInsertion(Loc, "()"); + + OwningExprResult NewBase + = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc, + MultiExprArg(*this, 0, 0), 0, Loc); + if (NewBase.isInvalid()) + return move(NewBase); + + BaseExpr = NewBase.takeAs<Expr>(); + DefaultFunctionArrayConversion(BaseExpr); + BaseType = BaseExpr->getType(); + } + } + } + // If this is an Objective-C pseudo-builtin and a definition is provided then // use that. if (BaseType->isObjCIdType()) { @@ -2437,18 +2469,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, 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->getAs<PointerType>()->isFunctionType())) { - SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); - Diag(Loc, diag::note_member_reference_needs_call) - << CodeModificationHint::CreateInsertion(Loc, "()"); - } - return ExprError(); } diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c index 9c5258dbcb..996e940f2c 100644 --- a/test/FixIt/fixit-errors.c +++ b/test/FixIt/fixit-errors.c @@ -8,3 +8,13 @@ struct s; // expected-note{{previous use is here}} union s *s1; // expected-error{{use of 's' with tag type that does not match previous declaration}} + +struct Point { + float x, y, z; +}; + +struct Point *get_origin(); + +void test_point() { + (void)get_origin->x; +} diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp index 069f52605b..cd13bcc367 100644 --- a/test/SemaCXX/member-expr.cpp +++ b/test/SemaCXX/member-expr.cpp @@ -28,8 +28,7 @@ struct B { A *f0(); }; int f0(B *b) { - return b->f0->f0; // expected-error{{member reference base type 'struct A *()' is not a structure or union}} \ - // expected-note{{perhaps you meant to call this function}} + return b->f0->f0; // expected-error{{perhaps you meant to call this function}} } int i; |