diff --git a/src/items/generics.md b/src/items/generics.md
index 789563c8a..a7de436ec 100644
--- a/src/items/generics.md
+++ b/src/items/generics.md
@@ -17,8 +17,8 @@
> _ConstParam_:\
> `const` [IDENTIFIER] `:` [_Type_]
-Functions, type aliases, structs, enumerations, unions, traits, and
-implementations may be *parameterized* by types, constants, and lifetimes. These
+[Functions], [type aliases], [structs], [enumerations], [unions], [traits], and
+[implementations] may be *parameterized* by types, constants, and lifetimes. These
parameters are listed in angle brackets (`<...>`),
usually immediately after the name of the item and before its definition. For
implementations, which don't have a name, they come directly after `impl`.
@@ -33,22 +33,147 @@ struct Ref<'a, T> where T: 'a { r: &'a T }
struct InnerArray([T; N]);
```
+Generic parameters are in scope within the item definition where they are
+declared. They are not in scope for items declared within the body of a
+function as described in [item declarations].
+
+[References], [raw pointers], [arrays], [slices][arrays], [tuples], and
+[function pointers] have lifetime or type parameters as well, but are not
+referred to with path syntax.
+
+### Const generics
+
+*Const generic parameters* allow items to be generic over constant values. The
+const identifier introduces a name for the constant parameter, and all
+instances of the item must be instantiated with a value of the given type.
+
+
+
The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`
`i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`.
-Const parameters may only be be used as standalone arguments inside
-of [types] and [repeat expressions] but may be freely used elsewhere:
+Const parameters can be used anywhere a [const item] can be used, with the
+exception that when used in a [type] or [array repeat expression], it must be
+standalone (as described below). That is, they are allowed in the following
+places:
+
+1. As an applied const to any type which forms a part of the signature of the
+ item in question.
+2. As part of a const expression used to define an [associated const], or as a
+ parameter to an [associated type].
+3. As a value in any runtime expression in the body of any functions in the
+ item.
+4. As a parameter to any type used in the body of any functions in the item.
+5. As a part of the type of any fields in the item.
+
+```rust
+// Examples where const generic parameters can be used.
+
+// Used in the signature of the item itself.
+fn foo(arr: [i32; N]) {
+ // Used as a type within a function body.
+ let x: [i32; N];
+ // Used as an expression.
+ println!("{}", N * 2);
+}
+
+// Used as a field of a struct.
+struct Foo([i32; N]);
+
+impl Foo {
+ // Used as an associated constant.
+ const CONST: usize = N * 4;
+}
+
+trait Trait {
+ type Output;
+}
+
+impl Trait for Foo {
+ // Used as an associated type.
+ type Output = [i32; N];
+}
+```
+
+```rust,compile_fail
+// Examples where const generic parameters cannot be used.
+fn foo() {
+ // Cannot use in item definitions within a function body.
+ const BAD_CONST: [usize; N] = [1; N];
+ static BAD_STATIC: [usize; N] = [1; N];
+ fn inner(bad_arg: [usize; N]) {
+ let bad_value = N * 2;
+ }
+ type BadAlias = [usize; N];
+ struct BadStruct([usize; N]);
+}
+```
+
+As a further restriction, const parameters may only appear as a standalone
+argument inside of a [type] or [array repeat expression]. In those contexts,
+they may only be used as a single segment [path expression], possibly inside a
+[block] (such as `N` or `{N}`). That is, they cannot be combined with other
+expressions.
```rust,compile_fail
-// ok: standalone argument
-fn foo() -> [u8; N] { todo!() }
+// Examples where const parameters may not be used.
-// ERROR: generic const operation
-fn bar() -> [u8; N + 1] { todo!() }
+// Not allowed to combine in other expressions in types, such as the
+// arithmetic expression in the return type here.
+fn bad_function() -> [u8; {N + 1}] {
+ // Similarly not allowed for array repeat expressions.
+ [1; {N + 1}]
+}
```
-Unlike type and lifetime parameters, const parameters of types can be used without
-being mentioned inside of a parameterized type:
+A const argument in a [path] specifies the const value to use for that item.
+The argument must be a [const expression] of the type ascribed to the const
+parameter. The const expression must be a [block expression][block]
+(surrounded with braces) unless it is a single path segment (an [IDENTIFIER])
+or a [literal] (with a possibly leading `-` token).
+
+> **Note**: This syntactic restriction is necessary to avoid requiring
+> infinite lookahead when parsing an expression inside of a type.
+
+```rust
+fn double() {
+ println!("doubled: {}", N * 2);
+}
+
+const SOME_CONST: i32 = 12;
+
+fn example() {
+ // Example usage of a const argument.
+ double::<9>();
+ double::<-123>();
+ double::<{7 + 8}>();
+ double::();
+ double::<{ SOME_CONST + 5 }>();
+}
+```
+
+When there is ambiguity if a generic argument could be resolved as either a
+type or const argument, it is always resolved as a type. Placing the argument
+in a block expression can force it to be interpreted as a const argument.
+
+
+
+```rust,compile_fail
+type N = u32;
+struct Foo;
+// The following is an error, because `N` is interpreted as the type alias `N`.
+fn foo() -> Foo { todo!() } // ERROR
+// Can be fixed by wrapping in braces to force it to be interprted as the `N`
+// const parameter:
+fn bar() -> Foo<{ N }> { todo!() } // ok
+```
+
+Unlike type and lifetime parameters, const parameters can be declared without
+being used inside of a parameterized item, with the exception of
+implementations as described in [generic implementations]:
```rust,compile_fail
// ok
@@ -58,11 +183,29 @@ enum Bar { A, B }
// ERROR: unused parameter
struct Baz;
struct Biz<'a>;
+struct Unconstrained;
+impl Unconstrained {}
+```
+
+When resolving a trait bound obligation, the exhaustiveness of all
+implementations of const parameters is not considered when determining if the
+bound is satisfied. For example, in the following, even though all possible
+const values for the `bool` type are implemented, it is still an error that
+the trait bound is not satisfied:
+
+```rust,compile_fail
+struct Foo;
+trait Bar {}
+impl Bar for Foo {}
+impl Bar for Foo {}
+
+fn needs_bar(_: impl Bar) {}
+fn generic() {
+ let v = Foo::;
+ needs_bar(v); // ERROR: trait bound `Foo: Bar` is not satisfied
+}
```
-[References], [raw pointers], [arrays], [slices][arrays], [tuples], and
-[function pointers] have lifetime or type parameters as well, but are not
-referred to with path syntax.
## Where clauses
@@ -90,7 +233,7 @@ parameters.
The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only
allows [_LifetimeParam_] parameters.
-Bounds that don't use the item's parameters or higher-ranked lifetimes are
+Bounds that don't use the item's parameters or [higher-ranked lifetimes] are
checked when the item is defined. It is an error for such a bound to be false.
[`Copy`], [`Clone`], and [`Sized`] bounds are also checked for certain generic
@@ -141,17 +284,35 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
[_Type_]: ../types.md#type-expressions
[_TypeParamBounds_]: ../trait-bounds.md
+[array repeat expression]: ../expressions/array-expr.md
[arrays]: ../types/array.md
+[associated const]: associated-items.md#associated-constants
+[associated type]: associated-items.md#associated-types
+[block]: ../expressions/block-expr.md
[const contexts]: ../const_eval.md#const-context
+[const expression]: ../const_eval.md#constant-expressions
+[const item]: constant-items.md
+[enumerations]: enumerations.md
+[functions]: functions.md
[function pointers]: ../types/function-pointer.md
+[generic implementations]: implementations.md#generic-implementations
[higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds
+[implementations]: implementations.md
+[item declarations]: ../statements.md#item-declarations
+[item]: ../items.md
+[literal]: ../expressions/literal-expr.md
+[path]: ../paths.md
+[path expression]: ../expressions/path-expr.md
[raw pointers]: ../types/pointer.md#raw-pointers-const-and-mut
[references]: ../types/pointer.md#shared-references-
-[repeat expressions]: ../expressions/array-expr.md
[`Clone`]: ../special-types-and-traits.md#clone
[`Copy`]: ../special-types-and-traits.md#copy
[`Sized`]: ../special-types-and-traits.md#sized
+[structs]: structs.md
[tuples]: ../types/tuple.md
[trait object]: ../types/trait-object.md
-[types]: ../types.md
+[traits]: traits.md
+[type aliases]: type-aliases.md
+[type]: ../types.md
+[unions]: unions.md
[attributes]: ../attributes.md
diff --git a/src/items/implementations.md b/src/items/implementations.md
index 976241481..33f7c84d9 100644
--- a/src/items/implementations.md
+++ b/src/items/implementations.md
@@ -180,11 +180,11 @@ is considered local.
## Generic Implementations
-An implementation can take type and lifetime parameters, which can be used in
-the rest of the implementation. Type parameters declared for an implementation
-must be used at least once in either the trait or the implementing type of an
-implementation. Implementation parameters are written directly after the `impl`
-keyword.
+An implementation can take [generic parameters] which are written directly
+after the `impl` keyword. The parameters can be used in the rest of the
+implementation. Type and const parameters must be used at least once in either
+the trait or the implementing type of an implementation. Lifetime parameters
+do not need to be used unless they appear in an [associated type].
```rust
# trait Seq { fn dummy(&self, _: T) { } }
@@ -219,6 +219,7 @@ attributes].
[trait]: traits.md
[associated functions]: associated-items.md#associated-functions-and-methods
[associated constants]: associated-items.md#associated-constants
+[associated type]: associated-items.md#associated-types
[attributes]: ../attributes.md
[`cfg`]: ../conditional-compilation.md
[`deprecated`]: ../attributes/diagnostics.md#the-deprecated-attribute
@@ -230,3 +231,4 @@ attributes].
[local type]: ../glossary.md#local-type
[fundamental types]: ../glossary.md#fundamental-type-constructors
[uncovered type]: ../glossary.md#uncovered-type
+[generic parameters]: generics.md