From d33e4b03f0f810a315915412448a1f73c30e0feb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 May 2024 08:52:15 +0200 Subject: [PATCH] document guarantee about evaluation of associated consts and const blocks --- src/expressions/block-expr.md | 26 ++++++++++++++++++++++---- src/expressions/path-expr.md | 3 +++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 890cf856d..0dda00c56 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -123,13 +123,13 @@ loop { > _ConstBlockExpression_ :\ >    `const` _BlockExpression_ -A *const block* is a variant of a block expression which evaluates at compile-time instead of at runtime. +A *const block* is a variant of a block expression whose body evaluates at compile-time instead of at runtime. Const blocks allows you to define a constant value without having to define new [constant items], and thus they are also sometimes referred as *inline consts*. It also supports type inference so there is no need to specify the type, unlike [constant items]. Const blocks have the ability to reference generic parameters in scope, unlike [free][free item] constant items. -They are desugared to associated constant items with generic parameters in scope. +They are desugared to constant items with generic parameters in scope (similar to associated constants, but without a trait or type they are associated with). For example, this code: ```rust @@ -152,8 +152,26 @@ fn foo() -> usize { } ``` -This also means that const blocks are treated similarly to associated constants. -For example, they are not guaranteed to be evaluated when the enclosing function is unused. +If the const block expression is executed at runtime, then the constant is guaranteed to be evaluated, even if its return value is ignored: + +```rust +fn foo() -> usize { + // If this code ever gets executed, then the assertion has definitely + // been evaluated at compile-time. + const { assert!(std::mem::size_of::() > 0); } + // Here we can have unsafe code relying on the type being non-zero-sized. + /* ... */ + 42 +} +``` + +If the const block expression is not executed at runtime, it may or may not be evaluated: +```rust,compile_fail +if false { + // The panic may or may not occur when the program is built. + const { panic!(); } +} +``` ## `unsafe` blocks diff --git a/src/expressions/path-expr.md b/src/expressions/path-expr.md index 0909c5ddb..0707e9d41 100644 --- a/src/expressions/path-expr.md +++ b/src/expressions/path-expr.md @@ -23,6 +23,8 @@ let push_integer = Vec::::push; let slice_reverse = <[i32]>::reverse; ``` +Evaluation of associated constants is handled the same way as [`const` blocks]. + [_PathInExpression_]: ../paths.md#paths-in-expressions [_QualifiedPathInExpression_]: ../paths.md#qualified-paths [place expressions]: ../expressions.md#place-expressions-and-value-expressions @@ -30,3 +32,4 @@ let slice_reverse = <[i32]>::reverse; [path]: ../paths.md [`static mut`]: ../items/static-items.md#mutable-statics [`unsafe` block]: block-expr.md#unsafe-blocks +[`const` blocks]: block-expr.md#const-blocks