[PATCH] Recovery of switch statement

Serge Pavlov sepavloff at gmail.com
Thu Mar 20 11:23:41 PDT 2014


sepavloff added you to the CC list for the revision "Recovery of switch statement".

Fix to PR19022 as well as some other problems of error recovery in switch statement.

http://llvm-reviews.chandlerc.com/D3137

Files:
  lib/Parse/ParseStmt.cpp
  lib/Sema/SemaStmt.cpp
  test/Parser/switch-recovery.cpp
  test/Sema/statements.c

Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -620,7 +620,9 @@
     ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
     MissingCase = false;
     if (LHS.isInvalid()) {
-      SkipUntil(tok::colon, StopAtSemi);
+      if (SkipUntil(tok::colon, StopAtSemi | StopBeforeMatch) &&
+          TryConsumeToken(tok::colon, ColonLoc))
+        continue;
       return StmtError();
     }
 
@@ -676,8 +678,6 @@
     // Handle all case statements.
   } while (Tok.is(tok::kw_case));
 
-  assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
-
   // If we found a non-case statement, start by parsing it.
   StmtResult SubStmt;
 
@@ -692,12 +692,13 @@
     SubStmt = true;
   }
 
-  // Broken sub-stmt shouldn't prevent forming the case statement properly.
-  if (SubStmt.isInvalid())
-    SubStmt = Actions.ActOnNullStmt(SourceLocation());
-
   // Install the body into the most deeply-nested case.
-  Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
+  if (DeepestParsedCaseStmt) {
+    // Broken sub-stmt shouldn't prevent forming the case statement properly.
+    if (SubStmt.isInvalid())
+      SubStmt = Actions.ActOnNullStmt(SourceLocation());
+    Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
+  }
 
   // Return the top level parsed statement tree.
   return TopLevelCase;
@@ -1222,15 +1223,6 @@
   InnerScope.Exit();
   SwitchScope.Exit();
 
-  if (Body.isInvalid()) {
-    // FIXME: Remove the case statement list from the Switch statement.
-
-    // Put the synthesized null statement on the same line as the end of switch
-    // condition.
-    SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd();
-    Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation);
-  }
-
   return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
 }
 
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -702,7 +702,19 @@
   assert(SS == getCurFunction()->SwitchStack.back() &&
          "switch stack missing push/pop!");
 
-  SS->setBody(BodyStmt, SwitchLoc);
+  Stmt *Body = BodyStmt;
+  if (!Body) {
+    // Put the synthesized null statement on the same line as the end of switch
+    // condition.
+    SourceLocation SynthesizedNullStmtLocation;
+    if (Expr *Cond = SS->getCond())
+      SynthesizedNullStmtLocation = Cond->getLocEnd();
+    else if (VarDecl *CondVar = SS->getConditionVariable())
+      SynthesizedNullStmtLocation = CondVar->getLocEnd();
+    Body = ActOnNullStmt(SynthesizedNullStmtLocation).release();
+    SS->setSwitchCaseList(0);
+  }
+  SS->setBody(Body, SwitchLoc);
   getCurFunction()->SwitchStack.pop_back();
 
   Expr *CondExpr = SS->getCond();
@@ -1141,8 +1153,9 @@
     }
   }
 
-  DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
-                        diag::warn_empty_switch_body);
+  if (BodyStmt)
+    DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
+                          diag::warn_empty_switch_body);
 
   // FIXME: If the case list was broken is some way, we don't have a good system
   // to patch it up.  Instead, just return the whole substmt as broken.
Index: test/Parser/switch-recovery.cpp
===================================================================
--- test/Parser/switch-recovery.cpp
+++ test/Parser/switch-recovery.cpp
@@ -170,3 +170,19 @@
     default: // expected-error {{label at end of compound statement: expected statement}}
   }
 }
+
+void pr19022_1() {
+  switch (int x)  // expected-error {{variable declaration in condition must have an initializer}}
+  case v: ;  // expected-error {{use of undeclared identifier 'v'}}
+}
+
+void pr19022_2() {
+  switch (int x)  // expected-error {{variable declaration in condition must have an initializer}}
+  case v1: case v2: ;  // expected-error {{use of undeclared identifier 'v1'}} \
+                       // expected-error {{use of undeclared identifier 'v2'}}
+}
+
+void pr19022_3(int x) {
+  switch (x)
+  case 1: case v2: ;  // expected-error {{use of undeclared identifier 'v2'}}
+}
Index: test/Sema/statements.c
===================================================================
--- test/Sema/statements.c
+++ test/Sema/statements.c
@@ -36,7 +36,7 @@
 
 // PR6034
 void test11(int bit) {
-  switch (bit) // expected-warning {{switch statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
+  switch (bit)
   switch (env->fpscr)  // expected-error {{use of undeclared identifier 'env'}}
   {
   }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D3137.1.patch
Type: text/x-patch
Size: 4703 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140320/38223b38/attachment.bin>


More information about the cfe-commits mailing list