Auto merge of #81172 - SimonSapin:ptr-metadata, r=oli-obk
Implement RFC 2580: Pointer metadata & VTable RFC: https://github.com/rust-lang/rfcs/pull/2580 ~~Before merging this PR:~~ * [x] Wait for the end of the RFC’s [FCP to merge](https://github.com/rust-lang/rfcs/pull/2580#issuecomment-759145278). * [x] Open a tracking issue: https://github.com/rust-lang/rust/issues/81513 * [x] Update `#[unstable]` attributes in the PR with the tracking issue number ---- This PR extends the language with a new lang item for the `Pointee` trait which is special-cased in trait resolution to implement it for all types. Even in generic contexts, parameters can be assumed to implement it without a corresponding bound. For this I mostly imitated what the compiler was already doing for the `DiscriminantKind` trait. I’m very unfamiliar with compiler internals, so careful review is appreciated. This PR also extends the standard library with new unstable APIs in `core::ptr` and `std::ptr`: ```rust pub trait Pointee { /// One of `()`, `usize`, or `DynMetadata<dyn SomeTrait>` type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } pub trait Thin = Pointee<Metadata = ()>; pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {} pub const fn from_raw_parts<T: ?Sized>(*const (), <T as Pointee>::Metadata) -> *const T {} pub const fn from_raw_parts_mut<T: ?Sized>(*mut (),<T as Pointee>::Metadata) -> *mut T {} impl<T: ?Sized> NonNull<T> { pub const fn from_raw_parts(NonNull<()>, <T as Pointee>::Metadata) -> NonNull<T> {} /// Convenience for `(ptr.cast(), metadata(ptr))` pub const fn to_raw_parts(self) -> (NonNull<()>, <T as Pointee>::Metadata) {} } impl<T: ?Sized> *const T { pub const fn to_raw_parts(self) -> (*const (), <T as Pointee>::Metadata) {} } impl<T: ?Sized> *mut T { pub const fn to_raw_parts(self) -> (*mut (), <T as Pointee>::Metadata) {} } /// `<dyn SomeTrait as Pointee>::Metadata == DynMetadata<dyn SomeTrait>` pub struct DynMetadata<Dyn: ?Sized> { // Private pointer to vtable } impl<Dyn: ?Sized> DynMetadata<Dyn> { pub fn size_of(self) -> usize {} pub fn align_of(self) -> usize {} pub fn layout(self) -> crate::alloc::Layout {} } unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {} unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Debug for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {} impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {} impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {} impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {} ``` API differences from the RFC, in areas noted as unresolved questions in the RFC: * Module-level functions instead of associated `from_raw_parts` functions on `*const T` and `*mut T`, following the precedent of `null`, `slice_from_raw_parts`, etc. * Added `to_raw_parts`
This commit is contained in:
commit
d1462d8558
24 changed files with 865 additions and 52 deletions
|
@ -201,6 +201,10 @@ language_item_table! {
|
||||||
// The associated item of `trait DiscriminantKind`.
|
// The associated item of `trait DiscriminantKind`.
|
||||||
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
|
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;
|
Freeze, sym::freeze, freeze_trait, Target::Trait;
|
||||||
|
|
||||||
Drop, sym::drop, drop_trait, Target::Trait;
|
Drop, sym::drop, drop_trait, Target::Trait;
|
||||||
|
|
|
@ -479,6 +479,9 @@ pub enum ImplSource<'tcx, N> {
|
||||||
/// ImplSource for a builtin `DeterminantKind` trait implementation.
|
/// ImplSource for a builtin `DeterminantKind` trait implementation.
|
||||||
DiscriminantKind(ImplSourceDiscriminantKindData),
|
DiscriminantKind(ImplSourceDiscriminantKindData),
|
||||||
|
|
||||||
|
/// ImplSource for a builtin `Pointee` trait implementation.
|
||||||
|
Pointee(ImplSourcePointeeData),
|
||||||
|
|
||||||
/// ImplSource automatically generated for a generator.
|
/// ImplSource automatically generated for a generator.
|
||||||
Generator(ImplSourceGeneratorData<'tcx, N>),
|
Generator(ImplSourceGeneratorData<'tcx, N>),
|
||||||
|
|
||||||
|
@ -497,7 +500,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Generator(c) => c.nested,
|
ImplSource::Generator(c) => c.nested,
|
||||||
ImplSource::Object(d) => d.nested,
|
ImplSource::Object(d) => d.nested,
|
||||||
ImplSource::FnPointer(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,
|
ImplSource::TraitAlias(d) => d.nested,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,7 +516,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Generator(c) => &c.nested[..],
|
ImplSource::Generator(c) => &c.nested[..],
|
||||||
ImplSource::Object(d) => &d.nested[..],
|
ImplSource::Object(d) => &d.nested[..],
|
||||||
ImplSource::FnPointer(d) => &d.nested[..],
|
ImplSource::FnPointer(d) => &d.nested[..],
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
|
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
||||||
ImplSource::TraitAlias(d) => &d.nested[..],
|
ImplSource::TraitAlias(d) => &d.nested[..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,6 +562,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
}
|
}
|
||||||
|
ImplSource::Pointee(ImplSourcePointeeData) => {
|
||||||
|
ImplSource::Pointee(ImplSourcePointeeData)
|
||||||
|
}
|
||||||
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
|
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
|
||||||
alias_def_id: d.alias_def_id,
|
alias_def_id: d.alias_def_id,
|
||||||
substs: d.substs,
|
substs: d.substs,
|
||||||
|
@ -635,6 +643,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub struct ImplSourceDiscriminantKindData;
|
pub struct ImplSourceDiscriminantKindData;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
pub struct ImplSourcePointeeData;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
||||||
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
||||||
pub alias_def_id: DefId,
|
pub alias_def_id: DefId,
|
||||||
|
|
|
@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
/// Builtin implementation of `DiscriminantKind`.
|
/// Builtin implementation of `DiscriminantKind`.
|
||||||
DiscriminantKindCandidate,
|
DiscriminantKindCandidate,
|
||||||
|
|
||||||
|
/// Builtin implementation of `Pointee`.
|
||||||
|
PointeeCandidate,
|
||||||
|
|
||||||
TraitAliasCandidate(DefId),
|
TraitAliasCandidate(DefId),
|
||||||
|
|
||||||
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
|
/// 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::DiscriminantKind(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
|
super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
super::ImplSource::Param(ref n, ct) => {
|
super::ImplSource::Param(ref n, ct) => {
|
||||||
|
@ -110,4 +112,5 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
|
||||||
TrivialTypeFoldableAndLiftImpls! {
|
TrivialTypeFoldableAndLiftImpls! {
|
||||||
super::IfExpressionCause,
|
super::IfExpressionCause,
|
||||||
super::ImplSourceDiscriminantKindData,
|
super::ImplSourceDiscriminantKindData,
|
||||||
|
super::ImplSourcePointeeData,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2133,6 +2133,54 @@ 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(..) => {
|
||||||
|
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
|
||||||
|
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
|
||||||
|
},
|
||||||
|
|
||||||
|
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
|
/// When we create a closure, we record its kind (i.e., what trait
|
||||||
/// it implements) into its `ClosureSubsts` using a type
|
/// it implements) into its `ClosureSubsts` using a type
|
||||||
/// parameter. This is kind of a phantom type, except that the
|
/// parameter. This is kind of a phantom type, except that the
|
||||||
|
|
|
@ -475,6 +475,7 @@ symbols! {
|
||||||
dropck_eyepatch,
|
dropck_eyepatch,
|
||||||
dropck_parametricity,
|
dropck_parametricity,
|
||||||
dylib,
|
dylib,
|
||||||
|
dyn_metadata,
|
||||||
dyn_trait,
|
dyn_trait,
|
||||||
edition_macro_pats,
|
edition_macro_pats,
|
||||||
eh_catch_typeinfo,
|
eh_catch_typeinfo,
|
||||||
|
@ -709,6 +710,7 @@ symbols! {
|
||||||
memory,
|
memory,
|
||||||
message,
|
message,
|
||||||
meta,
|
meta,
|
||||||
|
metadata_type,
|
||||||
min_align_of,
|
min_align_of,
|
||||||
min_align_of_val,
|
min_align_of_val,
|
||||||
min_const_fn,
|
min_const_fn,
|
||||||
|
@ -831,6 +833,7 @@ symbols! {
|
||||||
plugin,
|
plugin,
|
||||||
plugin_registrar,
|
plugin_registrar,
|
||||||
plugins,
|
plugins,
|
||||||
|
pointee_trait,
|
||||||
pointer,
|
pointer,
|
||||||
pointer_trait,
|
pointer_trait,
|
||||||
pointer_trait_fmt,
|
pointer_trait_fmt,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use super::SelectionContext;
|
||||||
use super::SelectionError;
|
use super::SelectionError;
|
||||||
use super::{
|
use super::{
|
||||||
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
|
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
|
||||||
ImplSourceGeneratorData, ImplSourceUserDefinedData,
|
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
|
||||||
};
|
};
|
||||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||||
|
|
||||||
|
@ -1069,6 +1069,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
| ty::Error(_) => false,
|
| 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(..) => {
|
super::ImplSource::Param(..) => {
|
||||||
// This case tell us nothing about the value of an
|
// This case tell us nothing about the value of an
|
||||||
// associated type. Consider:
|
// associated type. Consider:
|
||||||
|
@ -1169,6 +1214,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||||
super::ImplSource::DiscriminantKind(data) => {
|
super::ImplSource::DiscriminantKind(data) => {
|
||||||
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
||||||
}
|
}
|
||||||
|
super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
|
||||||
super::ImplSource::Object(_)
|
super::ImplSource::Object(_)
|
||||||
| super::ImplSource::AutoImpl(..)
|
| super::ImplSource::AutoImpl(..)
|
||||||
| super::ImplSource::Param(..)
|
| 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)
|
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>(
|
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
|
|
|
@ -267,6 +267,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
|
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
|
||||||
// `DiscriminantKind` is automatically implemented for every type.
|
// `DiscriminantKind` is automatically implemented for every type.
|
||||||
candidates.vec.push(DiscriminantKindCandidate);
|
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) {
|
} else if lang_items.sized_trait() == Some(def_id) {
|
||||||
// Sized is never implementable by end-users, it is
|
// Sized is never implementable by end-users, it is
|
||||||
// always automatically computed.
|
// always automatically computed.
|
||||||
|
|
|
@ -30,7 +30,8 @@ use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
||||||
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
||||||
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
|
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
||||||
|
ImplSourceUserDefinedData,
|
||||||
};
|
};
|
||||||
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
||||||
use crate::traits::{Obligation, ObligationCause};
|
use crate::traits::{Obligation, ObligationCause};
|
||||||
|
@ -99,6 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
|
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
|
||||||
|
|
||||||
TraitAliasCandidate(alias_def_id) => {
|
TraitAliasCandidate(alias_def_id) => {
|
||||||
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
|
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
|
||||||
Ok(ImplSource::TraitAlias(data))
|
Ok(ImplSource::TraitAlias(data))
|
||||||
|
|
|
@ -1318,8 +1318,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let is_global =
|
let is_global =
|
||||||
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
|
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
|
||||||
|
|
||||||
// (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
|
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
|
||||||
// to anything else.
|
// and `DiscriminantKindCandidate` to anything else.
|
||||||
//
|
//
|
||||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||||
// lifetime of a variable.
|
// 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)) => {
|
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||||
if other.value == victim.value && victim.constness == Constness::NotConst {
|
if other.value == victim.value && victim.constness == Constness::NotConst {
|
||||||
|
|
|
@ -275,7 +275,8 @@ fn resolve_associated_item<'tcx>(
|
||||||
traits::ImplSource::AutoImpl(..)
|
traits::ImplSource::AutoImpl(..)
|
||||||
| traits::ImplSource::Param(..)
|
| traits::ImplSource::Param(..)
|
||||||
| traits::ImplSource::TraitAlias(..)
|
| 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 did = Some(trait_def_id);
|
||||||
let li = tcx.lang_items();
|
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() {
|
if did == li.discriminant_kind_trait() {
|
||||||
let span = impl_header_span(tcx, impl_def_id);
|
let span = impl_header_span(tcx, impl_def_id);
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
|
|
|
@ -673,6 +673,14 @@ mod impls {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> Hash for *const T {
|
impl<T: ?Sized> Hash for *const T {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
{
|
||||||
|
let (address, metadata) = self.to_raw_parts();
|
||||||
|
state.write_usize(address as usize);
|
||||||
|
metadata.hash(state);
|
||||||
|
}
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||||
// Thin pointer
|
// Thin pointer
|
||||||
state.write_usize(*self as *const () as usize);
|
state.write_usize(*self as *const () as usize);
|
||||||
|
@ -689,10 +697,19 @@ mod impls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> Hash for *mut T {
|
impl<T: ?Sized> Hash for *mut T {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
{
|
||||||
|
let (address, metadata) = self.to_raw_parts();
|
||||||
|
state.write_usize(address as usize);
|
||||||
|
metadata.hash(state);
|
||||||
|
}
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||||
// Thin pointer
|
// Thin pointer
|
||||||
state.write_usize(*self as *const () as usize);
|
state.write_usize(*self as *const () as usize);
|
||||||
|
@ -709,4 +726,5 @@ mod impls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
#![feature(extended_key_value_attributes)]
|
#![feature(extended_key_value_attributes)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![feature(fundamental)]
|
#![feature(fundamental)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
|
||||||
#![feature(intrinsics)]
|
#![feature(intrinsics)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(link_llvm_intrinsics)]
|
#![feature(link_llvm_intrinsics)]
|
||||||
|
@ -123,6 +124,7 @@
|
||||||
#![feature(auto_traits)]
|
#![feature(auto_traits)]
|
||||||
#![feature(or_patterns)]
|
#![feature(or_patterns)]
|
||||||
#![feature(prelude_import)]
|
#![feature(prelude_import)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
|
||||||
#![feature(repr_simd, platform_intrinsics)]
|
#![feature(repr_simd, platform_intrinsics)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(simd_ffi)]
|
#![feature(simd_ffi)]
|
||||||
|
@ -133,6 +135,7 @@
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![feature(str_split_as_str)]
|
#![feature(str_split_as_str)]
|
||||||
#![feature(str_split_inclusive_as_str)]
|
#![feature(str_split_inclusive_as_str)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
#![feature(transparent_unions)]
|
#![feature(transparent_unions)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
|
|
|
@ -48,6 +48,17 @@ impl<T: ?Sized> *const T {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decompose a (possibly wide) pointer into is address and metadata components.
|
||||||
|
///
|
||||||
|
/// The pointer can be later reconstructed with [`from_raw_parts`].
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata) {
|
||||||
|
(self.cast(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||||
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
||||||
/// must be used instead.
|
/// must be used instead.
|
||||||
|
@ -905,10 +916,15 @@ impl<T> *const [T] {
|
||||||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||||
pub const fn len(self) -> usize {
|
pub const fn len(self) -> usize {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||||
// Only `std` can make this guarantee.
|
// Only `std` can make this guarantee.
|
||||||
unsafe { Repr { rust: self }.raw }.len
|
unsafe { Repr { rust: self }.raw }.len
|
||||||
}
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
metadata(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a raw pointer to the slice's buffer.
|
/// Returns a raw pointer to the slice's buffer.
|
||||||
///
|
///
|
||||||
|
|
265
library/core/src/ptr/metadata.rs
Normal file
265
library/core/src/ptr/metadata.rs
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
#![unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
|
||||||
|
use crate::fmt;
|
||||||
|
use crate::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
/// Provides the pointer metadata type of any pointed-to type.
|
||||||
|
///
|
||||||
|
/// # Pointer metadata
|
||||||
|
///
|
||||||
|
/// Raw pointer types and reference types in Rust can be thought of as made of two parts:
|
||||||
|
/// a data pointer that contains the memory address of the value, and some metadata.
|
||||||
|
///
|
||||||
|
/// For statically-sized types (that implement the `Sized` traits)
|
||||||
|
/// as well as for `extern` types,
|
||||||
|
/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.
|
||||||
|
///
|
||||||
|
/// Pointers to [dynamically-sized types][dst] are said to be “wide” or “fat”,
|
||||||
|
/// they have non-zero-sized metadata:
|
||||||
|
///
|
||||||
|
/// * For structs whose last field is a DST, metadata is the metadata for the last field
|
||||||
|
/// * For the `str` type, metadata is the length in bytes as `usize`
|
||||||
|
/// * For slice types like `[T]`, metadata is the length in items as `usize`
|
||||||
|
/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata]
|
||||||
|
/// (e.g. `DynMetadata<dyn SomeTrait>`)
|
||||||
|
///
|
||||||
|
/// In the future, the Rust language may gain new kinds of types
|
||||||
|
/// that have different pointer metadata.
|
||||||
|
///
|
||||||
|
/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # The `Pointee` trait
|
||||||
|
///
|
||||||
|
/// The point of this trait is its `Metadata` associated type,
|
||||||
|
/// which is `()` or `usize` or `DynMetadata<_>` as described above.
|
||||||
|
/// It is automatically implemented for every type.
|
||||||
|
/// It can be assumed to be implemented in a generic context, even without a corresponding bound.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// Raw pointers can be decomposed into the data address and metadata components
|
||||||
|
/// with their [`to_raw_parts`] method.
|
||||||
|
///
|
||||||
|
/// Alternatively, metadata alone can be extracted with the [`metadata`] function.
|
||||||
|
/// A reference can be passed to [`metadata`] and implicitly coerced.
|
||||||
|
///
|
||||||
|
/// A (possibly-wide) pointer can be put back together from its address and metadata
|
||||||
|
/// with [`from_raw_parts`] or [`from_raw_parts_mut`].
|
||||||
|
///
|
||||||
|
/// [`to_raw_parts`]: *const::to_raw_parts
|
||||||
|
#[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”.
|
||||||
|
///
|
||||||
|
/// This includes statically-`Sized` types and `extern` types.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```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 = "81513")]
|
||||||
|
// 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.
|
||||||
|
///
|
||||||
|
/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function
|
||||||
|
/// as they implicitly coerce to `*const T`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(ptr_metadata)]
|
||||||
|
///
|
||||||
|
/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
|
||||||
|
/// ```
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const 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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forms a (possibly-wide) raw pointer from a data address and metadata.
|
||||||
|
///
|
||||||
|
/// This function is safe but the returned pointer is not necessarily safe to dereference.
|
||||||
|
/// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements.
|
||||||
|
/// For trait objects, the metadata must come from a pointer to the same underlying ereased type.
|
||||||
|
///
|
||||||
|
/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_raw_parts<T: ?Sized>(
|
||||||
|
data_address: *const (),
|
||||||
|
metadata: <T as Pointee>::Metadata,
|
||||||
|
) -> *const T {
|
||||||
|
// 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 { components: PtrComponents { data_address, metadata } }.const_ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs the same functionality as [`from_raw_parts`], except that a
|
||||||
|
/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
|
||||||
|
///
|
||||||
|
/// See the documentation of [`from_raw_parts`] for more details.
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_raw_parts_mut<T: ?Sized>(
|
||||||
|
data_address: *mut (),
|
||||||
|
metadata: <T as Pointee>::Metadata,
|
||||||
|
) -> *mut T {
|
||||||
|
// 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 { components: PtrComponents { data_address, metadata } }.mut_ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) union PtrRepr<T: ?Sized> {
|
||||||
|
pub(crate) const_ptr: *const T,
|
||||||
|
pub(crate) mut_ptr: *mut T,
|
||||||
|
pub(crate) components: PtrComponents<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct PtrComponents<T: ?Sized> {
|
||||||
|
pub(crate) data_address: *const (),
|
||||||
|
pub(crate) 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 = dyn SomeTrait` trait object type.
|
||||||
|
///
|
||||||
|
/// It is a pointer to a vtable (virtual call table)
|
||||||
|
/// that represents all the necessary information
|
||||||
|
/// to manipulate the concrete type stored inside a trait object.
|
||||||
|
/// The vtable notably it contains:
|
||||||
|
///
|
||||||
|
/// * type size
|
||||||
|
/// * type alignment
|
||||||
|
/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)
|
||||||
|
/// * pointers to all the methods for the type’s implementation of the trait
|
||||||
|
///
|
||||||
|
/// Note that the first three are special because they’re necessary to allocate, drop,
|
||||||
|
/// and deallocate any trait object.
|
||||||
|
///
|
||||||
|
/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
|
||||||
|
/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
|
||||||
|
#[lang = "dyn_metadata"]
|
||||||
|
pub struct DynMetadata<Dyn: ?Sized> {
|
||||||
|
vtable_ptr: &'static VTable,
|
||||||
|
phantom: crate::marker::PhantomData<Dyn>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The common prefix of all vtables. It is followed by function pointers for trait methods.
|
||||||
|
///
|
||||||
|
/// Private implementation detail of `DynMetadata::size_of` etc.
|
||||||
|
#[repr(C)]
|
||||||
|
struct VTable {
|
||||||
|
drop_in_place: fn(*mut ()),
|
||||||
|
size_of: usize,
|
||||||
|
align_of: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> DynMetadata<Dyn> {
|
||||||
|
/// Returns the size of the type associated with this vtable.
|
||||||
|
#[inline]
|
||||||
|
pub fn size_of(self) -> usize {
|
||||||
|
self.vtable_ptr.size_of
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the alignment of the type associated with this vtable.
|
||||||
|
#[inline]
|
||||||
|
pub fn align_of(self) -> usize {
|
||||||
|
self.vtable_ptr.align_of
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size and alignment together as a `Layout`
|
||||||
|
#[inline]
|
||||||
|
pub fn layout(self) -> crate::alloc::Layout {
|
||||||
|
// SAFETY: the compiler emitted this vtable for a concrete Rust type which
|
||||||
|
// is known to have a valid layout. Same rationale as in `Layout::for_value`.
|
||||||
|
unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
|
||||||
|
unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual impls needed to avoid `Dyn: $Trait` bounds.
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
||||||
|
(self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
|
||||||
|
#[inline]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,14 @@ pub use crate::intrinsics::copy;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::intrinsics::write_bytes;
|
pub use crate::intrinsics::write_bytes;
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
mod metadata;
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub(crate) use metadata::PtrRepr;
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
|
||||||
|
|
||||||
mod non_null;
|
mod non_null;
|
||||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||||
pub use non_null::NonNull;
|
pub use non_null::NonNull;
|
||||||
|
@ -220,6 +228,7 @@ pub const fn null_mut<T>() -> *mut T {
|
||||||
0 as *mut T
|
0 as *mut T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) union Repr<T> {
|
pub(crate) union Repr<T> {
|
||||||
pub(crate) rust: *const [T],
|
pub(crate) rust: *const [T],
|
||||||
|
@ -227,12 +236,14 @@ pub(crate) union Repr<T> {
|
||||||
pub(crate) raw: FatPtr<T>,
|
pub(crate) raw: FatPtr<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) struct FatPtr<T> {
|
pub(crate) struct FatPtr<T> {
|
||||||
data: *const T,
|
data: *const T,
|
||||||
pub(crate) len: usize,
|
pub(crate) len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
// Manual impl needed to avoid `T: Clone` bound.
|
// Manual impl needed to avoid `T: Clone` bound.
|
||||||
impl<T> Clone for FatPtr<T> {
|
impl<T> Clone for FatPtr<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -240,6 +251,7 @@ impl<T> Clone for FatPtr<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
// Manual impl needed to avoid `T: Copy` bound.
|
// Manual impl needed to avoid `T: Copy` bound.
|
||||||
impl<T> Copy for FatPtr<T> {}
|
impl<T> Copy for FatPtr<T> {}
|
||||||
|
|
||||||
|
@ -267,10 +279,15 @@ impl<T> Copy for FatPtr<T> {}
|
||||||
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
||||||
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
||||||
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
|
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
|
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
|
||||||
// and FatPtr have the same memory layouts. Only std can make this
|
// and FatPtr have the same memory layouts. Only std can make this
|
||||||
// guarantee.
|
// guarantee.
|
||||||
unsafe { Repr { raw: FatPtr { data, len } }.rust }
|
unsafe { Repr { raw: FatPtr { data, len } }.rust }
|
||||||
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
from_raw_parts(data.cast(), len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
|
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
|
||||||
|
@ -302,9 +319,14 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
|
||||||
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
||||||
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
||||||
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
|
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
|
||||||
// and FatPtr have the same memory layouts
|
// and FatPtr have the same memory layouts
|
||||||
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
|
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
|
||||||
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
from_raw_parts_mut(data.cast(), len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Swaps the values at two mutable locations of the same type, without
|
/// Swaps the values at two mutable locations of the same type, without
|
||||||
|
|
|
@ -47,6 +47,17 @@ impl<T: ?Sized> *mut T {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decompose a (possibly wide) pointer into is address and metadata components.
|
||||||
|
///
|
||||||
|
/// The pointer can be later reconstructed with [`from_raw_parts_mut`].
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
|
||||||
|
(self.cast(), super::metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||||
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
||||||
/// must be used instead.
|
/// must be used instead.
|
||||||
|
@ -1162,10 +1173,15 @@ impl<T> *mut [T] {
|
||||||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||||
pub const fn len(self) -> usize {
|
pub const fn len(self) -> usize {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||||
// Only `std` can make this guarantee.
|
// Only `std` can make this guarantee.
|
||||||
unsafe { Repr { rust_mut: self }.raw }.len
|
unsafe { Repr { rust_mut: self }.raw }.len
|
||||||
}
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
metadata(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a raw pointer to the slice's buffer.
|
/// Returns a raw pointer to the slice's buffer.
|
||||||
///
|
///
|
||||||
|
|
|
@ -175,6 +175,37 @@ impl<T: ?Sized> NonNull<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
|
||||||
|
/// `NonNull` pointer is returned, as opposed to a raw `*const` pointer.
|
||||||
|
///
|
||||||
|
/// See the documentation of [`std::ptr::from_raw_parts`] for more details.
|
||||||
|
///
|
||||||
|
/// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_raw_parts(
|
||||||
|
data_address: NonNull<()>,
|
||||||
|
metadata: <T as super::Pointee>::Metadata,
|
||||||
|
) -> NonNull<T> {
|
||||||
|
// SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_address` is.
|
||||||
|
unsafe {
|
||||||
|
NonNull::new_unchecked(super::from_raw_parts_mut(data_address.as_ptr(), metadata))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decompose a (possibly wide) pointer into is address and metadata components.
|
||||||
|
///
|
||||||
|
/// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata) {
|
||||||
|
(self.cast(), super::metadata(self.as_ptr()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Acquires the underlying `*mut` pointer.
|
/// Acquires the underlying `*mut` pointer.
|
||||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||||
#[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
|
#[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
|
||||||
|
|
|
@ -94,10 +94,24 @@ impl<T> [T] {
|
||||||
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
|
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
|
||||||
#[rustc_allow_const_fn_unstable(const_fn_union)]
|
#[rustc_allow_const_fn_unstable(const_fn_union)]
|
||||||
pub const fn len(&self) -> usize {
|
pub const fn len(&self) -> usize {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
{
|
||||||
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
|
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
|
||||||
// Only `std` can make this guarantee.
|
// Only `std` can make this guarantee.
|
||||||
unsafe { crate::ptr::Repr { rust: self }.raw.len }
|
unsafe { crate::ptr::Repr { rust: self }.raw.len }
|
||||||
}
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
{
|
||||||
|
// FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
|
||||||
|
// As of this writing this causes a "Const-stable functions can only call other
|
||||||
|
// const-stable functions" error.
|
||||||
|
|
||||||
|
// 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 { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the slice has a length of 0.
|
/// Returns `true` if the slice has a length of 0.
|
||||||
///
|
///
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#![feature(duration_saturating_ops)]
|
#![feature(duration_saturating_ops)]
|
||||||
#![feature(duration_zero)]
|
#![feature(duration_zero)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
|
#![feature(extern_types)]
|
||||||
#![feature(fixed_size_array)]
|
#![feature(fixed_size_array)]
|
||||||
#![feature(flt2dec)]
|
#![feature(flt2dec)]
|
||||||
#![feature(fmt_internals)]
|
#![feature(fmt_internals)]
|
||||||
|
@ -68,8 +69,10 @@
|
||||||
#![feature(result_into_ok_or_err)]
|
#![feature(result_into_ok_or_err)]
|
||||||
#![feature(option_unwrap_none)]
|
#![feature(option_unwrap_none)]
|
||||||
#![feature(peekable_peek_mut)]
|
#![feature(peekable_peek_mut)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
#![feature(unsafe_block_in_unsafe_fn)]
|
#![feature(unsafe_block_in_unsafe_fn)]
|
||||||
|
#![feature(unsized_tuple_coercion)]
|
||||||
#![feature(int_bits_const)]
|
#![feature(int_bits_const)]
|
||||||
#![feature(nonzero_leading_trailing_zeros)]
|
#![feature(nonzero_leading_trailing_zeros)]
|
||||||
#![feature(const_option)]
|
#![feature(const_option)]
|
||||||
|
@ -77,6 +80,7 @@
|
||||||
#![feature(slice_group_by)]
|
#![feature(slice_group_by)]
|
||||||
#![feature(trusted_random_access)]
|
#![feature(trusted_random_access)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(unsize))]
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
use core::ptr;
|
||||||
use core::ptr::*;
|
use core::ptr::*;
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_const_from_raw_parts() {
|
fn test_const_from_raw_parts() {
|
||||||
|
@ -413,3 +417,253 @@ fn offset_from() {
|
||||||
assert_eq!(ptr2.offset(-2), ptr1);
|
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<dyn Debug> = metadata(&4_u16 as &dyn Debug);
|
||||||
|
let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
|
||||||
|
let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
|
||||||
|
let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
|
||||||
|
let vtable_5: DynMetadata<dyn Display> =
|
||||||
|
metadata(&Pair(true, 7_u32) as &Pair<bool, 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);
|
||||||
|
let address_5: usize = std::mem::transmute(vtable_5);
|
||||||
|
// Different trait => different vtable pointer
|
||||||
|
assert_ne!(address_1, address_2);
|
||||||
|
// Different erased type => different vtable pointer
|
||||||
|
assert_ne!(address_2, address_3);
|
||||||
|
// Same erased type and same trait => same vtable pointer
|
||||||
|
assert_eq!(address_3, address_4);
|
||||||
|
assert_eq!(address_3, address_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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:
|
||||||
|
|
||||||
|
let _ = static_assert_expected_bounds_for_metadata::<()>;
|
||||||
|
let _ = static_assert_expected_bounds_for_metadata::<usize>;
|
||||||
|
let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
|
||||||
|
fn _static_assert_associated_type<T: ?Sized>() {
|
||||||
|
let _ = 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,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
fn dyn_metadata() {
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(align(32))]
|
||||||
|
struct Something([u8; 47]);
|
||||||
|
|
||||||
|
let value = Something([0; 47]);
|
||||||
|
let trait_object: &dyn Debug = &value;
|
||||||
|
let meta = metadata(trait_object);
|
||||||
|
|
||||||
|
assert_eq!(meta.size_of(), 64);
|
||||||
|
assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
|
||||||
|
assert_eq!(meta.align_of(), 32);
|
||||||
|
assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
|
||||||
|
assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
|
||||||
|
|
||||||
|
assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
fn from_raw_parts() {
|
||||||
|
let mut value = 5_u32;
|
||||||
|
let address = &mut value as *mut _ as *mut ();
|
||||||
|
let trait_object: &dyn Display = &mut value;
|
||||||
|
let vtable = metadata(trait_object);
|
||||||
|
let trait_object = NonNull::from(trait_object);
|
||||||
|
|
||||||
|
assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
|
||||||
|
assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
|
||||||
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
|
||||||
|
|
||||||
|
let mut array = [5_u32, 5, 5, 5, 5];
|
||||||
|
let address = &mut array as *mut _ as *mut ();
|
||||||
|
let array_ptr = NonNull::from(&mut array);
|
||||||
|
let slice_ptr = NonNull::from(&mut array[..]);
|
||||||
|
|
||||||
|
assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
|
||||||
|
assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
|
||||||
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
|
||||||
|
|
||||||
|
assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
|
||||||
|
assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
|
||||||
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
fn thin_box() {
|
||||||
|
let foo = ThinBox::<dyn Display>::new(4);
|
||||||
|
assert_eq!(foo.to_string(), "4");
|
||||||
|
drop(foo);
|
||||||
|
let bar = ThinBox::<dyn Display>::new(7);
|
||||||
|
assert_eq!(bar.to_string(), "7");
|
||||||
|
|
||||||
|
// A slightly more interesting library that could be built on top of metadata APIs.
|
||||||
|
//
|
||||||
|
// * It could be generalized to any `T: ?Sized` (not just trait object)
|
||||||
|
// if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
|
||||||
|
// * Constructing a `ThinBox` without consuming and deallocating a `Box`
|
||||||
|
// requires either the unstable `Unsize` marker trait,
|
||||||
|
// or the unstable `unsized_locals` language feature,
|
||||||
|
// or taking `&dyn T` and restricting to `T: Copy`.
|
||||||
|
|
||||||
|
use std::alloc::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
struct ThinBox<T>
|
||||||
|
where
|
||||||
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
||||||
|
{
|
||||||
|
ptr: NonNull<DynMetadata<T>>,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ThinBox<T>
|
||||||
|
where
|
||||||
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
||||||
|
{
|
||||||
|
pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
|
||||||
|
let unsized_: &T = &value;
|
||||||
|
let meta = metadata(unsized_);
|
||||||
|
let meta_layout = Layout::for_value(&meta);
|
||||||
|
let value_layout = Layout::for_value(&value);
|
||||||
|
let (layout, offset) = meta_layout.extend(value_layout).unwrap();
|
||||||
|
// `DynMetadata` is pointer-sized:
|
||||||
|
assert!(layout.size() > 0);
|
||||||
|
// If `ThinBox<T>` is generalized to any `T: ?Sized`,
|
||||||
|
// handle ZSTs with a dangling pointer without going through `alloc()`,
|
||||||
|
// like `Box<T>` does.
|
||||||
|
unsafe {
|
||||||
|
let ptr = NonNull::new(alloc(layout))
|
||||||
|
.unwrap_or_else(|| handle_alloc_error(layout))
|
||||||
|
.cast::<DynMetadata<T>>();
|
||||||
|
ptr.as_ptr().write(meta);
|
||||||
|
ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
|
||||||
|
Self { ptr, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn meta(&self) -> DynMetadata<T> {
|
||||||
|
unsafe { *self.ptr.as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(&self) -> (Layout, usize) {
|
||||||
|
let meta = self.meta();
|
||||||
|
Layout::for_value(&meta).extend(meta.layout()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_ptr(&self) -> *const T {
|
||||||
|
let (_, offset) = self.layout();
|
||||||
|
let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
|
||||||
|
ptr::from_raw_parts(data_ptr.cast(), self.meta())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_mut_ptr(&mut self) -> *mut T {
|
||||||
|
let (_, offset) = self.layout();
|
||||||
|
// FIXME: can this line be shared with the same in `value_ptr()`
|
||||||
|
// without upsetting Stacked Borrows?
|
||||||
|
let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
|
||||||
|
from_raw_parts_mut(data_ptr.cast(), self.meta())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for ThinBox<T>
|
||||||
|
where
|
||||||
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
||||||
|
{
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
unsafe { &*self.value_ptr() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::DerefMut for ThinBox<T>
|
||||||
|
where
|
||||||
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
||||||
|
{
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
unsafe { &mut *self.value_mut_ptr() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Drop for ThinBox<T>
|
||||||
|
where
|
||||||
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let (layout, _) = self.layout();
|
||||||
|
unsafe {
|
||||||
|
drop_in_place::<T>(&mut **self);
|
||||||
|
dealloc(self.ptr.cast().as_ptr(), layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -275,6 +275,7 @@
|
||||||
#![feature(int_error_matching)]
|
#![feature(int_error_matching)]
|
||||||
#![feature(integer_atomics)]
|
#![feature(integer_atomics)]
|
||||||
#![feature(into_future)]
|
#![feature(into_future)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(link_args)]
|
#![feature(link_args)]
|
||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
#![deny(broken_intra_doc_links)]
|
#![deny(broken_intra_doc_links)]
|
||||||
|
#![feature(intra_doc_pointers)]
|
||||||
|
|
||||||
pub use std::*;
|
pub use std::*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue