Rework the fix-it hint for code like
get_origin->x
where get_origin is actually a function and the user has forgotten the
parentheses. Instead of giving a lame note for the fix-it, give a
full-fledge error, early, then build the call expression to try to
recover.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86238 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 729395a..a3cce6c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1447,8 +1447,9 @@
"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 f5bae07..031bbe7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1882,6 +1882,38 @@
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 @@
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 9c5258d..996e940 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 069f526..cd13bcc 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -28,8 +28,7 @@
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;