about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-21 03:48:47 +0000
committerbors <bors@rust-lang.org>2020-05-21 03:48:47 +0000
commit963bf528292d8f97104515e32908e30c2467b6a8 (patch)
treee6f2a5cf24832f59d7a8f86857b23dc95598016c
parent82911b3bba76e73afe2881b732fe6b0edb35d5d3 (diff)
parent08b9b97c5374f4a7523cbb189bbe0ab1ed80ed64 (diff)
Auto merge of #70705 - lcnr:generic_discriminant, r=nikomatsakis
Use `T`'s discriminant type in `mem::Discriminant<T>` instead of `u64`.

fixes #70509

Adds the lang-item `discriminant_kind`.
Updates the function signature of `intrinsics::discriminant_value`.
Adds the *probably permanently unstable* trait `DiscriminantKind`.
`mem::Discriminant` should now be smaller in some cases.

r? @ghost
-rw-r--r--src/doc/unstable-book/src/language-features/lang-items.md1
-rw-r--r--src/libcore/intrinsics.rs6
-rw-r--r--src/libcore/marker.rs32
-rw-r--r--src/libcore/mem/mod.rs6
-rw-r--r--src/librustc_builtin_macros/deriving/generic/mod.rs80
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs12
-rw-r--r--src/librustc_hir/lang_items.rs1
-rw-r--r--src/librustc_middle/lib.rs1
-rw-r--r--src/librustc_middle/traits/mod.rs12
-rw-r--r--src/librustc_middle/traits/select.rs35
-rw-r--r--src/librustc_middle/traits/structural_impls.rs5
-rw-r--r--src/librustc_middle/ty/codec.rs6
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs9
-rw-r--r--src/librustc_trait_selection/traits/project.rs85
-rw-r--r--src/librustc_trait_selection/traits/select.rs37
-rw-r--r--src/librustc_ty/instance.rs5
-rw-r--r--src/librustc_typeck/check/intrinsic.rs22
-rw-r--r--src/librustc_typeck/coherence/mod.rs15
-rw-r--r--src/test/ui/enum-discriminant/actually_not_an_enum-discriminant.rs49
-rw-r--r--src/test/ui/enum-discriminant/discriminant_size.rs53
-rw-r--r--src/test/ui/enum-discriminant/discriminant_value.rs22
-rw-r--r--src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.rs14
-rw-r--r--src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.stderr9
-rw-r--r--src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs2
-rw-r--r--src/test/ui/enum-discriminant/issue-70509-partial_eq.rs17
-rw-r--r--src/test/ui/enum-discriminant/repr128.rs44
-rw-r--r--src/test/ui/generator/discriminant.rs9
27 files changed, 450 insertions, 139 deletions
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 25082432192..20c7d7dcec8 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 a60380137e1..9006e4cfaf7 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<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
+    #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
+    #[cfg(bootstrap)]
     pub fn discriminant_value<T>(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 339b07119c6..c0c0f66aff9 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<T: Send + ?Sized> 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<T: ?Sized> 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 b1bbcaeab8d..010f2958e36 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<T, U>(src: &T) -> U {
 ///
 /// [`discriminant`]: fn.discriminant.html
 #[stable(feature = "discriminant_value", since = "1.21.0")]
-pub struct Discriminant<T>(u64, PhantomData<fn() -> T>);
+pub struct Discriminant<T>(<T as DiscriminantKind>::Discriminant);
 
 // N.B. These trait implementations cannot be derived because we don't want any bounds on T.
 
@@ -995,5 +995,5 @@ impl<T> fmt::Debug for Discriminant<T> {
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
 pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
-    Discriminant(intrinsics::discriminant_value(v), PhantomData)
+    Discriminant(intrinsics::discriminant_value(v))
 }
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index 0ba9df08383..a9567f20d69 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -187,7 +187,6 @@ use rustc_ast::ptr::P;
 use rustc_attr as attr;
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_session::parse::ParseSess;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -437,14 +436,7 @@ impl<'a> TraitDef<'a> {
                         // This can only cause further compilation errors
                         // downstream in blatantly illegal code, so it
                         // is fine.
-                        self.expand_enum_def(
-                            cx,
-                            enum_def,
-                            &item.attrs,
-                            item.ident,
-                            generics,
-                            from_scratch,
-                        )
+                        self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
                     }
                     ast::ItemKind::Union(ref struct_def, ref generics) => {
                         if self.supports_unions {
@@ -769,7 +761,6 @@ impl<'a> TraitDef<'a> {
         &self,
         cx: &mut ExtCtxt<'_>,
         enum_def: &'a EnumDef,
-        type_attrs: &[ast::Attribute],
         type_ident: Ident,
         generics: &Generics,
         from_scratch: bool,
@@ -801,7 +792,6 @@ impl<'a> TraitDef<'a> {
                         cx,
                         self,
                         enum_def,
-                        type_attrs,
                         type_ident,
                         self_args,
                         &nonself_args[..],
@@ -816,38 +806,6 @@ impl<'a> TraitDef<'a> {
     }
 }
 
-fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'static str {
-    let mut repr_type_name = "isize";
-    for a in type_attrs {
-        for r in &attr::find_repr_attrs(sess, a) {
-            repr_type_name = match *r {
-                attr::ReprPacked(_)
-                | attr::ReprSimd
-                | attr::ReprAlign(_)
-                | attr::ReprTransparent
-                | attr::ReprNoNiche => continue,
-
-                attr::ReprC => "i32",
-
-                attr::ReprInt(attr::SignedInt(ast::IntTy::Isize)) => "isize",
-                attr::ReprInt(attr::SignedInt(ast::IntTy::I8)) => "i8",
-                attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16",
-                attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32",
-                attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64",
-                attr::ReprInt(attr::SignedInt(ast::IntTy::I128)) => "i128",
-
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::Usize)) => "usize",
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8",
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16",
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32",
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64",
-                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128",
-            }
-        }
-    }
-    repr_type_name
-}
-
 impl<'a> MethodDef<'a> {
     fn call_substructure_method(
         &self,
@@ -1148,20 +1106,11 @@ impl<'a> MethodDef<'a> {
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         enum_def: &'b EnumDef,
-        type_attrs: &[ast::Attribute],
         type_ident: Ident,
         self_args: Vec<P<Expr>>,
         nonself_args: &[P<Expr>],
     ) -> P<Expr> {
-        self.build_enum_match_tuple(
-            cx,
-            trait_,
-            enum_def,
-            type_attrs,
-            type_ident,
-            self_args,
-            nonself_args,
-        )
+        self.build_enum_match_tuple(cx, trait_, enum_def, type_ident, self_args, nonself_args)
     }
 
     /// Creates a match for a tuple of all `self_args`, where either all
@@ -1181,11 +1130,11 @@ impl<'a> MethodDef<'a> {
 
     /// ```{.text}
     /// let __self0_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&self) } as i32;
+    ///     std::intrinsics::discriminant_value(&self) };
     /// let __self1_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg1) } as i32;
+    ///     std::intrinsics::discriminant_value(&arg1) };
     /// let __self2_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg2) } as i32;
+    ///     std::intrinsics::discriminant_value(&arg2) };
     ///
     /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
     ///     match (...) {
@@ -1204,7 +1153,6 @@ impl<'a> MethodDef<'a> {
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         enum_def: &'b EnumDef,
-        type_attrs: &[ast::Attribute],
         type_ident: Ident,
         mut self_args: Vec<P<Expr>>,
         nonself_args: &[P<Expr>],
@@ -1392,21 +1340,18 @@ impl<'a> MethodDef<'a> {
         //
         if variants.len() > 1 && self_args.len() > 1 {
             // Build a series of let statements mapping each self_arg
-            // to its discriminant value. If this is a C-style enum
-            // with a specific repr type, then casts the values to
-            // that type.  Otherwise casts to `i32` (the default repr
-            // type).
+            // to its discriminant value.
             //
             // i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
             // with three Self args, builds three statements:
             //
             // ```
             // let __self0_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&self) } as i32;
+            //     std::intrinsics::discriminant_value(&self) };
             // let __self1_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg1) } as i32;
+            //     std::intrinsics::discriminant_value(&arg1) };
             // let __self2_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg2) } as i32;
+            //     std::intrinsics::discriminant_value(&arg2) };
             // ```
             let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
 
@@ -1414,17 +1359,12 @@ impl<'a> MethodDef<'a> {
             // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
             let mut discriminant_test = cx.expr_bool(sp, true);
 
-            let target_type_name = find_repr_type_name(&cx.parse_sess, type_attrs);
-
             let mut first_ident = None;
             for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
                 let self_addr = cx.expr_addr_of(sp, self_arg.clone());
                 let variant_value =
                     deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]);
-
-                let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name, sp));
-                let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
-                let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
+                let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
                 index_let_stmts.push(let_stmt);
 
                 match first_ident {
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index ddf21ff6338..1e6d2e3dbb7 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -188,11 +188,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             }
             "size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id"
             | "type_name" => {
-                let ty_name = self
+                let value = self
                     .tcx
                     .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
                     .unwrap();
-                OperandRef::from_const(self, ty_name, ret_ty).immediate_or_packed_pair(self)
+                OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self)
             }
             // Effectively no-op
             "forget" => {
@@ -549,7 +549,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 }
             }
 
-            "discriminant_value" => args[0].deref(self.cx()).codegen_get_discr(self, ret_ty),
+            "discriminant_value" => {
+                if ret_ty.is_integral() {
+                    args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
+                } else {
+                    span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0])
+                }
+            }
 
             name if name.starts_with("simd_") => {
                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs
index 53f72804a84..04fe3b60b6a 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_middle/lib.rs b/src/librustc_middle/lib.rs
index d0f627d8bc5..7c433574d18 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -32,6 +32,7 @@
 #![feature(const_panic)]
 #![feature(const_transmute)]
 #![feature(core_intrinsics)]
+#![feature(discriminant_kind)]
 #![feature(drain_filter)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index adbeac29bdd..9afab5a4d2f 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -411,6 +411,9 @@ pub enum Vtable<'tcx, N> {
     /// Same as above, but for a function pointer type with the given signature.
     VtableFnPointer(VtableFnPointerData<'tcx, N>),
 
+    /// Vtable for a builtin `DeterminantKind` trait implementation.
+    VtableDiscriminantKind(VtableDiscriminantKindData),
+
     /// Vtable automatically generated for a generator.
     VtableGenerator(VtableGeneratorData<'tcx, N>),
 
@@ -429,6 +432,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
             VtableGenerator(c) => c.nested,
             VtableObject(d) => d.nested,
             VtableFnPointer(d) => d.nested,
+            VtableDiscriminantKind(VtableDiscriminantKindData) => Vec::new(),
             VtableTraitAlias(d) => d.nested,
         }
     }
@@ -443,6 +447,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
             VtableGenerator(c) => &c.nested[..],
             VtableObject(d) => &d.nested[..],
             VtableFnPointer(d) => &d.nested[..],
+            VtableDiscriminantKind(VtableDiscriminantKindData) => &[],
             VtableTraitAlias(d) => &d.nested[..],
         }
     }
