When a valid expression is followed by a colon inside a switch scope,
suggest a fix-it hint to insert a case before the expression.
int f1(int i) {
switch (i) {
0: return 1;
default: return 0;
}
}
case.cc:3:4: error: expected 'case' keyword before expression
0: return 1;
^
case
Index: test/Parser/switch-recovery.cpp
===================================================================
--- test/Parser/switch-recovery.cpp (revision 129584)
+++ test/Parser/switch-recovery.cpp (working copy)
@@ -32,3 +32,81 @@
}
}
};
+
+int test3(int i) {
+ switch (i) {
+ case 1: return 0;
+ 2: return 1; // expected-error {{expected 'case' keyword before expression}}
+ default: return 5;
+ }
+}
+
+int test4(int i) {
+ switch (i)
+ 1: return -1; // expected-error {{expected 'case' keyword before expression}}
+ return 0;
+}
+
+int test5(int i) {
+ switch (i) {
+ case 1: case 2: case 3: return 1;
+ {
+ 4:5:6:7: return 2; // expected-error 4{{expected 'case' keyword before expression}}
+ }
+ default: return -1;
+ }
+}
+
+int test6(int i) {
+ switch (i) {
+ case 1:
+ case 4:
+ class foo{
+ public:
+ protected:
+ private:
+ };
+ case 2:
+ 5: // expected-error {{expected 'case' keyword before expression}}
+ default: return 1;
+ }
+}
+
+int test7(int i) {
+ switch (i) {
+ case false ? 1 : 2:
+ true ? 1 : 2: // expected-error {{expected 'case' keyword before expression}}
+ case 10:
+ 14 ? 3 : 4;
+ default:
+ return 1;
+ }
+}
+
+enum foo { A, B, C};
+int test8( foo x ) {
+ switch (x) {
+ A: return 0; // no warning since A is a valid label.
+ default: return 1;
+ }
+}
+
+// Stress test to make sure Clang doesn't crash.
+void test9(int x) {
+ switch(x) {
+ case 1: return;
+ 2: case; // expected-error {{expected 'case' keyword before expression}} \
+ expected-error {{expected expression}}
+ 4:5:6: return; // expected-error 3{{expected 'case' keyword before expression}}
+ 7: :x; // expected-error {{expected 'case' keyword before expression}} \
+ expected-error {{expected expression}}
+ 8:: x; // expected-error {{expected ';' after expression}} \
+ expected-error {{no member named 'x' in the global namespace}} \
+ expected-warning {{expression result unused}}
+ 9:: :y; // expected-error {{expected ';' after expression}} \
+ expected-error {{expected unqualified-id}} \
+ expected-warning {{expression result unused}}
+ :; // expected-error {{expected expression}}
+ ::; // expected-error {{expected unqualified-id}}
+ }
+}
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td (revision 129584)
+++ include/clang/Basic/DiagnosticParseKinds.td (working copy)
@@ -204,6 +204,9 @@
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
+def err_expected_case_before_expression: Error<
+ "expected 'case' keyword before expression">;
+
// Declarations.
def err_typename_requires_specqual : Error<
"type name requires a specifier or qualifier">;
Index: include/clang/Sema/Scope.h
===================================================================
--- include/clang/Sema/Scope.h (revision 129584)
+++ include/clang/Sema/Scope.h (working copy)
@@ -75,7 +75,10 @@
/// ObjCMethodScope - This scope corresponds to an Objective-C method body.
/// It always has FnScope and DeclScope set as well.
- ObjCMethodScope = 0x400
+ ObjCMethodScope = 0x400,
+
+ /// SwitchScope - This is a scope that corresponds to a switch statement.
+ SwitchScope = 0x800
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -260,6 +263,15 @@
return getFlags() & Scope::AtCatchScope;
}
+ /// isSwitchScope - Return true if this scope is a switch scope.
+ bool isSwitchScope() const {
+ for (const Scope *S = this; S; S = S->getParent()) {
+ if (S->getFlags() & Scope::SwitchScope)
+ return true;
+ }
+ return false;
+ }
+
typedef UsingDirectivesTy::iterator udir_iterator;
typedef UsingDirectivesTy::const_iterator const_udir_iterator;
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp (revision 129584)
+++ lib/Parse/ParseStmt.cpp (working copy)
@@ -121,10 +121,16 @@
return StmtError();
}
+ // If a case statement is missing, then back-track to this point and
+ // insert case keyword.
+ Token OldToken = Tok;
+ TentativeParsingAction TPA(*this);
+
// FIXME: Use the attributes
// expression[opt] ';'
ExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
+ TPA.Commit();
// If the expression is invalid, skip ahead to the next semicolon or '}'.
// Not doing this opens us up to the possibility of infinite loops if
// ParseExpression does not consume any tokens.
@@ -133,9 +139,26 @@
ConsumeToken();
return StmtError();
}
- // Otherwise, eat the semicolon.
- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+
+ if (!Tok.is(tok::colon) || !getCurScope()->isSwitchScope()) {
+ TPA.Commit();
+ // Otherwise, eat the semicolon.
+ ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+ }
+
+ // If the expression is followed by a colon and inside a switch block,
+ // suggest a missing case keyword.
+ Diag(OldToken, diag::err_expected_case_before_expression)
+ << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
+
+ // Push expression back on token stream
+ TPA.Revert();
+ PP.EnterToken(OldToken);
+ // Set current token to kw_case
+ OldToken.setKind(tok::kw_case);
+ Tok = OldToken;
+ // PASS THROUGH
}
case tok::kw_case: // C99 6.8.1: labeled-statement
@@ -775,7 +798,7 @@
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- unsigned ScopeFlags = Scope::BreakScope;
+ unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits