diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 250824321920d..20c7d7dcec8d6 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -287,6 +287,7 @@ the source code. - `unsize`: `libcore/marker.rs` - `sync`: `libcore/marker.rs` - `phantom_data`: `libcore/marker.rs` + - `discriminant_kind`: `libcore/marker.rs` - `freeze`: `libcore/marker.rs` - `debug_trait`: `libcore/fmt/mod.rs` - `non_zero`: `libcore/nonzero.rs` diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a60380137e11e..9006e4cfaf7bb 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -54,6 +54,8 @@ )] #![allow(missing_docs)] +#[cfg(not(bootstrap))] +use crate::marker::DiscriminantKind; use crate::mem; #[stable(feature = "drop_in_place", since = "1.8.0")] @@ -1912,6 +1914,10 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html) #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] + #[cfg(not(bootstrap))] + pub fn discriminant_value(v: &T) -> ::Discriminant; + #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] + #[cfg(bootstrap)] pub fn discriminant_value(v: &T) -> u64; /// Rust's "try catch" construct which invokes the function pointer `try_fn` diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 339b07119c6d5..c0c0f66aff908 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -8,6 +8,7 @@ use crate::cell::UnsafeCell; use crate::cmp; +use crate::fmt::Debug; use crate::hash::Hash; use crate::hash::Hasher; @@ -679,6 +680,37 @@ mod impls { unsafe impl Send for &mut T {} } +/// Compiler-internal trait used to indicate the type of enum discriminants. +/// +/// This trait is automatically implemented for every type and does not add any +/// guarantees to [`mem::Discriminant`]. It is **undefined behavior** to transmute +/// between `DiscriminantKind::Discriminant` and `mem::Discriminant`. +/// +/// [`mem::Discriminant`]: https://doc.rust-lang.org/stable/core/mem/struct.Discriminant.html +#[unstable( + feature = "discriminant_kind", + issue = "none", + reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" +)] +#[cfg_attr(not(bootstrap), lang = "discriminant_kind")] +pub trait DiscriminantKind { + /// The type of the dicriminant, which must satisfy the trait + /// bounds required by `mem::Discriminant`. + type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin; +} + +// Manually implement `DiscriminantKind` for all types during bootstrap +// to reduce the required amount of conditional compilation. +#[unstable( + feature = "discriminant_kind", + issue = "none", + reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" +)] +#[cfg(bootstrap)] +impl DiscriminantKind for T { + type Discriminant = u64; +} + /// Compiler-internal trait used to determine whether a type contains /// any `UnsafeCell` internally, but not through an indirection. /// This affects, for example, whether a `static` of that type is diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index b1bbcaeab8def..010f2958e36b9 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -10,7 +10,7 @@ use crate::cmp; use crate::fmt; use crate::hash; use crate::intrinsics; -use crate::marker::{Copy, PhantomData, Sized}; +use crate::marker::{Copy, DiscriminantKind, Sized}; use crate::ptr; mod manually_drop; @@ -930,7 +930,7 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// /// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] -pub struct Discriminant(u64, PhantomData T>); +pub struct Discriminant(::Discriminant); // N.B. These trait implementations cannot be derived because we don't want any bounds on T. @@ -995,5 +995,5 @@ impl fmt::Debug for Discriminant { #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub const fn discriminant(v: &T) -> Discriminant { - Discriminant(intrinsics::discriminant_value(v), PhantomData) + Discriminant(intrinsics::discriminant_value(v)) } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 53f72804a848d..04fe3b60b6a87 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -163,6 +163,7 @@ language_item_table! { CopyTraitLangItem, "copy", copy_trait, Target::Trait; CloneTraitLangItem, "clone", clone_trait, Target::Trait; SyncTraitLangItem, "sync", sync_trait, Target::Trait; + DiscriminantKindTraitLangItem,"discriminant_kind", discriminant_kind_trait, Target::Trait; FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait; DropTraitLangItem, "drop", drop_trait, Target::Trait; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index db6c30adb04cc..68f9025fd19e1 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_target::spec::abi::Abi; use std::iter; @@ -283,14 +283,20 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { "likely" => (0, vec![tcx.types.bool], tcx.types.bool), "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool), - "discriminant_value" => ( - 1, - vec![tcx.mk_imm_ref( - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))), - param(0), - )], - tcx.types.u64, - ), + "discriminant_value" => { + let assoc_items = + tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); + let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + + ( + 1, + vec![tcx.mk_imm_ref( + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))), + param(0), + )], + tcx.mk_projection(discriminant_def_id, tcx.mk_substs([param(0).into()].iter())), + ) + } "try" => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);