@@ -484,6 +489,9 @@ impl<'tcx, N> Vtable<'tcx, N> {
                 fn_ty: p.fn_ty,
                 nested: p.nested.into_iter().map(f).collect(),
             }),
+            VtableDiscriminantKind(VtableDiscriminantKindData) => {
+                VtableDiscriminantKind(VtableDiscriminantKindData)
+            }
             VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
                 alias_def_id: d.alias_def_id,
                 substs: d.substs,
@@ -560,6 +568,10 @@ pub struct VtableFnPointerData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
+// FIXME(@lcnr): This should be  refactored and merged with other builtin vtables.
+#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct VtableDiscriminantKindData;
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
 pub struct VtableTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
diff --git a/src/librustc_middle/traits/select.rs b/src/librustc_middle/traits/select.rs
index d316d7659e2..a12f5910b14 100644
--- a/src/librustc_middle/traits/select.rs
+++ b/src/librustc_middle/traits/select.rs
@@ -34,7 +34,7 @@ impl<'tcx> SelectionCache<'tcx> {
 /// clauses, and so forth that might resolve an obligation. Sometimes
 /// we'll be able to say definitively that (e.g.) an impl does not
 /// apply to the obligation: perhaps it is defined for `usize` but the
-/// obligation is for `int`. In that case, we drop the impl out of the
+/// obligation is for `i32`. In that case, we drop the impl out of the
 /// list. But the other cases are considered *candidates*.
 ///
 /// For selection to succeed, there must be exactly one matching
@@ -54,12 +54,14 @@ impl<'tcx> SelectionCache<'tcx> {
 /// will always be satisfied) picking the blanket impl will be wrong
 /// for at least *some* substitutions. To make this concrete, if we have
 ///
-///    trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
-///    impl<T: fmt::Debug> AsDebug for T {
-///        type Out = T;
-///        fn debug(self) -> fmt::Debug { self }
-///    }
-///    fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
+/// ```rust, ignore
+/// trait AsDebug { type Out: fmt::Debug; fn debug(self) -> Self::Out; }
+/// impl<T: fmt::Debug> AsDebug for T {
+///     type Out = T;
+///     fn debug(self) -> fmt::Debug { self }
+/// }
+/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
+/// ```
 ///
 /// we can't just use the impl to resolve the `<T as AsDebug>` obligation
 /// -- a type from another crate (that doesn't implement `fmt::Debug`) could
@@ -79,14 +81,16 @@ impl<'tcx> SelectionCache<'tcx> {
 /// inference variables. The can lead to inference making "leaps of logic",
 /// for example in this situation:
 ///
-///    pub trait Foo<T> { fn foo(&self) -> T; }
-///    impl<T> Foo<()> for T { fn foo(&self) { } }
-///    impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
+/// ```rust, ignore
+/// pub trait Foo<T> { fn foo(&self) -> T; }
+/// impl<T> Foo<()> for T { fn foo(&self) { } }
+/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
 ///
-///    pub fn foo<T>(t: T) where T: Foo<bool> {
-///       println!("{:?}", <T as Foo<_>>::foo(&t));
-///    }
-///    fn main() { foo(false); }
+/// pub fn foo<T>(t: T) where T: Foo<bool> {
+///     println!("{:?}", <T as Foo<_>>::foo(&t));
+/// }
+/// fn main() { foo(false); }
+/// ```
 ///
 /// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
 /// impl and the where-clause. We select the where-clause and unify `$0=bool`,
@@ -128,6 +132,9 @@ pub enum SelectionCandidate<'tcx> {
     /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
     FnPointerCandidate,
 
+    /// Builtin implementation of `DiscriminantKind`.
+    DiscriminantKindCandidate,
+
     TraitAliasCandidate(DefId),
 
     ObjectCandidate,
diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs
index 56744283b0c..74f74415294 100644
--- a/src/librustc_middle/traits/structural_impls.rs
+++ b/src/librustc_middle/traits/structural_impls.rs
@@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
 
             super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
 
+            super::VtableDiscriminantKind(ref d) => write!(f, "{:?}", d),
+
             super::VtableObject(ref d) => write!(f, "{:?}", d),
 
             super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
@@ -274,6 +276,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
                     traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
                 })
             }
+            traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData) => {
+                Some(traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData))
+            }
             traits::VtableParam(n) => Some(traits::VtableParam(n)),
             traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
             traits::VtableObject(traits::VtableObjectData {
diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs
index cbbc937ed7d..1cd4af45f29 100644
--- a/src/librustc_middle/ty/codec.rs
+++ b/src/librustc_middle/ty/codec.rs
@@ -15,8 +15,10 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
+use std::convert::{TryFrom, TryInto};
 use std::hash::Hash;
 use std::intrinsics;
+use std::marker::DiscriminantKind;
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
@@ -60,6 +62,7 @@ where
     E: TyEncoder,
     M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
     T: EncodableWithShorthand,
+    <T::Variant as DiscriminantKind>::Discriminant: Ord + TryFrom<usize>,
 {
     let existing_shorthand = cache(encoder).get(value).cloned();
     if let Some(shorthand) = existing_shorthand {
@@ -75,7 +78,8 @@ where
     // The shorthand encoding uses the same usize as the
     // discriminant, with an offset so they can't conflict.
     let discriminant = intrinsics::discriminant_value(variant);
-    assert!(discriminant < SHORTHAND_OFFSET as u64);
+    assert!(discriminant < SHORTHAND_OFFSET.try_into().ok().unwrap());
+
     let shorthand = start + SHORTHAND_OFFSET;
 
     // Get the number of bits that leb128 could fit
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index c8bf328ce8e..42b969c9991 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -2,8 +2,6 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
-use std::convert::TryFrom;
-
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
@@ -220,7 +218,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::discriminant_value => {
                 let place = self.deref_operand(args[0])?;
                 let discr_val = self.read_discriminant(place.into())?.0;
-                self.write_scalar(Scalar::from_u64(u64::try_from(discr_val).unwrap()), dest)?;
+                let scalar = match dest.layout.ty.kind {
+                    ty::Int(_) => Scalar::from_int(discr_val as i128, dest.layout.size),
+                    ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size),
+                    _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout),
+                };
+                self.write_scalar(scalar, dest)?;
             }
             sym::unchecked_shl
             | sym::unchecked_shr
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index c4cb72fa08c..f102f34c744 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -12,7 +12,10 @@ use super::Selection;
 use super::SelectionContext;
 use super::SelectionError;
 use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
-use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
+use super::{
+    VtableClosureData, VtableDiscriminantKindData, VtableFnPointerData, VtableGeneratorData,
+    VtableImplData,
+};
 
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
@@ -23,6 +26,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::DUMMY_SP;
@@ -1043,6 +1047,46 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     }
                 }
             }
