Skip to content

Commit d1462d8

Browse files
committed
Auto merge of #81172 - SimonSapin:ptr-metadata, r=oli-obk
Implement RFC 2580: Pointer metadata & VTable RFC: rust-lang/rfcs#2580 ~~Before merging this PR:~~ * [x] Wait for the end of the RFC’s [FCP to merge](rust-lang/rfcs#2580 (comment)). * [x] Open a tracking issue: #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`
2 parents cbf666d + cac71bf commit d1462d8

File tree

24 files changed

+865
-52
lines changed

24 files changed

+865
-52
lines changed

compiler/rustc_hir/src/lang_items.rs

+4
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ language_item_table! {
201201
// The associated item of `trait DiscriminantKind`.
202202
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
203203

204+
PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait;
205+
Metadata, sym::metadata_type, metadata_type, Target::AssocTy;
206+
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct;
207+
204208
Freeze, sym::freeze, freeze_trait, Target::Trait;
205209

206210
Drop, sym::drop, drop_trait, Target::Trait;

compiler/rustc_middle/src/traits/mod.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ pub enum ImplSource<'tcx, N> {
479479
/// ImplSource for a builtin `DeterminantKind` trait implementation.
480480
DiscriminantKind(ImplSourceDiscriminantKindData),
481481

482+
/// ImplSource for a builtin `Pointee` trait implementation.
483+
Pointee(ImplSourcePointeeData),
484+
482485
/// ImplSource automatically generated for a generator.
483486
Generator(ImplSourceGeneratorData<'tcx, N>),
484487

@@ -497,7 +500,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
497500
ImplSource::Generator(c) => c.nested,
498501
ImplSource::Object(d) => d.nested,
499502
ImplSource::FnPointer(d) => d.nested,
500-
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
503+
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
504+
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
501505
ImplSource::TraitAlias(d) => d.nested,
502506
}
503507
}
@@ -512,7 +516,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
512516
ImplSource::Generator(c) => &c.nested[..],
513517
ImplSource::Object(d) => &d.nested[..],
514518
ImplSource::FnPointer(d) => &d.nested[..],
515-
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
519+
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
520+
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
516521
ImplSource::TraitAlias(d) => &d.nested[..],
517522
}
518523
}
@@ -557,6 +562,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
557562
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
558563
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
559564
}
565+
ImplSource::Pointee(ImplSourcePointeeData) => {
566+
ImplSource::Pointee(ImplSourcePointeeData)
567+
}
560568
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
561569
alias_def_id: d.alias_def_id,
562570
substs: d.substs,
@@ -635,6 +643,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
635643
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
636644
pub struct ImplSourceDiscriminantKindData;
637645

646+
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
647+
pub struct ImplSourcePointeeData;
648+
638649
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
639650
pub struct ImplSourceTraitAliasData<'tcx, N> {
640651
pub alias_def_id: DefId,

compiler/rustc_middle/src/traits/select.rs

+3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
125125
/// Builtin implementation of `DiscriminantKind`.
126126
DiscriminantKindCandidate,
127127

128+
/// Builtin implementation of `Pointee`.
129+
PointeeCandidate,
130+
128131
TraitAliasCandidate(DefId),
129132

130133
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the

compiler/rustc_middle/src/traits/structural_impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
1919

2020
super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
2121

22+
super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
23+
2224
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
2325

2426
super::ImplSource::Param(ref n, ct) => {
@@ -110,4 +112,5 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
110112
TrivialTypeFoldableAndLiftImpls! {
111113
super::IfExpressionCause,
112114
super::ImplSourceDiscriminantKindData,
115+
super::ImplSourcePointeeData,
113116
}

compiler/rustc_middle/src/ty/sty.rs

+48
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,54 @@ impl<'tcx> TyS<'tcx> {
21332133
}
21342134
}
21352135

