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;