Attached is an initial patch for trying to correct a missing "-" or ">" to
"->" when accessing a member through an object pointer. This patch also
doesn't work for C code as C seems to hit a different code path. I'm
sending the patch out for pre-commit review even though it is a small and
fairly unobtrusive (code-wise) patch because I'm a bit iffy on whether it's
a good way to perform the diagnostic.

For a bit of context, what makes this diagnostic tricky is that the
original error about the unknown identifier after the "-" or ">" occurs
well within Sema as the parser is handling the RHS of a binary operator,
but the recovery would require following a code path in the parser that was
part of the construction of the LHS. And since Sema cannot tell the parser
to back up a few steps....

Cheers,
Kaelyn
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index c9eb2ad..c96971d 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -501,6 +501,9 @@ def ext_abstract_pack_declarator_parens : ExtWarn<
 def err_function_is_not_record : Error<
   "unexpected '%select{.|->}0' in function call; perhaps remove the "
   "'%select{.|->}0'?">;
+def err_mistyped_arrow_in_member_access : Error<
+  "use of undeclared identifier %0; did you mean '->' instead of "
+  "'%select{-|>}1'?">;
 
 // C++ derived classes
 def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index e9cb827..8ef055f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -166,6 +166,46 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
   ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
                                        /*isAddressOfOperand=*/false,
                                        isTypeCast);
+
+  // Check for a possible typo of "-" or ">" instead of "->" after a
+  // pointer to a struct or class, while recovery is still possible.
+  if (LHS.isUsable() && (Tok.is(tok::minus) || Tok.is(tok::greater))) {
+    QualType LHSType = LHS.get()->getType();
+    const RecordType *Pointee =
+        LHSType->isPointerType()
+            ? LHSType->getPointeeType()->getAsStructureType()
+            : 0;
+    const RecordDecl *RD = Pointee ? Pointee->getDecl() : 0;
+    const Token &NextTok = NextToken();
+    if (RD && NextTok.is(tok::identifier)) {
+      UnqualifiedId Name;
+      CXXScopeSpec ScopeSpec;
+      SourceLocation TemplateKWLoc;
+      NoTypoCorrectionCCC NoTCValidator;
+      Name.setIdentifier(NextTok.getIdentifierInfo(), NextTok.getLocation());
+      Sema::SFINAETrap Trap(Actions);
+      ExprResult Res =
+          Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
+                                    Name, false, false, &NoTCValidator);
+      if (Res.isInvalid()) {
+        Token OpTok = Tok;
+        Tok.setKind(tok::arrow);
+        PP.EnableBacktrackAtThisPos();
+        Res = ParsePostfixExpressionSuffix(LHS);
+        if (Res.isUsable()) {
+          LHS = Res;
+          PP.CommitBacktrackedTokens();
+          Diag(OpTok, diag::err_mistyped_arrow_in_member_access)
+              << NextTok.getIdentifierInfo() << OpTok.is(tok::greater)
+              << FixItHint::CreateReplacement(OpTok.getLocation(), "->");
+        } else {
+          Tok = OpTok;
+          PP.Backtrack();
+        }
+      }
+    }
+  }
+
   return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
 }
 
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 239aecf..f5991a4 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -224,3 +224,16 @@ namespace pr16676 {
         .i;  // expected-error {{member reference type 'pr16676::S *' is a pointer; maybe you meant to use '->'}}
   }
 }
+
+namespace PR9054 {
+struct Foo {
+  void bar(int);
+  int fiz;
+};
+
+int test(struct Foo *foo) {
+  foo-bar(5);  // expected-error {{use of undeclared identifier 'bar'; did you mean '->' instead of '-'?}}
+  foo>baz(4);  // expected-error-re {{use of undeclared identifier 'baz'$}}
+  return foo>fiz;  // expected-error {{use of undeclared identifier 'fiz'; did you mean '->' instead of '>'?}}
+}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to