]> granicus.if.org Git - clang/commitdiff
Improve parser recovery in "for" statements, from Richard Smith!
authorDouglas Gregor <dgregor@apple.com>
Thu, 17 Feb 2011 03:38:46 +0000 (03:38 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 17 Feb 2011 03:38:46 +0000 (03:38 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125722 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseStmt.cpp
test/Parser/for.cpp [new file with mode: 0644]

index 5f932919b9250b7e6a00b8cbfcf3a474e0184e87..3e7ec533bd5bb42b92647cb9afcc43146612af69 100644 (file)
@@ -1039,7 +1039,6 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
       Collection = ParseExpression();
     } else {
       Diag(Tok, diag::err_expected_semi_for);
-      SkipUntil(tok::semi);
     }
   } else {
     Value = ParseExpression();
@@ -1065,8 +1064,14 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
       }
       Collection = ParseExpression();
     } else {
-      if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
-      SkipUntil(tok::semi);
+      if (!Value.isInvalid()) {
+        Diag(Tok, diag::err_expected_semi_for);
+      } else {
+        // Skip until semicolon or rparen, don't consume it.
+        SkipUntil(tok::r_paren, true, true);
+        if (Tok.is(tok::semi))
+          ConsumeToken();
+      }
     }
   }
   if (!ForEach) {
@@ -1074,6 +1079,8 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
     // 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 +1095,16 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
       SecondPart = Actions.MakeFullExpr(Second.get());
     }
 
+    if (Tok.isNot(tok::semi)) {
+      if (!SecondPartIsInvalid || SecondVar)
+        Diag(Tok, diag::err_expected_semi_for);
+      else
+        // Skip until semicolon or rparen, don't consume it.
+        SkipUntil(tok::r_paren, true, true);
+    }
+
     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.
diff --git a/test/Parser/for.cpp b/test/Parser/for.cpp
new file mode 100644 (file)
index 0000000..e413839
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 (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 n < 10 n++); // expected-error 2{{expected ';' in 'for'}}
+
+  for (;); // expected-error {{expected ';' in 'for'}}
+}