Hi,

The attached patch improves diagnostics error recovery in for-statements.
Examples:

Before:

for.cpp:8:11: error: expected ';' in 'for' statement specifier
  for (n  0; n < 10; n++); // expected-error {{expected '=' in 'for'}}
          ^
for.cpp:8:8: warning: expression result unused
  for (n  0; n < 10; n++); // expected-error {{expected '=' in 'for'}}
       ^

After:

for.cpp:8:11: error: expected '=' in 'for' init statement
  for (n  0; n < 10; n++); // expected-error {{expected '=' in 'for'}}
          ^
          =


Before (note that this error currently causes clang to get confused about
the following statement):

for.cpp:9:14: error: expected ';' in 'for' statement specifier
  for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
             ^
for.cpp:9:25: error: expected ';' in 'for' statement specifier
  for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
                        ^
for.cpp:10:3: error: expected expression
  for (n = 0; n < 10 n++); // expected-error {{expected ';' in 'for'}}
  ^
for.cpp:10:3: error: expected ')'
for.cpp:9:7: note: to match this '('
  for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
      ^

After:

for.cpp:9:14: error: expected ';' in 'for' statement specifier
  for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
             ^
             ;


Before (an extreme case):

for.cpp:20:10: error: expected ';' in 'for' statement specifier
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
         ^
for.cpp:20:22: error: expected expression
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
                     ^
for.cpp:22:3: error: expected expression
  for (intt n = 0; n < 10; ++n); // expected-error {{undeclared identifier
'intt'}}
  ^
for.cpp:22:3: error: expected ')'
for.cpp:20:7: note: to match this '('
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
      ^
for.cpp:20:8: warning: expression result unused
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
       ^

After:

../src/tools/clang/test/Parser/for.cpp:20:10: error: expected '=' in 'for'
init statement
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
         ^
         =
../src/tools/clang/test/Parser/for.cpp:20:12: error: expected ';' in 'for'
statement specifier
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
           ^
           ;
../src/tools/clang/test/Parser/for.cpp:20:19: error: expected ';' in 'for'
statement specifier
  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}}
expected-error 2{{expected ';' in 'for'}}
                  ^
                  ;

The patch can be viewed online here: http://codereview.appspot.com/3992046/

Please let me know what I need to fix in order to get this committed.

Thanks!
Richard
Index: test/Parser/for.cpp
===================================================================
--- test/Parser/for.cpp	(revision 0)
+++ test/Parser/for.cpp	(revision 0)
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f1() {
+  int n;
+
+  for (n = 0; n < 10; n++);
+
+  for (n  0; n < 10; n++); // expected-error {{expected '=' in 'for'}}
+  for (n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
+  for (n = 0; n < 10 n++); // expected-error {{expected ';' in 'for'}}
+
+  for (int n  0; n < 10; n++); // expected-error {{expected '=' in 'for'}}
+  for (int n = 0 n < 10; n++); // expected-error {{expected ';' in 'for'}}
+  for (int n = 0; n < 10 n++); // expected-error {{expected ';' in 'for'}}
+
+  for (n  0; bool b = n < 10; n++); // expected-error {{expected '=' in 'for'}}
+  for (n = 0 bool b = n < 10; n++); // expected-error {{expected ';' in 'for'}}
+  for (n = 0; bool b = n < 10 n++); // expected-error {{expected ';' in 'for'}}
+
+  for (n 0 n < 10 n++); // expected-error {{expected '=' in 'for'}} expected-error 2{{expected ';' in 'for'}}
+
+  for (intt n = 0; n < 10; ++n); // expected-error {{undeclared identifier 'intt'}}
+
+  for (;); // expected-error {{expected ';' in 'for'}}
+}
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td	(revision 124070)
+++ include/clang/Basic/DiagnosticParseKinds.td	(working copy)
@@ -142,6 +142,7 @@
 def err_expected_semi_after_static_assert : Error<
   "expected ';' after static_assert">;
 def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
+def err_expected_equals_for : Error<"expected '=' in 'for' init statement">;
 def err_expected_colon_after : Error<"expected ':' after %0">;
 def err_label_end_of_compound_statement : Error<
   "label at end of compound statement: expected statement">;
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp	(revision 124070)
+++ lib/Parse/ParseStmt.cpp	(working copy)
@@ -14,6 +14,8 @@
 
 #include "clang/Parse/Parser.h"
 #include "RAIIObjectsForParser.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
 #include "clang/Sema/Scope.h"
@@ -1038,8 +1040,22 @@
       }
       Collection = ParseExpression();
     } else {
-      Diag(Tok, diag::err_expected_semi_for);
-      SkipUntil(tok::semi);
+      // suggest 'expected "="' if the declaration's last declarator lacks
+      // an initializer. eg. for (int n 0; n < 10; ++n)
+      VarDecl *VD = DG.get().isNull() ? 0 : dyn_cast<VarDecl>(*(DG.get().end() - 1));
+      if (VD && !VD->hasInit()) {
+        Diag(Tok, diag::err_expected_equals_for)
+          << FixItHint::CreateInsertion(Tok.getLocation(), "=");
+        ExprResult Init = ParseExpression();
+        VD->setInit(Init.take());
+      }
+      if (Tok.is(tok::semi)) {
+        ConsumeToken();
+      } else {
+        // eg. for (int n = 0l n < 10; ++n)
+        Diag(Tok, diag::err_expected_semi_for)
+          << FixItHint::CreateInsertion(Tok.getLocation(), "; ");
+      }
     }
   } else {
     Value = ParseExpression();
@@ -1065,8 +1081,30 @@
       }
       Collection = ParseExpression();
     } else {
-      if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
-      SkipUntil(tok::semi);
+      if (!Value.isInvalid()) {
+        // 'expected "="' if the expression is a DeclRefExpr: for (n 0; n < 10; ++n)
+        if (isa<DeclRefExpr>(Value.get())) {
+          SourceLocation TokLocation = Tok.getLocation();
+          Diag(Tok, diag::err_expected_equals_for)
+            << FixItHint::CreateInsertion(TokLocation, "=");
+          ExprResult Init = ParseExpression();
+          if (!Init.isInvalid()) {
+            Value = Actions.ActOnBinOp(getCurScope(), TokLocation, tok::equal,
+                                       Value.take(), Init.take());
+            FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get()));
+          }
+        }
+        if (Tok.is(tok::semi)) {
+          ConsumeToken();
+        } else {
+          Diag(Tok, diag::err_expected_semi_for)
+            << FixItHint::CreateInsertion(Tok.getLocation(), "; ");
+        }
+      } else {
+        SkipUntil(tok::r_paren, true, true);
+        if (Tok.is(tok::semi))
+          ConsumeToken();
+      }
     }
   }
   if (!ForEach) {
@@ -1074,6 +1112,8 @@
     // Parse the second part of the for specifier.
     if (Tok.is(tok::semi)) {  // for (...;;
       // no second part.
+    } else if (Tok.is(tok::r_paren)) {
+      // missing both semicolons.
     } else {
       ExprResult Second;
       if (getLang().CPlusPlus)
@@ -1088,12 +1128,19 @@
       SecondPart = Actions.MakeFullExpr(Second.get());
     }
 
+    if (Tok.isNot(tok::semi)) {
+      if (!SecondPartIsInvalid || SecondVar)
+        Diag(Tok, diag::err_expected_semi_for)
+          << FixItHint::CreateInsertion(Tok.getLocation(), "; ");
+      else {
+        SkipUntil(tok::r_paren, true, true);
+        if (Tok.is(tok::semi))
+          ConsumeToken();
+      }
+    }
+
     if (Tok.is(tok::semi)) {
       ConsumeToken();
-    } else {
-      if (!SecondPartIsInvalid || SecondVar) 
-        Diag(Tok, diag::err_expected_semi_for);
-      SkipUntil(tok::semi);
     }
 
     // Parse the third part of the for specifier.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to