Add ptr::Pointee
trait (for all types) and ptr::metadata
function
RFC: https://github.com/rust-lang/rfcs/pull/2580
This commit is contained in:
parent
9503ea19ed
commit
696b239f72
17 changed files with 349 additions and 10 deletions
|
@ -201,6 +201,10 @@ language_item_table! {
|
|||
// The associated item of `trait DiscriminantKind`.
|
||||
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
|
||||
|
||||
PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait;
|
||||
Metadata, sym::metadata_type, metadata_type, Target::AssocTy;
|
||||
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct;
|
||||
|
||||
Freeze, sym::freeze, freeze_trait, Target::Trait;
|
||||
|
||||
Drop, sym::drop, drop_trait, Target::Trait;
|
||||
|
|
|
@ -476,6 +476,9 @@ pub enum ImplSource<'tcx, N> {
|
|||
/// ImplSource for a builtin `DeterminantKind` trait implementation.
|
||||
DiscriminantKind(ImplSourceDiscriminantKindData),
|
||||
|
||||
/// ImplSource for a builtin `Pointee` trait implementation.
|
||||
Pointee(ImplSourcePointeeData),
|
||||
|
||||
/// ImplSource automatically generated for a generator.
|
||||
Generator(ImplSourceGeneratorData<'tcx, N>),
|
||||
|
||||
|
@ -494,7 +497,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
|||
ImplSource::Generator(c) => c.nested,
|
||||
ImplSource::Object(d) => d.nested,
|
||||
ImplSource::FnPointer(d) => d.nested,
|
||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
|
||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
|
||||
ImplSource::TraitAlias(d) => d.nested,
|
||||
}
|
||||
}
|
||||
|
@ -509,7 +513,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
|||
ImplSource::Generator(c) => &c.nested[..],
|
||||
ImplSource::Object(d) => &d.nested[..],
|
||||
ImplSource::FnPointer(d) => &d.nested[..],
|
||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
|
||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
||||
ImplSource::TraitAlias(d) => &d.nested[..],
|
||||
}
|
||||
}
|
||||
|
@ -554,6 +559,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
|||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
|
||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||
}
|
||||
ImplSource::Pointee(ImplSourcePointeeData) => {
|
||||
ImplSource::Pointee(ImplSourcePointeeData)
|
||||
}
|
||||
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
|
||||
alias_def_id: d.alias_def_id,
|
||||
substs: d.substs,
|
||||
|
@ -632,6 +640,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ImplSourceDiscriminantKindData;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ImplSourcePointeeData;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
||||
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
||||
pub alias_def_id: DefId,
|
||||
|
|
|
@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
|
|||
/// Builtin implementation of `DiscriminantKind`.
|
||||
DiscriminantKindCandidate,
|
||||
|
||||
/// Builtin implementation of `Pointee`.
|
||||
PointeeCandidate,
|
||||
|
||||
TraitAliasCandidate(DefId),
|
||||
|
||||
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
|
||||
|
|
|
@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
|||
|
||||
super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Param(ref n, ct) => {
|
||||
|
@ -110,4 +112,5 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
|
|||
TrivialTypeFoldableAndLiftImpls! {
|
||||
super::IfExpressionCause,
|
||||
super::ImplSourceDiscriminantKindData,
|
||||
super::ImplSourcePointeeData,
|
||||
}
|
||||
|
|
|
@ -2133,6 +2133,51 @@ impl<'tcx> TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the type of metadata for (potentially fat) pointers to this type.
|
||||
pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
// FIXME: should this normalize?
|
||||
let tail = tcx.struct_tail_without_normalization(self);
|
||||
match tail.kind() {
|
||||
// Sized types
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
| ty::Float(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Char
|
||||
| ty::Ref(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Error(_)
|
||||
| ty::Foreign(..)
|
||||
// If returned by `struct_tail_without_normalization` this is a unit struct
|
||||
// without any fields, or not a struct, and therefore is Sized.
|
||||
| ty::Adt(..)
|
||||
// If returned by `struct_tail_without_normalization` this is the empty tuple,
|
||||
// a.k.a. unit type, which is Sized
|
||||
| ty::Tuple(..) => tcx.types.unit,
|
||||
|
||||
ty::Str | ty::Slice(_) => tcx.types.usize,
|
||||
ty::Dynamic(..) => tcx.type_of(tcx.lang_items().dyn_metadata().unwrap()),
|
||||
|
||||
ty::Projection(_)
|
||||
| ty::Param(_)
|
||||
| ty::Opaque(..)
|
||||
| ty::Infer(ty::TyVar(_))
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When we create a closure, we record its kind (i.e., what trait
|
||||
/// it implements) into its `ClosureSubsts` using a type
|
||||
/// parameter. This is kind of a phantom type, except that the
|
||||
|
|
|
@ -476,6 +476,7 @@ symbols! {
|
|||
dropck_eyepatch,
|
||||
dropck_parametricity,
|
||||
dylib,
|
||||
dyn_metadata,
|
||||
dyn_trait,
|
||||
edition_macro_pats,
|
||||
eh_catch_typeinfo,
|
||||
|
@ -710,6 +711,7 @@ symbols! {
|
|||
memory,
|
||||
message,
|
||||
meta,
|
||||
metadata_type,
|
||||
min_align_of,
|
||||
min_align_of_val,
|
||||
min_const_fn,
|
||||
|
@ -832,6 +834,7 @@ symbols! {
|
|||
plugin,
|
||||
plugin_registrar,
|
||||
plugins,
|
||||
pointee_trait,
|
||||
pointer,
|
||||
pointer_trait,
|
||||
pointer_trait_fmt,
|
||||
|
|
|
@ -12,7 +12,7 @@ use super::SelectionContext;
|
|||
use super::SelectionError;
|
||||
use super::{
|
||||
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
|
||||
ImplSourceGeneratorData, ImplSourceUserDefinedData,
|
||||
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
|
||||
};
|
||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||
|
||||
|
@ -1069,6 +1069,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
| ty::Error(_) => false,
|
||||
}
|
||||
}
|
||||
super::ImplSource::Pointee(..) => {
|
||||
// While `Pointee` is automatically implemented for every type,
|
||||
// the concrete metadata type may not be known yet.
|
||||
//
|
||||
// Any type with multiple potential metadata types is therefore not eligible.
|
||||
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
|
||||
|
||||
// FIXME: should this normalize?
|
||||
let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
|
||||
match tail.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| 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
|
||||
// If returned by `struct_tail_without_normalization` this is a unit struct
|
||||
// without any fields, or not a struct, and therefore is Sized.
|
||||
| ty::Adt(..)
|
||||
// If returned by `struct_tail_without_normalization` this is the empty tuple.
|
||||
| ty::Tuple(..)
|
||||
// Integers and floats are always Sized, and so have unit type metadata.
|
||||
| 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::ImplSource::Param(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
|
@ -1169,6 +1214,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||
super::ImplSource::DiscriminantKind(data) => {
|
||||
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
||||
}
|
||||
super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Object(_)
|
||||
| super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::Param(..)
|
||||
|
@ -1256,6 +1302,26 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
|||
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
|
||||
}
|
||||
|
||||
fn confirm_pointee_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
_: ImplSourcePointeeData,
|
||||
) -> 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 metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
|
||||
|
||||
let predicate = ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
|
||||
ty: self_ty.ptr_metadata_ty(tcx),
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
|
|
|
@ -267,6 +267,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
} 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.pointee_trait() == Some(def_id) {
|
||||
// `Pointee` is automatically implemented for every type.
|
||||
candidates.vec.push(PointeeCandidate);
|
||||
} else if lang_items.sized_trait() == Some(def_id) {
|
||||
// Sized is never implementable by end-users, it is
|
||||
// always automatically computed.
|
||||
|
|
|
@ -30,7 +30,8 @@ use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
|||
use crate::traits::{
|
||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
||||
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
||||
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
|
||||
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
||||
ImplSourceUserDefinedData,
|
||||
};
|
||||
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
||||
use crate::traits::{Obligation, ObligationCause};
|
||||
|
@ -99,6 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
|
||||
}
|
||||
|
||||
PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
|
||||
|
||||
TraitAliasCandidate(alias_def_id) => {
|
||||
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
|
||||
Ok(ImplSource::TraitAlias(data))
|
||||
|
|
|
@ -1318,8 +1318,8 @@ 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.
|
||||
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
|
||||
// and `DiscriminantKindCandidate` to anything else.
|
||||
//
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
|
@ -1332,8 +1332,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
// (*)
|
||||
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
|
||||
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
|
||||
(
|
||||
BuiltinCandidate { has_nested: false }
|
||||
| DiscriminantKindCandidate
|
||||
| PointeeCandidate,
|
||||
_,
|
||||
) => true,
|
||||
(
|
||||
_,
|
||||
BuiltinCandidate { has_nested: false }
|
||||
| DiscriminantKindCandidate
|
||||
| PointeeCandidate,
|
||||
) => false,
|
||||
|
||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||
if other.value == victim.value && victim.constness == Constness::NotConst {
|
||||
|
|
|
@ -274,7 +274,8 @@ fn resolve_associated_item<'tcx>(
|
|||
traits::ImplSource::AutoImpl(..)
|
||||
| traits::ImplSource::Param(..)
|
||||
| traits::ImplSource::TraitAlias(..)
|
||||
| traits::ImplSource::DiscriminantKind(..) => None,
|
||||
| traits::ImplSource::DiscriminantKind(..)
|
||||
| traits::ImplSource::Pointee(..) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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 `DiscriminantKind`, `Sized` and `Unsize` for now.
|
||||
// Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
|
||||
if did == li.pointee_trait() {
|
||||
let span = impl_header_span(tcx, impl_def_id);
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0322,
|
||||
"explicit impls for the `Pointee` trait are not permitted"
|
||||
)
|
||||
.span_label(span, "impl of 'Pointee' not allowed")
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
if did == li.discriminant_kind_trait() {
|
||||
let span = impl_header_span(tcx, impl_def_id);
|
||||
struct_span_err!(
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(str_split_as_str)]
|
||||
#![feature(str_split_inclusive_as_str)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(transparent_unions)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
|
77
library/core/src/ptr/metadata.rs
Normal file
77
library/core/src/ptr/metadata.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
#![unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
|
||||
|
||||
use crate::fmt;
|
||||
use crate::hash::Hash;
|
||||
use crate::ptr::NonNull;
|
||||
|
||||
/// FIXME docs
|
||||
#[lang = "pointee_trait"]
|
||||
pub trait Pointee {
|
||||
/// The type for metadata in pointers and references to `Self`.
|
||||
#[lang = "metadata_type"]
|
||||
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
|
||||
// in `library/core/src/ptr/metadata.rs`
|
||||
// in sync with those here:
|
||||
type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
|
||||
}
|
||||
|
||||
/// Pointers to types implementing this trait alias are “thin”
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(ptr_metadata)]
|
||||
///
|
||||
/// fn this_never_panics<T: std::ptr::Thin>() {
|
||||
/// assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
|
||||
// NOTE: don’t stabilize this before trait aliases are stable in the language?
|
||||
pub trait Thin = Pointee<Metadata = ()>;
|
||||
|
||||
/// Extract the metadata component of a pointer.
|
||||
#[inline]
|
||||
pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
|
||||
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
|
||||
// and PtrComponents<T> have the same memory layouts. Only std can make this
|
||||
// guarantee.
|
||||
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
union PtrRepr<T: ?Sized> {
|
||||
const_ptr: *const T,
|
||||
components: PtrComponents<T>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct PtrComponents<T: ?Sized> {
|
||||
data_address: usize,
|
||||
metadata: <T as Pointee>::Metadata,
|
||||
}
|
||||
|
||||
// Manual impl needed to avoid `T: Copy` bound.
|
||||
impl<T: ?Sized> Copy for PtrComponents<T> {}
|
||||
|
||||
// Manual impl needed to avoid `T: Clone` bound.
|
||||
impl<T: ?Sized> Clone for PtrComponents<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// The metadata for a `dyn SomeTrait` trait object type.
|
||||
#[lang = "dyn_metadata"]
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
pub struct DynMetadata {
|
||||
#[allow(unused)]
|
||||
vtable_ptr: NonNull<()>,
|
||||
}
|
||||
|
||||
unsafe impl Send for DynMetadata {}
|
||||
unsafe impl Sync for DynMetadata {}
|
||||
|
||||
impl fmt::Debug for DynMetadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("DynMetadata { … }")
|
||||
}
|
||||
}
|
|
@ -82,6 +82,12 @@ pub use crate::intrinsics::copy;
|
|||
#[doc(inline)]
|
||||
pub use crate::intrinsics::write_bytes;
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
mod metadata;
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
|
||||
pub use metadata::{metadata, DynMetadata, Pointee, Thin};
|
||||
|
||||
mod non_null;
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
pub use non_null::NonNull;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#![feature(duration_saturating_ops)]
|
||||
#![feature(duration_zero)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(fixed_size_array)]
|
||||
#![feature(flt2dec)]
|
||||
#![feature(fmt_internals)]
|
||||
|
@ -67,8 +68,10 @@
|
|||
#![feature(option_result_unwrap_unchecked)]
|
||||
#![feature(option_unwrap_none)]
|
||||
#![feature(peekable_peek_mut)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
#![feature(int_bits_const)]
|
||||
#![feature(nonzero_leading_trailing_zeros)]
|
||||
#![feature(const_option)]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use core::cell::RefCell;
|
||||
use core::ptr::*;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[test]
|
||||
fn test_const_from_raw_parts() {
|
||||
|
@ -413,3 +414,89 @@ fn offset_from() {
|
|||
assert_eq!(ptr2.offset(-2), ptr1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(bootstrap))]
|
||||
fn ptr_metadata() {
|
||||
struct Unit;
|
||||
struct Pair<A, B: ?Sized>(A, B);
|
||||
extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
let () = metadata(&());
|
||||
let () = metadata(&Unit);
|
||||
let () = metadata(&4_u32);
|
||||
let () = metadata(&String::new());
|
||||
let () = metadata(&Some(4_u32));
|
||||
let () = metadata(&ptr_metadata);
|
||||
let () = metadata(&|| {});
|
||||
let () = metadata(&[4, 7]);
|
||||
let () = metadata(&(4, String::new()));
|
||||
let () = metadata(&Pair(4, String::new()));
|
||||
let () = metadata(0 as *const Extern);
|
||||
let () = metadata(0 as *const <&u32 as std::ops::Deref>::Target);
|
||||
|
||||
assert_eq!(metadata("foo"), 3_usize);
|
||||
assert_eq!(metadata(&[4, 7][..]), 2_usize);
|
||||
|
||||
let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
|
||||
let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
|
||||
assert_eq!(metadata(dst_tuple), 3_usize);
|
||||
assert_eq!(metadata(dst_struct), 3_usize);
|
||||
unsafe {
|
||||
let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
|
||||
let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
|
||||
assert_eq!(&dst_tuple.1, "foo");
|
||||
assert_eq!(&dst_struct.1, "foo");
|
||||
assert_eq!(metadata(dst_tuple), 3_usize);
|
||||
assert_eq!(metadata(dst_struct), 3_usize);
|
||||
}
|
||||
|
||||
let vtable_1: DynMetadata = metadata(&4_u32 as &dyn Display);
|
||||
let vtable_2: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display));
|
||||
let vtable_3: DynMetadata = metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
|
||||
let vtable_4: DynMetadata = metadata(&4_u16 as &dyn Display);
|
||||
unsafe {
|
||||
let address_1: usize = std::mem::transmute(vtable_1);
|
||||
let address_2: usize = std::mem::transmute(vtable_2);
|
||||
let address_3: usize = std::mem::transmute(vtable_3);
|
||||
let address_4: usize = std::mem::transmute(vtable_4);
|
||||
// Same erased type and same trait: same vtable pointer
|
||||
assert_eq!(address_1, address_2);
|
||||
assert_eq!(address_1, address_3);
|
||||
// Different erased type: different vtable pointer
|
||||
assert_ne!(address_1, address_4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(bootstrap))]
|
||||
fn ptr_metadata_bounds() {
|
||||
fn metadata_eq_method_address<T: ?Sized>() -> usize {
|
||||
// The `Metadata` associated type has an `Ord` bound, so this is valid:
|
||||
<<T as Pointee>::Metadata as PartialEq>::eq as usize
|
||||
}
|
||||
// "Synthetic" trait impls generated by the compiler like those of `Pointee`
|
||||
// are not checked for bounds of associated type.
|
||||
// So with a buggy libcore we could have both:
|
||||
// * `<dyn Display as Pointee>::Metadata == DynMetadata`
|
||||
// * `DynMetadata: !PartialEq`
|
||||
// … and cause an ICE here:
|
||||
metadata_eq_method_address::<dyn Display>();
|
||||
|
||||
// For this reason, let’s check here that bounds are satisfied:
|
||||
|
||||
static_assert_expected_bounds_for_metadata::<()>();
|
||||
static_assert_expected_bounds_for_metadata::<usize>();
|
||||
static_assert_expected_bounds_for_metadata::<DynMetadata>();
|
||||
fn static_assert_associated_type<T: ?Sized>() {
|
||||
static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>()
|
||||
}
|
||||
|
||||
fn static_assert_expected_bounds_for_metadata<Meta>()
|
||||
where
|
||||
// Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
|
||||
Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue