r[const-eval]
# Constant evaluation

r[const-eval.general]
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.

r[const-eval.const-expr]
## Constant expressions

r[const-eval.const-expr.general]
Certain forms of expressions, called constant expressions, can be evaluated at
compile time.

r[const-eval.const-expr.const-context]
In [const contexts](#const-context), these are the only allowed
expressions, and are always evaluated at compile time.

r[const-eval.const-expr.runtime-context]
In other places, such as [let statements], constant expressions *may* be, but are not guaranteed to be, evaluated at compile time.

r[const-eval.const-expr.error]
Behaviors such as out of bounds [array indexing] or [overflow] are compiler errors if the value
must be evaluated at compile time (i.e. in const contexts). Otherwise, these
behaviors are warnings, but will likely panic at run-time.

r[const-eval.const-expr.list]
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 run.

r[const-eval.const-expr.literal]
* [Literals].

r[const-eval.const-expr.parameter]
* [Const parameters].

r[const-eval.const-expr.path-item]
* [Paths] to [functions] and [constants].
  Recursively defining constants is not allowed.

r[const-eval.const-expr.path-static]
* Paths to [statics] with these restrictions:
  * Writes to `static` items are not allowed in any constant evaluation context.
  * Reads from `extern` statics are not allowed in any constant evaluation context.
  * If the evaluation is *not* carried out in an initializer of a `static` item, then reads from any mutable `static` are not allowed. A mutable `static` is a `static mut` item, or a `static` item with an interior-mutable type.

These requirements are checked only when the constant is evaluated. In other words, having such accesses syntactically occur in const contexts is allowed as long as they never get executed.

r[const-eval.const-expr.tuple]
* [Tuple expressions].

r[const-eval.const-expr.array]
* [Array expressions].

r[const-eval.const-expr.constructor]
* [Struct] expressions.

r[const-eval.const-expr.block]
* [Block expressions], including `unsafe` and `const` blocks.
    * [let statements] and thus irrefutable [patterns], including mutable bindings
    * [assignment expressions]
    * [compound assignment expressions]
    * [expression statements]

r[const-eval.const-expr.field]
* [Field] expressions.

r[const-eval.const-expr.index]
* Index expressions, [array indexing] or [slice] with a `usize`.

r[const-eval.const-expr.range]
* [Range expressions].

r[const-eval.const-expr.closure]
* [Closure expressions] which don't capture variables from the environment.

r[const-eval.const-expr.builtin-arith-logic]
* Built-in [negation], [arithmetic], [logical], [comparison] or [lazy boolean]
  operators used on integer and floating point types, `bool`, and `char`.

r[const-eval.const-expr.borrows]
* All forms of [borrow]s, including raw borrows, with one limitation:
  mutable borrows and shared borrows to values with interior mutability
  are only allowed to refer to *transient* places or to *static* places. A place is *transient*
  if its lifetime is strictly contained inside the current [const context].
  A place is *static* if it is a `static` item or a [promoted expression].

r[const-eval.const-expr.deref]
* The [dereference operator] except for raw pointers.

r[const-eval.const-expr.group]

* [Grouped] expressions.

r[const-eval.const-expr.cast]
* [Cast] expressions, except
  * pointer to address casts and
  * function pointer to address casts.

r[const-eval.const-expr.const-fn]
* Calls of [const functions] and const methods.

r[const-eval.const-expr.loop]
* [loop] and [while] expressions.

r[const-eval.const-expr.if-match]
* [if] and [match] expressions.

r[const-eval.const-context]
## Const context
[const context]: #const-context

r[const-eval.const-context.general]
A _const context_ is one of the following:

r[const-eval.const-context.array-length]
* [Array type length expressions]

r[const-eval.const-context.repeat-length]
* [Array repeat length expressions][array expressions]

r[const-eval.const-context.init]
* The initializer of
  * [constants]
  * [statics]
  * [enum discriminants]

r[const-eval.const-context.generic]
* A [const generic argument]

r[const-eval.const-context.block]
* A [const block]

Const contexts that are used as parts of types (array type and repeat length
expressions as well as const generic arguments) can only make restricted use of
surrounding generic parameters: such an expression must either be a single bare
const generic parameter, or an arbitrary expression not making use of any
generics.

r[const-eval.const-fn]
## Const Functions

r[const-eval.const-fn.general]
A _const fn_ is a function that one is permitted to call from a const context.

r[const-eval.const-fn.usage]
Declaring a function
`const` has no effect on any existing uses, it only restricts the types that arguments and the
return type may use, and restricts the function body to constant expressions.

r[const-eval.const-fn.const-context]
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.

[arithmetic]:           expressions/operator-expr.md#arithmetic-and-logical-binary-operators
[array expressions]:    expressions/array-expr.md
[array indexing]:       expressions/array-expr.md#array-and-slice-indexing-expressions
[array indexing]:       expressions/array-expr.md#array-and-slice-indexing-expressions
[array type length expressions]: types/array.md
[assignment expressions]: expressions/operator-expr.md#assignment-expressions
[compound assignment expressions]: expressions/operator-expr.md#compound-assignment-expressions
[block expressions]:    expressions/block-expr.md
[borrow]:               expressions/operator-expr.md#borrow-operators
[cast]:                 expressions/operator-expr.md#type-cast-expressions
[closure expressions]:  expressions/closure-expr.md
[comparison]:           expressions/operator-expr.md#comparison-operators
[const block]:          expressions/block-expr.md#const-blocks
[const functions]:      items/functions.md#const-functions
[const generic argument]: items/generics.md#const-generics
[const generic parameters]: items/generics.md#const-generics
[constants]:            items/constant-items.md
[Const parameters]:     items/generics.md
[dereference operator]: expressions/operator-expr.md#the-dereference-operator
[destructors]:          destructors.md
[enum discriminants]:   items/enumerations.md#discriminants
[expression statements]: statements.md#expression-statements
[expressions]:          expressions.md
[`extern` statics]:     items/external-blocks.md#statics
[field]:                expressions/field-expr.md
[functions]:            items/functions.md
[grouped]:              expressions/grouped-expr.md
[interior mutability]:  interior-mutability.md
[if]:                   expressions/if-expr.md#if-expressions
[lazy boolean]:         expressions/operator-expr.md#lazy-boolean-operators
[let statements]:       statements.md#let-statements
[literals]:             expressions/literal-expr.md
[logical]:              expressions/operator-expr.md#arithmetic-and-logical-binary-operators
[loop]:                 expressions/loop-expr.md#infinite-loops
[match]:                expressions/match-expr.md
[negation]:             expressions/operator-expr.md#negation-operators
[overflow]:             expressions/operator-expr.md#overflow
[paths]:                expressions/path-expr.md
[patterns]:             patterns.md
[promoted expression]:  destructors.md#constant-promotion
[range expressions]:    expressions/range-expr.md
[slice]:                types/slice.md
[statics]:              items/static-items.md
[struct]:               expressions/struct-expr.md
[tuple expressions]:    expressions/tuple-expr.md
[while]:                expressions/loop-expr.md#predicate-loops
