Skip to content

Commit 53c008f

Browse files
kitaisrealrintaro
authored andcommitted
[Parser]: Labeled block without do diagnostics (swiftlang#29147)
Improve diagnostics for labeled block without 'do'. Parse and diagnose { identifier ':' '{' } as a labeled 'do' statement. https://bugs.swift.org/browse/SR-3867
1 parent a8e5a04 commit 53c008f

File tree

4 files changed

+30
-3
lines changed

4 files changed

+30
-3
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,8 @@ ERROR(statement_same_line_without_semi,none,
933933
"consecutive statements on a line must be separated by ';'", ())
934934
ERROR(invalid_label_on_stmt,none,
935935
"labels are only valid on loops, if, and switch statements", ())
936+
ERROR(labeled_block_needs_do,none,
937+
"labeled block needs 'do'", ())
936938

937939
ERROR(snake_case_deprecated,none,
938940
"%0 has been replaced with %1 in Swift 3",

include/swift/Parse/Parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,8 @@ class Parser {
16031603
ParserResult<Stmt> parseStmtGuard();
16041604
ParserResult<Stmt> parseStmtWhile(LabeledStmtInfo LabelInfo);
16051605
ParserResult<Stmt> parseStmtRepeat(LabeledStmtInfo LabelInfo);
1606-
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo);
1606+
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo,
1607+
bool shouldSkipDoTokenConsume = false);
16071608
ParserResult<CatchStmt> parseStmtCatch();
16081609
ParserResult<Stmt> parseStmtForEach(LabeledStmtInfo LabelInfo);
16091610
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);

lib/Parse/ParseStmt.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ bool Parser::isStartOfStmt() {
9393
Parser::BacktrackingScope backtrack(*this);
9494
consumeToken(tok::identifier);
9595
consumeToken(tok::colon);
96+
97+
// We treating IDENTIIFIER: { as start of statement to provide missed 'do'
98+
// diagnostics. This case will be handled in parseStmt().
99+
if (Tok.is(tok::l_brace)) {
100+
return true;
101+
}
96102
// For better recovery, we just accept a label on any statement. We reject
97103
// putting a label on something inappropriate in parseStmt().
98104
return isStartOfStmt();
@@ -637,6 +643,12 @@ ParserResult<Stmt> Parser::parseStmt() {
637643
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
638644
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
639645
return parseStmtPoundAssert();
646+
case tok::l_brace:
647+
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
648+
SourceLoc colonLoc = Tok.getLoc();
649+
diagnose(colonLoc, diag::labeled_block_needs_do)
650+
.fixItInsert(colonLoc, "do ");
651+
return parseStmtDo(LabelInfo, /*shouldSkipDoTokenConsume*/ true);
640652
}
641653
}
642654

@@ -1875,9 +1887,16 @@ ParserResult<Stmt> Parser::parseStmtRepeat(LabeledStmtInfo labelInfo) {
18751887
/// stmt-do:
18761888
/// (identifier ':')? 'do' stmt-brace
18771889
/// (identifier ':')? 'do' stmt-brace stmt-catch+
1878-
ParserResult<Stmt> Parser::parseStmtDo(LabeledStmtInfo labelInfo) {
1890+
ParserResult<Stmt> Parser::parseStmtDo(LabeledStmtInfo labelInfo,
1891+
bool shouldSkipDoTokenConsume) {
18791892
SyntaxContext->setCreateSyntax(SyntaxKind::DoStmt);
1880-
SourceLoc doLoc = consumeToken(tok::kw_do);
1893+
SourceLoc doLoc;
1894+
1895+
if (shouldSkipDoTokenConsume) {
1896+
doLoc = Tok.getLoc();
1897+
} else {
1898+
doLoc = consumeToken(tok::kw_do);
1899+
}
18811900

18821901
ParserStatus status;
18831902

test/stmt/statements.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ func DoWhileStmt2() {
252252
}
253253
}
254254

255+
func LabeledDoStmt() {
256+
LABEL: { // expected-error {{labeled block needs 'do'}} {{10-10=do }}
257+
}
258+
}
259+
255260
//===--- Repeat-while statement.
256261

257262
func RepeatWhileStmt1() {

0 commit comments

Comments
 (0)