Updated patch.

  Added comments, tests, handle more cases.
  Please review.

  Thank you.

http://reviews.llvm.org/D3137

CHANGE SINCE LAST DIFF
  http://reviews.llvm.org/D3137?vs=7995&id=8396#toc

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
@@ -617,11 +617,21 @@
     /// expression.
     ColonProtectionRAIIObject ColonProtection(*this);
 
-    ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
-    MissingCase = false;
-    if (LHS.isInvalid()) {
-      SkipUntil(tok::colon, StopAtSemi);
-      return StmtError();
+    ExprResult LHS;
+    if (!MissingCase) {
+      LHS = ParseConstantExpression();
+      if (LHS.isInvalid()) {
+        // If constant-expression is parsed unsuccessfully, recover by skipping
+        // current case statement (moving to the colon that ends it).
+        if (SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) {
+          TryConsumeToken(tok::colon, ColonLoc);
+          continue;
+        }
+        return StmtError();
+      }
+    } else {
+      LHS = Expr;
+      MissingCase = false;
     }
 
     // GNU case range extension.
@@ -631,25 +641,29 @@
       Diag(DotDotDotLoc, diag::ext_gnu_case_range);
       RHS = ParseConstantExpression();
       if (RHS.isInvalid()) {
-        SkipUntil(tok::colon, StopAtSemi);
+        if (SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) {
+          TryConsumeToken(tok::colon, ColonLoc);
+          continue;
+        }
         return StmtError();
       }
     }
 
     ColonProtection.restore();
 
-    if (TryConsumeToken(tok::colon, ColonLoc)) {
-    } else if (TryConsumeToken(tok::semi, ColonLoc)) {
-      // Treat "case blah;" as a typo for "case blah:".
-      Diag(ColonLoc, diag::err_expected_after)
-          << "'case'" << tok::colon
-          << FixItHint::CreateReplacement(ColonLoc, ":");
-    } else {
-      SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
-      Diag(ExpectedLoc, diag::err_expected_after)
-          << "'case'" << tok::colon
-          << FixItHint::CreateInsertion(ExpectedLoc, ":");
-      ColonLoc = ExpectedLoc;
+    if (!TryConsumeToken(tok::colon, ColonLoc)) {
+      if (TryConsumeToken(tok::semi, ColonLoc)) {
+        // Treat "case blah;" as a typo for "case blah:".
+        Diag(ColonLoc, diag::err_expected_after)
+            << "'case'" << tok::colon
+            << FixItHint::CreateReplacement(ColonLoc, ":");
+      } else {
+        SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
+        Diag(ExpectedLoc, diag::err_expected_after)
+            << "'case'" << tok::colon
+            << FixItHint::CreateInsertion(ExpectedLoc, ":");
+        ColonLoc = ExpectedLoc;
+      }
     }
 
     StmtResult Case =
@@ -676,8 +690,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;
 
@@ -687,17 +699,20 @@
     // Nicely diagnose the common error "switch (X) { case 4: }", which is
     // not valid.
     SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
+    if (ColonLoc.isInvalid())
+      AfterColonLoc = PrevTokLocation;
     Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
       << FixItHint::CreateInsertion(AfterColonLoc, " ;");
     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 +1237,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,48 @@
     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_1a(int x) {
+  switch(x) {
+  case 1  // expected-error{{expected ':' after 'case'}} \
+          // expected-error{{label at end of compound statement: expected statement}}
+  }
+}
+
+void pr19022_1b(int x) {
+  switch(x) {
+  case v  // expected-error{{use of undeclared identifier 'v'}} \
+          // expected-error{{label at end of compound statement: expected statement}}
+  }
+ }
+
+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'}}
+}
+
+int pr19022_4(int x) {
+  switch(x) {
+  case 1  // expected-error{{expected ':' after 'case'}} expected-note{{previous case defined here}}
+  case 1 : return x;  // expected-error{{duplicate case value '1'}}
+  }
+}
+
+namespace pr19022 {
+int baz5() {}
+bool bar0() {
+  switch (int foo0)  //expected-error{{variable declaration in condition must have an initializer}}
+  case bar5: ;  // expected-error{{use of undeclared identifier 'bar5'}}
+}
+}
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