diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md
index 428f053ef..1b91188e8 100644
--- a/src/expressions/operator-expr.md
+++ b/src/expressions/operator-expr.md
@@ -338,7 +338,7 @@ well as the following additional casts. Here `*T` means either `*const T` or
| Type of `e` | `U` | Cast performed by `e as U` |
|-----------------------|-----------------------|----------------------------------|
| Integer or Float type | Integer or Float type | Numeric cast |
-| C-like enum | Integer type | Enum cast |
+| Field-less enum | Integer type | Enum cast |
| `bool` or `char` | Integer type | Primitive to integer cast |
| `u8` | `char` | `u8` to `char` cast |
| `*T` | `*V` where `V: Sized` \* | Pointer to pointer cast |
diff --git a/src/items/enumerations.md b/src/items/enumerations.md
index 258795503..f94c06d19 100644
--- a/src/items/enumerations.md
+++ b/src/items/enumerations.md
@@ -13,8 +13,8 @@
>
> _EnumItem_ :\
> _OuterAttribute_\*\
-> [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_
-> | _EnumItemDiscriminant_ )?
+> [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_ )?
+> _EnumItemDiscriminant_?
>
> _EnumItemTuple_ :\
> `(` [_TupleFields_]? `)`
@@ -56,22 +56,68 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
```
In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply
-called an enum variant. Each enum instance has a _discriminant_ which is an
-integer associated to it that is used to determine which variant it holds. An
-opaque reference to this discriminant can be obtained with the
-[`mem::discriminant`] function.
+called an enum variant.
-## Custom Discriminant Values for Field-Less Enumerations
+## Discriminants
-If there is no data attached to *any* of the variants of an enumeration,
-then the discriminant can be directly chosen and accessed.
+Each enum instance has a _discriminant_: an integer logically associated to it
+that is used to determine which variant it holds. An opaque reference to this
+discriminant can be obtained with the [`mem::discriminant`] function.
-These enumerations can be cast to integer types with the `as` operator by a
-[numeric cast]. The enumeration can optionally specify which integer each
-discriminant gets by following the variant name with `=` followed by a [constant
-expression]. If the first variant in the declaration is unspecified, then it is
-set to zero. For every other unspecified discriminant, it is set to one higher
-than the previous variant in the declaration.
+Under the [default representation], the discriminant is interpreted as
+an `isize` value. However, the compiler is allowed to use a smaller type (or
+another means of distinguishing variants) in its actual memory layout.
+
+If the [primitive representation] or the [`C` representation] is used, the
+leading bytes of a variant (for example, two bytes if `#[repr(u16)]` is used), will
+correspond exactly to the discriminant.
+
+### Assigning Discriminant Values
+
+#### Explicit Discriminants
+
+In two circumstances, the discriminant of a variant may be explicitly set by
+following the variant name with `=` and a [constant expression]:
+
+
+-
+
+if the enumeration is "C-like" (i.e., it has no tuple or struct variants); e.g.:
+
+```rust
+# #![feature(arbitrary_enum_discriminant)]
+enum Enum {
+ Foo = 3,
+ Bar = 2,
+ Baz = 1,
+}
+```
+
+-
+
+if a [primitive representation] is used. For example:
+
+```rust
+# #![feature(arbitrary_enum_discriminant)]
+#[repr(u8)]
+enum Enum {
+ Unit = 3,
+ Tuple(u16),
+ Struct {
+ a: u8,
+ b: u16,
+ } = 1,
+}
+```
+
+
+
+#### Implicit Discriminants
+
+If a discriminant for a variant is not specified, then it is set to one higher
+than the discriminant of the previous variant in the declaration. If the
+discriminant of the first variant in the declaration is unspecified, then
+it is set to zero.
```rust
enum Foo {
@@ -84,14 +130,11 @@ let baz_discriminant = Foo::Baz as u32;
assert_eq!(baz_discriminant, 123);
```
-Under the [default representation], the specified discriminant is interpreted as
-an `isize` value although the compiler is allowed to use a smaller type in the
-actual memory layout. The size and thus acceptable values can be changed by
-using a [primitive representation] or the [`C` representation].
+#### Restrictions
It is an error when two variants share the same discriminant.
-```rust,ignore
+```rust,compile_fail
enum SharedDiscriminantError {
SharedA = 1,
SharedB = 1
@@ -107,7 +150,7 @@ enum SharedDiscriminantError2 {
It is also an error to have an unspecified discriminant where the previous
discriminant is the maximum value for the size of the discriminant.
-```rust,ignore
+```rust,compile_fail
#[repr(u8)]
enum OverflowingDiscriminantError {
Max = 255,
@@ -122,6 +165,53 @@ enum OverflowingDiscriminantError2 {
}
```
+### Accessing Discriminant Values
+
+#### Casting
+
+If there is no data attached to *any* of the variants of an enumeration, then
+the discriminant can be directly accessed with a [numeric cast]; e.g.:
+
+```rust
+enum Enum {
+ Unit,
+ Tuple(),
+ Struct{},
+}
+
+assert_eq!(0, Enum::Unit as isize);
+assert_eq!(1, Enum::Tuple() as isize);
+assert_eq!(2, Enum::Struct{} as isize);
+```
+
+#### Pointer Casting
+
+If the enumeration specifies a [primitive representation], then the
+discriminant may be reliably accessed via unsafe pointer casting:
+
+```rust
+#[repr(u8)]
+enum Enum {
+ Unit,
+ Tuple(bool),
+ Struct{a: bool},
+}
+
+impl Enum {
+ fn discriminant(&self) -> u8 {
+ unsafe { *(self as *const Self as *const u8) }
+ }
+}
+
+let unit_like = Enum::Unit;
+let tuple_like = Enum::Tuple(true);
+let struct_like = Enum::Struct{a: false};
+
+assert_eq!(0, unit_like.discriminant());
+assert_eq!(1, tuple_like.discriminant());
+assert_eq!(2, struct_like.discriminant());
+```
+
## Zero-variant Enums
Enums with zero variants are known as *zero-variant enums*. As they have
diff --git a/src/type-layout.md b/src/type-layout.md
index fe611559f..e2cf0af60 100644
--- a/src/type-layout.md
+++ b/src/type-layout.md
@@ -357,7 +357,7 @@ used with any other representation.
[`size_of`]: ../std/mem/fn.size_of.html
[`Sized`]: ../std/marker/trait.Sized.html
[dynamically sized types]: dynamically-sized-types.html
-[C-like enumerations]: items/enumerations.html#custom-discriminant-values-for-field-less-enumerations
+[C-like enumerations]: items/enumerations.html#explicit-discriminants
[zero-variant enumerations]: items/enumerations.html#zero-variant-enums
[undefined behavior]: behavior-considered-undefined.html
[27060]: https://github.com/rust-lang/rust/issues/27060