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`.
|
// 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;
|
||||||
|
|
|
@ -476,6 +476,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>),
|
||||||
|
|
||||||
|
@ -494,7 +497,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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +513,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[..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -554,6 +559,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,
|
||||||
|
@ -632,6 +640,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,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
|
/// 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
|
||||||
|
|
|
@ -476,6 +476,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,
|
||||||
|
@ -710,6 +711,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,
|
||||||
|
@ -832,6 +834,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 {
|
||||||
|
|
|
@ -274,7 +274,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!(
|
||||||
|
|
|
@ -133,6 +133,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)]
|
||||||
|
|
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)]
|
#[doc(inline)]
|
||||||
pub use crate::intrinsics::write_bytes;
|
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;
|
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;
|
||||||
|
|
|
@ -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)]
|
||||||
|
@ -67,8 +68,10 @@
|
||||||
#![feature(option_result_unwrap_unchecked)]
|
#![feature(option_result_unwrap_unchecked)]
|
||||||
#![feature(option_unwrap_none)]
|
#![feature(option_unwrap_none)]
|
||||||
#![feature(peekable_peek_mut)]
|
#![feature(peekable_peek_mut)]
|
||||||
|
#![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)]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::ptr::*;
|
use core::ptr::*;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_const_from_raw_parts() {
|
fn test_const_from_raw_parts() {
|
||||||
|
@ -413,3 +414,89 @@ 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 = 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
Add a link
Reference in a new issue