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
This commit is contained in:
commit
963bf52829
@ -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`
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
|
@ -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; }
|
||||
/// ```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,6 +81,7 @@ impl<'tcx> SelectionCache<'tcx> {
|
||||
/// inference variables. The can lead to inference making "leaps of logic",
|
||||
/// for example in this situation:
|
||||
///
|
||||
/// ```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 } }
|
||||
@ -87,6 +90,7 @@ impl<'tcx> SelectionCache<'tcx> {
|
||||
/// 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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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(..) =>
|
||||
| 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>,
|
||||
|
@ -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();
|
||||
|
||||
match other.candidate {
|
||||
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
|
||||
// (*) 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.
|
||||
BuiltinCandidate { has_nested: false } => true,
|
||||
match other.candidate {
|
||||
// (*)
|
||||
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))
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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" => (
|
||||
"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.types.u64,
|
||||
),
|
||||
tcx.mk_projection(discriminant_def_id, tcx.mk_substs([param(0).into()].iter())),
|
||||
)
|
||||
}
|
||||
|
||||
"try" => {
|
||||
let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
|
||||
|
@ -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!(
|
||||
|
@ -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)));
|
||||
}
|
53
src/test/ui/enum-discriminant/discriminant_size.rs
Normal file
53
src/test/ui/enum-discriminant/discriminant_size.rs
Normal file
@ -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]);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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>());
|
||||
}
|
||||
|
17
src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
Normal file
17
src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
Normal file
@ -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.
|
||||
}
|
44
src/test/ui/enum-discriminant/repr128.rs
Normal file
44
src/test/ui/enum-discriminant/repr128.rs
Normal file
@ -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);
|
||||
}
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user