+            super::VtableDiscriminantKind(..) => {
+                // While `DiscriminantKind` is automatically implemented for every type,
+                // the concrete discriminant may not be known yet.
+                //
+                // Any type with multiple potential discriminant types is therefore not eligible.
+                let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+                match self_ty.kind {
+                    ty::Bool
+                    | ty::Char
+                    | ty::Int(_)
+                    | ty::Uint(_)
+                    | ty::Float(_)
+                    | ty::Adt(..)
+                    | ty::Foreign(_)
+                    | ty::Str
+                    | ty::Array(..)
+                    | ty::Slice(_)
+                    | ty::RawPtr(..)
+                    | ty::Ref(..)
+                    | ty::FnDef(..)
+                    | ty::FnPtr(..)
+                    | ty::Dynamic(..)
+                    | ty::Closure(..)
+                    | ty::Generator(..)
+                    | ty::GeneratorWitness(..)
+                    | ty::Never
+                    | ty::Tuple(..)
+                    // Integers and floats always have `u8` as their discriminant.
+                    | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+                    ty::Projection(..)
+                    | ty::Opaque(..)
+                    | ty::Param(..)
+                    | ty::Bound(..)
+                    | ty::Placeholder(..)
+                    | ty::Infer(..)
+                    | ty::Error => false,
+                }
+            }
             super::VtableParam(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
@@ -1124,13 +1168,15 @@ fn confirm_select_candidate<'cx, 'tcx>(
         super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data),
         super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data),
         super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
+        super::VtableDiscriminantKind(data) => {
+            confirm_discriminant_kind_candidate(selcx, obligation, data)
+        }
         super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref),
         super::VtableAutoImpl(..)
         | super::VtableParam(..)
         | super::VtableBuiltin(..)
-        | super::VtableTraitAlias(..) =>
-        // we don't create Select candidates with this kind of resolution
-        {
+        | super::VtableTraitAlias(..) => {
+            // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
                 "Cannot project an associated type from `{:?}`",
@@ -1259,6 +1305,37 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         .with_addl_obligations(obligations)
 }
 
+fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    _: VtableDiscriminantKindData,
+) -> Progress<'tcx> {
+    let tcx = selcx.tcx();
+
+    let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+    let substs = tcx.mk_substs([self_ty.into()].iter());
+
+    let assoc_items = tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
+    // FIXME: emit an error if the trait definition is wrong
+    let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
+
+    let discriminant_ty = match self_ty.kind {
+        // Use the discriminant type for enums.
+        ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
+        // Default to `i32` for generators.
+        ty::Generator(..) => tcx.types.i32,
+        // Use `u8` for all other types.
+        _ => tcx.types.u8,
+    };
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
+        ty: discriminant_ty,
+    };
+
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
+}
+
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index 70c6cbef102..d903779e507 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -24,12 +24,13 @@ use super::{ObjectCastObligation, Obligation};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
 use super::{
-    VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
-    VtableObject, VtableParam, VtableTraitAlias,
+    VtableAutoImpl, VtableBuiltin, VtableClosure, VtableDiscriminantKind, VtableFnPointer,
+    VtableGenerator, VtableImpl, VtableObject, VtableParam, VtableTraitAlias,
 };
 use super::{
-    VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
-    VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
+    VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableDiscriminantKindData,
+    VtableFnPointerData, VtableGeneratorData, VtableImplData, VtableObjectData,
+    VtableTraitAliasData,
 };
 
 use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
@@ -1382,6 +1383,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // For other types, we'll use the builtin rules.
             let copy_conditions = self.copy_clone_conditions(obligation);
             self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+        } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+            // `DiscriminantKind` is automatically implemented for every type.
+            candidates.vec.push(DiscriminantKindCandidate);
         } else if lang_items.sized_trait() == Some(def_id) {
             // Sized is never implementable by end-users, it is
             // always automatically computed.
@@ -1995,11 +1999,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let is_global =
             |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
 
+        // (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
+        // to anything else.
+        //
+        // This is a fix for #53123 and prevents winnowing from accidentally extending the
+        // lifetime of a variable.
         match other.candidate {
-            // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-            // This is a fix for #53123 and prevents winnowing from accidentally extending the
-            // lifetime of a variable.
-            BuiltinCandidate { has_nested: false } => true,
+            // (*)
+            BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
             ParamCandidate(ref cand) => match victim.candidate {
                 AutoImplCandidate(..) => {
                     bug!(
@@ -2007,10 +2014,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                          when there are other valid candidates"
                     );
                 }
-                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-                // This is a fix for #53123 and prevents winnowing from accidentally extending the
-                // lifetime of a variable.
-                BuiltinCandidate { has_nested: false } => false,
+                // (*)
+                BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
@@ -2038,10 +2043,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                          when there are other valid candidates"
                     );
                 }
-                // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
-                // This is a fix for #53123 and prevents winnowing from accidentally extending the
-                // lifetime of a variable.
-                BuiltinCandidate { has_nested: false } => false,
+                // (*)
+                BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
@@ -2486,6 +2489,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(VtableFnPointer(data))
             }
 
