diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md
index bd9c0a623..673d7eb04 100644
--- a/src/expressions/block-expr.md
+++ b/src/expressions/block-expr.md
@@ -4,13 +4,8 @@
> _BlockExpression_ :\
> `{`\
> [_InnerAttribute_]\*\
-> _Statements_?\
+> ([_Statement_]\* ([_StatementNotExpression_] | [_Expression_]))?\
> `}`
->
-> _Statements_ :\
-> [_Statement_]\+\
-> | [_Statement_]\+ [_ExpressionWithoutBlock_]\
-> | [_ExpressionWithoutBlock_]
A *block expression*, or *block*, is a control flow expression and anonymous namespace scope for items and variable declarations.
As a control flow expression, a block sequentially executes its component non-item declaration statements and then its final optional expression.
@@ -20,10 +15,8 @@ The syntax for a block is `{`, then any [inner attributes], then any number of [
Statements are usually required to be followed by a semicolon, with two exceptions:
-1. Item declaration statements do not need to be followed by a semicolon.
-2. Expression statements usually require a following semicolon except if its outer expression is a flow control expression.
-
-Furthermore, extra semicolons between statements are allowed, but these semicolons do not affect semantics.
+1. Item declaration statements.
+2. Expression statements that end with a `}` and are not at the end of the block.
When evaluating a block expression, each statement, except for item declaration statements, is executed sequentially.
Then the final operand is executed, if given.
@@ -167,9 +160,10 @@ fn is_unix_platform() -> bool {
}
```
-[_ExpressionWithoutBlock_]: ../expressions.md
+[_Expression_]: ../expressions.md
[_InnerAttribute_]: ../attributes.md
[_Statement_]: ../statements.md
+[_StatementNotExpression_]: ../statements.md
[`await` expressions]: await-expr.md
[`cfg`]: ../conditional-compilation.md
[`for`]: loop-expr.md#iterator-loops
diff --git a/src/statements.md b/src/statements.md
index c2ae585a0..835fda6d2 100644
--- a/src/statements.md
+++ b/src/statements.md
@@ -2,10 +2,14 @@
> **Syntax**\
> _Statement_ :\
+> _StatementNotExpression_\
+> | [_ExpressionWithBlock_]
+>
+> _StatementNotExpression_ :\
> `;`\
> | [_Item_]\
> | [_LetStatement_]\
-> | [_ExpressionStatement_]\
+> | [_Expression_] `;`\
> | [_MacroInvocationSemi_]
@@ -75,18 +79,13 @@ let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler
## Expression statements
-> **Syntax**\
-> _ExpressionStatement_ :\
-> [_ExpressionWithoutBlock_][expression] `;`\
-> | [_ExpressionWithBlock_][expression] `;`?
-
An *expression statement* is one that evaluates an [expression] and ignores its result.
As a rule, an expression statement's purpose is to trigger the effects of evaluating its expression.
An expression that consists of only a [block expression][block] or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon.
This can cause an ambiguity between it being parsed as a standalone statement and as a part of another expression;
in this case, it is parsed as a statement.
-The type of [_ExpressionWithBlock_][expression] expressions when used as statements must be the unit type.
+The type of [_ExpressionWithBlock_] expressions when used as statements must be the unit type.
```rust
# let mut v = vec![1, 2, 3];
@@ -135,8 +134,8 @@ The attributes that have meaning on a statement are [`cfg`], and [the lint check
[the lint check attributes]: attributes/diagnostics.md#lint-check-attributes
[pattern]: patterns.md
[_BlockExpression_]: expressions/block-expr.md
-[_ExpressionStatement_]: #expression-statements
[_Expression_]: expressions.md
+[_ExpressionWithBlock_]: expressions.md
[_Item_]: items.md
[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
[_LetStatement_]: #let-statements