@@ -1113,7 +1113,10 @@ impl<T> fmt::Debug for Discriminant<T> {
11131113/// # Stability
11141114///
11151115/// The discriminant of an enum variant may change if the enum definition changes. A discriminant
1116- /// of some variant will not change between compilations with the same compiler.
1116+ /// of some variant will not change between compilations with the same compiler. See the [Reference]
1117+ /// for more information.
1118+ ///
1119+ /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
11171120///
11181121/// # Examples
11191122///
@@ -1129,6 +1132,62 @@ impl<T> fmt::Debug for Discriminant<T> {
11291132/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2)));
11301133/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
11311134/// ```
1135+ ///
1136+ /// ## Accessing the numeric value of the discriminant
1137+ ///
1138+ /// Note that it is *undefined behavior* to [`transmute`] from [`Discriminant`] to a primitive!
1139+ ///
1140+ /// If an enum has only unit variants, then the numeric value of the discriminant can be accessed
1141+ /// with an [`as`] cast:
1142+ ///
1143+ /// ```
1144+ /// enum Enum {
1145+ /// Foo,
1146+ /// Bar,
1147+ /// Baz,
1148+ /// }
1149+ ///
1150+ /// assert_eq!(0, Enum::Foo as isize);
1151+ /// assert_eq!(1, Enum::Bar as isize);
1152+ /// assert_eq!(2, Enum::Baz as isize);
1153+ /// ```
1154+ ///
1155+ /// If an enum has opted-in to having a [primitive representation] for its discriminant,
1156+ /// then it's possible to use pointers to read the memory location storing the discriminant.
1157+ /// That **cannot** be done for enums using the [default representation], however, as it's
1158+ /// undefined what layout the discriminant has and where it's stored — it might not even be
1159+ /// stored at all!
1160+ ///
1161+ /// [`as`]: ../../std/keyword.as.html
1162+ /// [primitive representation]: ../../reference/type-layout.html#primitive-representations
1163+ /// [default representation]: ../../reference/type-layout.html#the-default-representation
1164+ /// ```
1165+ /// #[repr(u8)]
1166+ /// enum Enum {
1167+ /// Unit,
1168+ /// Tuple(bool),
1169+ /// Struct { a: bool },
1170+ /// }
1171+ ///
1172+ /// impl Enum {
1173+ /// fn discriminant(&self) -> u8 {
1174+ /// // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)` `union`
1175+ /// // between `repr(C)` structs, each of which has the `u8` discriminant as its first
1176+ /// // field, so we can read the discriminant without offsetting the pointer.
1177+ /// unsafe { *<*const _>::from(self).cast::<u8>() }
1178+ /// }
1179+ /// }
1180+ ///
1181+ /// let unit_like = Enum::Unit;
1182+ /// let tuple_like = Enum::Tuple(true);
1183+ /// let struct_like = Enum::Struct { a: false };
1184+ /// assert_eq!(0, unit_like.discriminant());
1185+ /// assert_eq!(1, tuple_like.discriminant());
1186+ /// assert_eq!(2, struct_like.discriminant());
1187+ ///
1188+ /// // ⚠️ This is undefined behavior. Don't do this. ⚠️
1189+ /// // assert_eq!(0, unsafe { std::mem::transmute::<_, u8>(std::mem::discriminant(&unit_like)) });
1190+ /// ```
11321191#[ stable( feature = "discriminant_value" , since = "1.21.0" ) ]
11331192#[ rustc_const_unstable( feature = "const_discriminant" , issue = "69821" ) ]
11341193#[ cfg_attr( not( test) , rustc_diagnostic_item = "mem_discriminant" ) ]
0 commit comments