diff --git a/changelog/dmd.empty-statement-error.dd b/changelog/dmd.empty-statement-error.dd new file mode 100644 index 000000000000..daa35299a768 --- /dev/null +++ b/changelog/dmd.empty-statement-error.dd @@ -0,0 +1,21 @@ +Using `;` as an empty statement has been turned into an error + +This has been deprecated since 2.075.0 because it's error prone: + +--- +void main() +{ + foreach (i; 0 .. 8); + { + // Because of the accidental semicolon above, + // this block statement is executed once. + // It's not the loop body + } +} +--- + +It will now result in an error. + +$(CONSOLE +app.d(3): Error: use `{ }` for an empty statement, not `;` +) diff --git a/compiler/src/dmd/cparse.d b/compiler/src/dmd/cparse.d index cc78317ddc62..dc21af6e1024 100644 --- a/compiler/src/dmd/cparse.d +++ b/compiler/src/dmd/cparse.d @@ -199,7 +199,7 @@ final class CParser(AST) : Parser!AST else if (token.value == TOK.leftCurly) s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_); else - s = cparseStatement(ParseStatementFlags.semiOk); + s = cparseStatement(0); s = new AST.LabelStatement(loc, ident, s); break; } @@ -373,7 +373,7 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(cparseStatement(ParseStatementFlags.curlyScope)); } if (endPtr) *endPtr = token.ptr; @@ -514,7 +514,7 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + auto cur = cparseStatement(ParseStatementFlags.curlyScope); statements.push(cur); // https://issues.dlang.org/show_bug.cgi?id=21739 @@ -529,7 +529,7 @@ final class CParser(AST) : Parser!AST } else { - s = cparseStatement(ParseStatementFlags.semi); + s = cparseStatement(0); } s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.CaseStatement(loc, exp, s); @@ -546,12 +546,12 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(cparseStatement(ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else - s = cparseStatement(ParseStatementFlags.semi); + s = cparseStatement(0); s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.DefaultStatement(loc, s); break; diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index da257601a89a..3055e25880c7 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -5198,7 +5198,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.leftCurly: if (requireDo) error("missing `do { ... }` after `in` or `out`"); - f.fbody = parseStatement(ParseStatementFlags.semi); + f.fbody = parseStatement(0); f.endloc = endloc; break; @@ -6034,7 +6034,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope)); } if (endPtr) *endPtr = token.ptr; @@ -6067,10 +6067,7 @@ LagainStc: case TOK.semicolon: if (!(flags & ParseStatementFlags.semiOk)) { - if (flags & ParseStatementFlags.semi) - deprecation("use `{ }` for an empty statement, not `;`"); - else - error("use `{ }` for an empty statement, not `;`"); + error("use `{ }` for an empty statement, not `;`"); } nextToken(); s = new AST.ExpStatement(loc, cast(AST.Expression)null); @@ -6287,7 +6284,7 @@ LagainStc: _body = null; } else - _body = parseStatement(ParseStatementFlags.semi); + _body = parseStatement(0); s = new AST.PragmaStatement(loc, ident, args, _body); break; } @@ -6340,7 +6337,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - auto cur = parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + auto cur = parseStatement(ParseStatementFlags.curlyScope); statements.push(cur); // https://issues.dlang.org/show_bug.cgi?id=21739 @@ -6355,7 +6352,7 @@ LagainStc: } else { - s = parseStatement(ParseStatementFlags.semi); + s = parseStatement(0); } s = new AST.ScopeStatement(loc, s, token.loc); @@ -6384,12 +6381,12 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else - s = parseStatement(ParseStatementFlags.semi); + s = parseStatement(0); s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.DefaultStatement(loc, s); break; @@ -9686,7 +9683,6 @@ immutable PREC[EXP.max + 1] precedence = enum ParseStatementFlags : int { - semi = 1, // empty ';' statements are allowed, but deprecated scope_ = 2, // start a new scope curly = 4, // { } statement is required curlyScope = 8, // { } starts a new scope diff --git a/compiler/src/dmd/statementsem.d b/compiler/src/dmd/statementsem.d index 2004d8f89682..9c56ce6cdfff 100644 --- a/compiler/src/dmd/statementsem.d +++ b/compiler/src/dmd/statementsem.d @@ -4788,7 +4788,7 @@ private Statements* flatten(Statement statement, Scope* sc) auto a = new Statements(); while (p.token.value != TOK.endOfFile) { - Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + Statement s = p.parseStatement(ParseStatementFlags.curlyScope); if (!s || global.errors != errors) return errorStatements(); a.push(s); diff --git a/compiler/test/fail_compilation/fail4559.d b/compiler/test/fail_compilation/fail4559.d index 0101ae98bf1a..657c184d7875 100644 --- a/compiler/test/fail_compilation/fail4559.d +++ b/compiler/test/fail_compilation/fail4559.d @@ -1,10 +1,10 @@ /* -REQUIRED_ARGS: -o- -de +REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/fail4559.d(13): Deprecation: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(19): Deprecation: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(21): Deprecation: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(13): Error: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(19): Error: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(21): Error: use `{ }` for an empty statement, not `;` --- */