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!
RichardIndex: 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