2136+
/// Returns the type of metadata for (potentially fat) pointers to this type.
2137+
pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
2138+
// FIXME: should this normalize?
2139+
let tail = tcx.struct_tail_without_normalization(self);
2140+
match tail.kind() {
2141+
// Sized types
2142+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
2143+
| ty::Uint(_)
2144+
| ty::Int(_)
2145+
| ty::Bool
2146+
| ty::Float(_)
2147+
| ty::FnDef(..)
2148+
| ty::FnPtr(_)
2149+
| ty::RawPtr(..)
2150+
| ty::Char
2151+
| ty::Ref(..)
2152+
| ty::Generator(..)
2153+
| ty::GeneratorWitness(..)
2154+
| ty::Array(..)
2155+
| ty::Closure(..)
2156+
| ty::Never
2157+
| ty::Error(_)
2158+
| ty::Foreign(..)
2159+
// If returned by `struct_tail_without_normalization` this is a unit struct
2160+
// without any fields, or not a struct, and therefore is Sized.
2161+
| ty::Adt(..)
2162+
// If returned by `struct_tail_without_normalization` this is the empty tuple,
2163+
// a.k.a. unit type, which is Sized
2164+
| ty::Tuple(..) => tcx.types.unit,
2165+
2166+
ty::Str | ty::Slice(_) => tcx.types.usize,
2167+
ty::Dynamic(..) => {
2168+
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
2169+
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
2170+
},
2171+
2172+
ty::Projection(_)
2173+
| ty::Param(_)
2174+
| ty::Opaque(..)
2175+
| ty::Infer(ty::TyVar(_))
2176+
| ty::Bound(..)
2177+
| ty::Placeholder(..)
2178+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2179+
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
2180+
}
2181+
}
2182+
}
2183+
21362184
/// When we create a closure, we record its kind (i.e., what trait
21372185
/// it implements) into its `ClosureSubsts` using a type
21382186
/// parameter. This is kind of a phantom type, except that the

compiler/rustc_span/src/symbol.rs

+3
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ symbols! {
475475
dropck_eyepatch,
476476
dropck_parametricity,
477477
dylib,
478+
dyn_metadata,
478479
dyn_trait,
479480
edition_macro_pats,
480481
eh_catch_typeinfo,
@@ -709,6 +710,7 @@ symbols! {
709710
memory,
710711
message,
711712
meta,
713+
metadata_type,
712714
min_align_of,
713715
min_align_of_val,
714716
min_const_fn,
@@ -831,6 +833,7 @@ symbols! {
831833
plugin,
832834
plugin_registrar,
833835
plugins,
836+
pointee_trait,
834837
pointer,
835838
pointer_trait,
836839
pointer_trait_fmt,

compiler/rustc_trait_selection/src/traits/project.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::SelectionContext;
1212
use super::SelectionError;
1313
use super::{
1414
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
15-
ImplSourceGeneratorData, ImplSourceUserDefinedData,
15+
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
1616
};
1717
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
1818

@@ -1069,6 +1069,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10691069
| ty::Error(_) => false,
10701070
}
10711071
}
1072+
super::ImplSource::Pointee(..) => {
1073+
// While `Pointee` is automatically implemented for every type,
1074+
// the concrete metadata type may not be known yet.
1075+
//
1076+
// Any type with multiple potential metadata types is therefore not eligible.
1077+
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
1078+
1079+
// FIXME: should this normalize?
1080+
let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
1081+
match tail.kind() {
1082+
ty::Bool
1083+
| ty::Char
1084+
| ty::Int(_)
1085+
| ty::Uint(_)
1086+
| ty::Float(_)
1087+
| ty::Foreign(_)
1088+
| ty::Str
1089+
| ty::Array(..)
1090+
| ty::Slice(_)
1091+
| ty::RawPtr(..)
1092+
| ty::Ref(..)
1093+
| ty::FnDef(..)
1094+
| ty::FnPtr(..)
1095+
| ty::Dynamic(..)
1096+
| ty::Closure(..)
1097+
| ty::Generator(..)
1098+
| ty::GeneratorWitness(..)
1099+
| ty::Never
1100+
// If returned by `struct_tail_without_normalization` this is a unit struct
1101+
// without any fields, or not a struct, and therefore is Sized.
1102+
| ty::Adt(..)
1103+
// If returned by `struct_tail_without_normalization` this is the empty tuple.
1104+
| ty::Tuple(..)
1105+
// Integers and floats are always Sized, and so have unit type metadata.
1106+
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
1107+
1108+
ty::Projection(..)
1109+
| ty::Opaque(..)
1110+
| ty::Param(..)
1111+
| ty::Bound(..)
1112+
| ty::Placeholder(..)
1113+
| ty::Infer(..)
1114+
| ty::Error(_) => false,
1115+
}
1116+
}
10721117
super::ImplSource::Param(..) => {
10731118
// This case tell us nothing about the value of an
10741119
// associated type. Consider:
@@ -1169,6 +1214,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
11691214
super::ImplSource::DiscriminantKind(data) => {
11701215
confirm_discriminant_kind_candidate(selcx, obligation, data)
11711216
}
1217+
super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
11721218
super::ImplSource::Object(_)
11731219
| super::ImplSource::AutoImpl(..)
11741220
| super::ImplSource::Param(..)
@@ -1256,6 +1302,26 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
12561302
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
12571303
}
12581304

1305+
fn confirm_pointee_candidate<'cx, 'tcx>(
1306+
selcx: &mut SelectionContext<'cx, 'tcx>,
1307+
obligation: &ProjectionTyObligation<'tcx>,
1308+
_: ImplSourcePointeeData,
1309+
) -> Progress<'tcx> {
1310+
let tcx = selcx.tcx();
1311+
1312+
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
1313+
let substs = tcx.mk_substs([self_ty.into()].iter());
1314+
1315+
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
1316+
1317+
let predicate = ty::ProjectionPredicate {
1318+
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
1319+
ty: self_ty.ptr_metadata_ty(tcx),
1320+
};
1321+
1322+
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
1323+
}
1324+
12591325
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
12601326
selcx: &mut SelectionContext<'cx, 'tcx>,
12611327
obligation: &ProjectionTyObligation<'tcx>,

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+3
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
267267
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
268268
// `DiscriminantKind` is automatically implemented for every type.
269269
candidates.vec.push(DiscriminantKindCandidate);
270+
} else if lang_items.pointee_trait() == Some(def_id) {
271+
// `Pointee` is automatically implemented for every type.
272+
candidates.vec.push(PointeeCandidate);
270273
} else if lang_items.sized_trait() == Some(def_id) {
271274
// Sized is never implementable by end-users, it is
272275
// always automatically computed.

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
3030
use crate::traits::{
3131
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
3232
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
33-
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
33+
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
34+
ImplSourceUserDefinedData,
3435
};
3536
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
3637
use crate::traits::{Obligation, ObligationCause};
@@ -99,6 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
99100
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
100101
}
101102