+            DiscriminantKindCandidate => Ok(VtableDiscriminantKind(VtableDiscriminantKindData)),
+
             TraitAliasCandidate(alias_def_id) => {
                 let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
                 Ok(VtableTraitAlias(data))
diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs
index 2a99bb1aed9..a793031d402 100644
--- a/src/librustc_ty/instance.rs
+++ b/src/librustc_ty/instance.rs
@@ -236,7 +236,10 @@ fn resolve_associated_item<'tcx>(
                 None
             }
         }
-        traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None,
+        traits::VtableAutoImpl(..)
+        | traits::VtableParam(..)
+        | traits::VtableTraitAlias(..)
+        | traits::VtableDiscriminantKind(..) => None,
     })
 }
 
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index db6c30adb04..bded2c695c9 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -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);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 05d5a81217c..a45a44a6801 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
     let did = Some(trait_def_id);
     let li = tcx.lang_items();
 
-    // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
+    // Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
+    if did == li.discriminant_kind_trait() {
+        let span = impl_header_span(tcx, impl_def_id);
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0322,
+            "explicit impls for the `DiscriminantKind` trait are not permitted"
+        )
+        .span_label(span, "impl of 'DiscriminantKind' not allowed")
+        .emit();
+        return;
+    }
+
     if did == li.sized_trait() {
         let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
diff --git a/src/test/ui/enum-discriminant/actually_not_an_enum-discriminant.rs b/src/test/ui/enum-discriminant/actually_not_an_enum-discriminant.rs
new file mode 100644
index 00000000000..6a566ab3a3d
--- /dev/null
+++ b/src/test/ui/enum-discriminant/actually_not_an_enum-discriminant.rs
@@ -0,0 +1,49 @@
+// run-pass
+#![feature(core_intrinsics)]
+
+use std::intrinsics::discriminant_value;
+
+struct Zst;
+
+struct Struct {
+    _a: u32,
+}
+
+union Union {
+    _a: u32,
+}
+
+fn check(v: u8) {
+    assert_eq!(v, 0);
+}
+
+pub fn generic<T>()
+where
+    for<'a> T: Fn(&'a isize),
+{
+    let v: Vec<T> =  Vec::new();
+    let _: u8 = discriminant_value(&v);
+}
+
+fn main() {
+    // check that we use `u8` as the discriminant value
+    // for everything that is not an enum.
+    check(discriminant_value(&true));
+    check(discriminant_value(&'a'));
+    check(discriminant_value(&7));
+    check(discriminant_value(&7.0));
+    check(discriminant_value(&Zst));
+    check(discriminant_value(&Struct { _a: 7 }));
+    check(discriminant_value(&Union { _a: 7 }));
+    check(discriminant_value(&[7, 77]));
+    check(discriminant_value(&(7 as *const ())));
+    check(discriminant_value(&(7 as *mut ())));
+    check(discriminant_value(&&7));
+    check(discriminant_value(&&mut 7));
+    check(discriminant_value(&check));
+    let fn_ptr: fn(u8) = check;
+    check(discriminant_value(&fn_ptr));
+    let hrtb: for<'a> fn(&'a str) -> &'a str = |x| x;
+    check(discriminant_value(&hrtb));
+    check(discriminant_value(&(7, 77, 777)));
+}
diff --git a/src/test/ui/enum-discriminant/discriminant_size.rs b/src/test/ui/enum-discriminant/discriminant_size.rs
new file mode 100644
index 00000000000..4cede8c2a2d
--- /dev/null
+++ b/src/test/ui/enum-discriminant/discriminant_size.rs
@@ -0,0 +1,53 @@
+// run-pass
+#![feature(core_intrinsics, repr128)]
+
+use std::intrinsics::discriminant_value;
+
+enum E1 {
+    A,
+    B,
+}
+
+#[repr(i8)]
+enum E2 {
+    A = 7,
+    B = -2,
+}
+
+#[repr(C)]
+enum E3 {
+    A = 42,
+    B = 100,
+}
+
+#[repr(i128)]
+enum E4 {
+    A = 0x1223_3445_5667_7889,
+    B = -0x1223_3445_5667_7889,
+}
+
+fn main() {
+    let mut target: [isize; 3] = [0, 0, 0];
+    target[1] = discriminant_value(&E1::A);
+    assert_eq!(target, [0, 0, 0]);
+    target[1] = discriminant_value(&E1::B);
+    assert_eq!(target, [0, 1, 0]);
+
+    let mut target: [i8; 3] = [0, 0, 0];
+    target[1] = discriminant_value(&E2::A);
+    assert_eq!(target, [0, 7, 0]);
+    target[1] = discriminant_value(&E2::B);
+    assert_eq!(target, [0, -2, 0]);
+
+    let mut target: [isize; 3] = [0, 0, 0];
+    target[1] = discriminant_value(&E3::A);
+    assert_eq!(target, [0, 42, 0]);
+    target[1] = discriminant_value(&E3::B);
+    assert_eq!(target, [0, 100, 0]);
+
+    let mut target: [i128; 3] = [0, 0, 0];
+    target[1] = discriminant_value(&E4::A);
+    assert_eq!(target, [0, 0x1223_3445_5667_7889, 0]);
+    target[1] = discriminant_value(&E4::B);
+    assert_eq!(target, [0, -0x1223_3445_5667_7889, 0]);
+}
diff --git a/src/test/ui/enum-discriminant/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs
index 32d2d40241c..eb60aaf4b2d 100644
--- a/src/test/ui/enum-discriminant/discriminant_value.rs
+++ b/src/test/ui/enum-discriminant/discriminant_value.rs
@@ -51,31 +51,31 @@ enum Mixed {
 }
 
 pub fn main() {
-    assert_eq!(discriminant_value(&CLike1::A), 0);
+    assert_eq!(discriminant_value(&CLike1::A), 0isize);
     assert_eq!(discriminant_value(&CLike1::B), 1);
     assert_eq!(discriminant_value(&CLike1::C), 2);
     assert_eq!(discriminant_value(&CLike1::D), 3);
 
-    assert_eq!(discriminant_value(&CLike2::A), 5);
+    assert_eq!(discriminant_value(&CLike2::A), 5isize);
     assert_eq!(discriminant_value(&CLike2::B), 2);
     assert_eq!(discriminant_value(&CLike2::C), 19);
     assert_eq!(discriminant_value(&CLike2::D), 20);
 
-    assert_eq!(discriminant_value(&CLike3::A), 5);
+    assert_eq!(discriminant_value(&CLike3::A), 5i8);
     assert_eq!(discriminant_value(&CLike3::B), 6);
-    assert_eq!(discriminant_value(&CLike3::C), -1_i8 as u64);
+    assert_eq!(discriminant_value(&CLike3::C), -1);
     assert_eq!(discriminant_value(&CLike3::D), 0);
 
-    assert_eq!(discriminant_value(&ADT::First(0,0)), 0);
+    assert_eq!(discriminant_value(&ADT::First(0,0)), 0isize);
     assert_eq!(discriminant_value(&ADT::Second(5)), 1);
 
-    assert_eq!(discriminant_value(&NullablePointer::Nothing), 1);
+    assert_eq!(discriminant_value(&NullablePointer::Nothing), 1isize);
     assert_eq!(discriminant_value(&NullablePointer::Something(&CONST)), 0);
 
-    assert_eq!(discriminant_value(&10), 0);
-    assert_eq!(discriminant_value(&"test"), 0);
+    assert_eq!(discriminant_value(&10), 0u8);
+    assert_eq!(discriminant_value(&"test"), 0u8);
 
-    assert_eq!(3, discriminant_value(&Mixed::Unit));
-    assert_eq!(2, discriminant_value(&Mixed::Tuple(5)));
-    assert_eq!(1, discriminant_value(&Mixed::Struct{a: 7, b: 11}));
+    assert_eq!(discriminant_value(&Mixed::Unit), 3isize);
+    assert_eq!(discriminant_value(&Mixed::Tuple(5)), 2);
+    assert_eq!(discriminant_value(&Mixed::Struct{a: 7, b: 11}), 1);
 }
