This is a common misconception, but it isn't true.
Rust is an expression-oriented language. This means that most things are expressions, and evaluate to some kind of value. However, there are also statements. "Item declarations" (stuff like defining structs, etc) and let statements are the two most common kinds of statements. However, there's also an "expression statement", where you can take any expression, add ; to it, and it becomes a statement rather than an expression.
A block has the following grammar:
BlockExpression :
{
InnerAttribute*
Statements?
}
Statements :
Statement+
| Statement+ ExpressionWithoutBlock
| ExpressionWithoutBlock
A block is made of (leaving some things out for simplicity) zero or more statements, where statements is either one or more statements, one or more statements and an expression, or an expression.Note that blocks are themselves expressions, and so evaluate to a value. The only way that you get "no semicolon for return" is when the expression is in this tail position, when its value is the value of the whole block.
... does that make sense? Perusing https://doc.rust-lang.org/reference/statements-and-expressio... might help.