103+
PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
104+
102105
TraitAliasCandidate(alias_def_id) => {
103106
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
104107
Ok(ImplSource::TraitAlias(data))

compiler/rustc_trait_selection/src/traits/select/mod.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1318,8 +1318,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13181318
let is_global =
13191319
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
13201320

1321-
// (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
1322-
// to anything else.
1321+
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
1322+
// and `DiscriminantKindCandidate` to anything else.
13231323
//
13241324
// This is a fix for #53123 and prevents winnowing from accidentally extending the
13251325
// lifetime of a variable.
@@ -1332,8 +1332,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13321332
}
13331333

13341334
// (*)
1335-
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
1336-
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
1335+
(
1336+
BuiltinCandidate { has_nested: false }
1337+
| DiscriminantKindCandidate
1338+
| PointeeCandidate,
1339+
_,
1340+
) => true,
1341+
(
1342+
_,
1343+
BuiltinCandidate { has_nested: false }
1344+
| DiscriminantKindCandidate
1345+
| PointeeCandidate,
1346+
) => false,
13371347

13381348
(ParamCandidate(other), ParamCandidate(victim)) => {
13391349
if other.value == victim.value && victim.constness == Constness::NotConst {

compiler/rustc_ty_utils/src/instance.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ fn resolve_associated_item<'tcx>(
275275
traits::ImplSource::AutoImpl(..)
276276
| traits::ImplSource::Param(..)
277277
| traits::ImplSource::TraitAlias(..)
278-
| traits::ImplSource::DiscriminantKind(..) => None,
278+
| traits::ImplSource::DiscriminantKind(..)
279+
| traits::ImplSource::Pointee(..) => None,
279280
})
280281
}
281282

compiler/rustc_typeck/src/coherence/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
4848
let did = Some(trait_def_id);
4949
let li = tcx.lang_items();
5050

51-
// Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
51+
// Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
52+
if did == li.pointee_trait() {
53+
let span = impl_header_span(tcx, impl_def_id);
54+
struct_span_err!(
55+
tcx.sess,
56+
span,
57+
E0322,
58+
"explicit impls for the `Pointee` trait are not permitted"
59+
)
60+
.span_label(span, "impl of 'Pointee' not allowed")
61+
.emit();
62+
return;
63+
}
64+
5265
if did == li.discriminant_kind_trait() {
5366
let span = impl_header_span(tcx, impl_def_id);
5467
struct_span_err!(

0 commit comments

Comments
 (0)