diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a15a5b17a5e6f..6259cfac95248 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -91,6 +91,8 @@ - [Behavior considered undefined](behavior-considered-undefined.md) - [Behavior not considered unsafe](behavior-not-considered-unsafe.md) +- [Constant Evalutation](const_eval.md) + [Appendix: Influences](influences.md) [Appendix: As-yet-undocumented Features](undocumented.md) diff --git a/src/const_eval.md b/src/const_eval.md new file mode 100644 index 0000000000000..410e609e22a1b --- /dev/null +++ b/src/const_eval.md @@ -0,0 +1,82 @@ +# Constant evaluation + +Constant evaluation is the process of computing the result of +[expressions] during compilation. Only a subset of all expressions +can be evaluated at compile-time. + +## Constant expressions + +Certain types of expressions can be evaluated at compile time. These are called +_constant expressions_ and are required in const contexts. In +other places, such as in [`let` statements](statements.html#let-statements), +constant expressions may be evaluated at compile time. If errors, such as out +of bounds [array indexing] or [overflow] occurs, +then it is a compiler error if the value must be evaluated at compile time, +otherwise it is just a warning, but the code will most likely panic when run. + +The following expressions are constant expressions, so long as any operands are +also constant expressions and do not cause any [`Drop::drop`][destructors] calls +to be ran. + +* [Literals]. +* [Paths] to [functions](items/functions.html) and constants. + Recursively defining constants is not allowed. +* [Tuple expressions]. +* [Array expressions]. +* [Struct] expressions. +* [Enum variant] expressions. +* [Block expressions], including `unsafe` blocks, which only contain items and + possibly a constant tail expression. +* [Field] expressions. +* Index expressions, [array indexing] or [slice] with a `usize`. +* [Range expressions]. +* [Closure expressions] which don't capture variables from the environment. +* Built in [negation], [arithmetic, logical], [comparison] or [lazy boolean] + operators used on integer and floating point types, `bool` and `char`. +* Shared [borrow]s, except if applied to a type with [interior mutability]. +* The [dereference operator]. +* [Grouped] expressions. +* [Cast] expressions, except pointer to address and + function pointer to address casts. +* calls of const functions and const methods + +## Const context + +A _const context_ is one of the following: + +* [array type length expressions] +* repeat expression length expessions +* the initializer of + * [constants] + * [statics] + * [enum discriminants] + +[array type length expressions]: types.html#array-and-slice-types +[enum discriminants]: items/enumerations.html#custom-discriminant-values-for-field-less-enumerations +[constants]: items/constant-items.html +[statics]: items/static-items.html +[expressions]: expressions.html +[array indexing]: expressions/array-expr.html#array-and-slice-indexing-expressions +[overflow]: expressions/operator-expr.html#overflow +[destructors]: destructors.html +[literals]: expressions/literal-expr.html +[paths]: expressions/path-expr.html +[tuple expressions]: expressions/tuple-expr.html +[array expressions]: expressions/array-expr.html +[struct]: expressions/struct-expr.html +[enum variant]: expressions/enum-variant-expr.html +[block expressions]: expressions/block-expr.html +[field]: expressions/field-expr.html +[array indexing]: expressions/array-expr.html#array-and-slice-indexing-expressions +[slice]: types.html#array-and-slice-types +[range expressions]: expressions/range-expr.html +[closure expressions]: expressions/closure-expr.html +[negation]: expressions/operator-expr.html#negation-operators +[arithmetic, logical]: expressions/operator-expr.html#arithmetic-and-logical-binary-operators +[comparison]: expressions/operator-expr.html#comparison-operators +[lazy boolean]: expressions/operator-expr.html#lazy-boolean-operators +[borrow]: expressions/operator-expr.html#borrow-operators +[interior mutability]: interior-mutability.html +[dereference operator]: expressions/operator-expr.html#the-dereference-operator +[grouped]: expressions/grouped-expr.html +[cast]: expressions/operator-expr.html#type-cast-expressions diff --git a/src/expressions.md b/src/expressions.md index fd3d0e8838442..a00a19643d495 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -229,43 +229,6 @@ Implicit borrows may be taken in the following expressions: * Operands of [comparison]. * Left operands of the [compound assignment]. -## Constant expressions - -Certain types of expressions can be evaluated at compile time. These are called -_constant expressions_. Certain places, such as in -[constants](items/constant-items.html) and [statics](items/static-items.html), -require a constant expression, and are always evaluated at compile time. In -other places, such as in [`let` statements](statements.html#let-statements), -constant expressions may be evaluated at compile time. If errors, such as out -of bounds [array indexing] or [overflow] occurs, -then it is a compiler error if the value must be evaluated at compile time, -otherwise it is just a warning, but the code will most likely panic when run. - -The following expressions are constant expressions, so long as any operands are -also constant expressions and do not cause any [`Drop::drop`][destructors] calls -to be ran. - -* [Literals]. -* [Paths] to [functions](items/functions.html) and constants. - Recursively defining constants is not allowed. -* [Tuple expressions]. -* [Array expressions]. -* [Struct] expressions. -* [Enum variant] expressions. -* [Block expressions], including `unsafe` blocks, which only contain items and - possibly a constant tail expression. -* [Field] expressions. -* Index expressions, [array indexing] or [slice] with a `usize`. -* [Range expressions]. -* [Closure expressions] which don't capture variables from the environment. -* Built in [negation], [arithmetic, logical], [comparison] or [lazy boolean] - operators used on integer and floating point types, `bool` and `char`. -* Shared [borrow]s, except if applied to a type with [interior mutability]. -* The [dereference operator]. -* [Grouped] expressions. -* [Cast] expressions, except pointer to address and - function pointer to address casts. - ## Overloading Traits Many of the following operators and expressions can also be overloaded for @@ -313,6 +276,7 @@ exist in `core::ops` and `core::cmp` with the same names. [let]: statements.html#let-statements [let statement]: statements.html#let-statements [Mutable `static` items]: items/static-items.html#mutable-statics +[const contexts]: const_eval.html [slice]: types.html#array-and-slice-types [static variables]: items/static-items.html [Temporary values]: #temporary-lifetimes diff --git a/src/items/functions.md b/src/items/functions.md index 5fb071266e1fd..9c44fc49d7c77 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -8,7 +8,7 @@ > [_BlockExpression_] > > _FunctionFront_ :\ -> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup> +> `const`<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup> > > _Abi_ :\ > [STRING_LITERAL] | [RAW_STRING_LITERAL] @@ -160,6 +160,59 @@ attributes], [`must_use`], [the procedural macro attributes], [the testing attributes], and [the optimization hint attributes]. +## Const functions + +Functions can be `const`, meaning they can be called from within +[const contexts]. When called from a const context, the function is interpreted +by the compiler at compile time. The interpretation happens in the environment +of the compilation target and not the host. So `usize` is `32` bits if you are +compiling against a `32` bit system, irrelevant of whether you are building on +a `64` bit or a `32` bit system. + +If a const function is called outside a "const context", it is indistinguishable +from any other function. You can freely do anything with a const function that +you can do with a regular function. + +const functions have various restrictions to makes sure that you cannot define a +const function that can't be evaluated at compile-time. It is, for example, not +possible to write a random number generator as a const function. Calling a +const function at compile-time will always yield the same result as calling it at +runtime, even when called multiple times. There's one exception to this rule: +if you are doing complex floating point operations in extreme situations, +then you might get (very slightly) different results. +It is adviseable to not make array lengths and enum discriminants depend +on floating point computations. + +Exhaustive list of permitted structures in const functions: + +> **Note**: this list is more restrictive than what you can write in +> regular constants + +* type parameters where the parameters only have any [trait bounds] + of the following kind: + * lifetimes + * `Sized` or [`?Sized`] + + This means that `<T: 'a + ?Sized>`, `<T: 'b + Sized>` and `<T>` + are all permitted. + + This rule also applies to type parameters of impl blocks that + contain const methods + +* arithmetic and comparison operators on integers +* all boolean operators except for `&&` and `||` which are banned since + they are short-circuiting. +* any kind of aggregate constructor (array, `struct`, `enum`, tuple, ...) +* calls to other *safe* const functions (whether by function call or method call) +* index expressions on arrays and slices +* field accesses on structs and tuples +* reading from constants (but not statics, not even taking a reference to a static) +* `&` and `*` (only dereferencing of references, not raw pointers) +* casts except for raw pointer to integer casts +* `const unsafe fn` is allowed, but the body must consist of safe operations + only and you won't be able to call the `const unsafe fn` from within another + const function even if you use `unsafe` + [IDENTIFIER]: identifiers.html [RAW_STRING_LITERAL]: tokens.html#raw-string-literals [STRING_LITERAL]: tokens.html#string-literals @@ -170,6 +223,7 @@ attributes]. [_Statement_]: statements.html [_Type_]: types.html [_WhereClause_]: items/generics.html#where-clauses +[const contexts]: const_eval.html [external blocks]: items/external-blocks.html [path]: paths.html [block]: expressions/block-expr.html @@ -187,3 +241,5 @@ attributes]. [`doc`]: attributes.html#documentation [`must_use`]: attributes.html#must_use [patterns]: patterns.html +[`?Sized`]: trait-bounds.html#sized +[trait bounds]: trait-bounds.html