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'}}
   {
   }
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'}}
   {
   }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to