From: Douglas Gregor Date: Thu, 17 Feb 2011 03:38:46 +0000 (+0000) Subject: Improve parser recovery in "for" statements, from Richard Smith! X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b72c77855473379c4c47e701005f7818946f659b;p=clang Improve parser recovery in "for" statements, from Richard Smith! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125722 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 5f932919b9..3e7ec533bd 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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 index 0000000000..e413839389 --- /dev/null +++ b/test/Parser/for.cpp @@ -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'}} +}