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_ :\
-> &nbsp;&nbsp; `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
+> &nbsp;&nbsp; `const`<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
 >
 > _Abi_ :\
 > &nbsp;&nbsp; [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