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'}} { }