diff --git a/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.rs b/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.rs
new file mode 100644
index 00000000000..4760ca5482a
--- /dev/null
+++ b/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.rs
@@ -0,0 +1,14 @@
+#![feature(discriminant_kind)]
+
+use std::marker::DiscriminantKind;
+
+enum Uninhabited {}
+
+struct NewType;
+
+impl DiscriminantKind for NewType {
+    //~^ ERROR explicit impls for the `DiscriminantKind` trait are not permitted
+    type Discriminant = Uninhabited;
+}
+
+fn main() {}
diff --git a/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.stderr b/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.stderr
new file mode 100644
index 00000000000..54360c4f47b
--- /dev/null
+++ b/src/test/ui/enum-discriminant/forbidden-discriminant-kind-impl.stderr
@@ -0,0 +1,9 @@
+error[E0322]: explicit impls for the `DiscriminantKind` trait are not permitted
+  --> $DIR/forbidden-discriminant-kind-impl.rs:9:1
+   |
+LL | impl DiscriminantKind for NewType {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'DiscriminantKind' not allowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0322`.
diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
index 05911a9a303..5a528379b04 100644
--- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
+++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
@@ -13,5 +13,5 @@ enum MyWeirdOption<T> {
 
 fn main() {
     assert_eq!(discriminant_value(&MyWeirdOption::<()>::None), 0);
-    assert_eq!(discriminant_value(&MyWeirdOption::Some(())), core::mem::size_of::<usize>() as u64);
+    assert_eq!(discriminant_value(&MyWeirdOption::Some(())), core::mem::size_of::<usize>());
 }
diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
new file mode 100644
index 00000000000..e9c6104e387
--- /dev/null
+++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(repr128, arbitrary_enum_discriminant)]
+
+#[derive(PartialEq, Debug)]
+#[repr(i128)]
+enum Test {
+    A(Box<u64>) = 0,
+    B(usize) = u64::max_value() as i128 + 1,
+}
+
+fn main() {
+    assert_ne!(Test::A(Box::new(2)), Test::B(0));
+    // This previously caused a segfault.
+    //
+    // See https://github.com/rust-lang/rust/issues/70509#issuecomment-620654186
+    // for a detailed explanation.
+}
diff --git a/src/test/ui/enum-discriminant/repr128.rs b/src/test/ui/enum-discriminant/repr128.rs
new file mode 100644
index 00000000000..420b6007c6d
--- /dev/null
+++ b/src/test/ui/enum-discriminant/repr128.rs
@@ -0,0 +1,44 @@
+// run-pass
+#![feature(repr128, core_intrinsics, discriminant_kind)]
+
+use std::intrinsics::discriminant_value;
+use std::marker::DiscriminantKind;
+
+#[repr(i128)]
+enum Signed {
+    Zero = 0,
+    Staircase = 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f,
+    U64Limit = u64::max_value() as i128 + 1,
+    SmallNegative = -1,
+    BigNegative = i128::min_value(),
+    Next,
+}
+
+#[repr(u128)]
+enum Unsigned {
+    Zero = 0,
+    Staircase = 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f,
+    U64Limit = u64::max_value() as u128 + 1,
+    Next,
+}
+
+fn discr<T, U>(v: T, value: U)
+where
+    <T as DiscriminantKind>::Discriminant: PartialEq<U>,
+{
+    assert!(discriminant_value(&v) == value);
+}
+
+fn main() {
+    discr(Signed::Zero, 0);
+    discr(Signed::Staircase, 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f);
+    discr(Signed::U64Limit, u64::max_value() as i128 + 1);
+    discr(Signed::SmallNegative, -1);
+    discr(Signed::BigNegative, i128::min_value());
+    discr(Signed::Next, i128::min_value() + 1);
+
+    discr(Unsigned::Zero, 0);
+    discr(Unsigned::Staircase, 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f);
+    discr(Unsigned::U64Limit, u64::max_value() as u128 + 1);
+    discr(Unsigned::Next, u64::max_value() as u128 + 2);
+}
diff --git a/src/test/ui/generator/discriminant.rs b/src/test/ui/generator/discriminant.rs
index 8a0f8a380ab..3d0930da422 100644
--- a/src/test/ui/generator/discriminant.rs
+++ b/src/test/ui/generator/discriminant.rs
@@ -3,10 +3,10 @@
 
 // run-pass
 
-#![feature(generators, generator_trait, core_intrinsics)]
+#![feature(generators, generator_trait, core_intrinsics, discriminant_kind)]
 
 use std::intrinsics::discriminant_value;
-use std::marker::Unpin;
+use std::marker::{Unpin, DiscriminantKind};
 use std::mem::size_of_val;
 use std::{cmp, ops::*};
 
@@ -65,7 +65,10 @@ macro_rules! yield250 {
     };
 }
 
-fn cycle(gen: impl Generator<()> + Unpin, expected_max_discr: u64) {
+fn cycle(
+    gen: impl Generator<()> + Unpin + DiscriminantKind<Discriminant = i32>,
+    expected_max_discr: i32
+) {
     let mut gen = Box::pin(gen);
     let mut max_discr = 0;
     loop {