Skip to content

Commit 696b239

Browse files
committed
Add ptr::Pointee trait (for all types) and ptr::metadata function
RFC: rust-lang/rfcs#2580
1 parent 9503ea1 commit 696b239

File tree

17 files changed

+349
-10
lines changed

17 files changed

+349
-10
lines changed

compiler/rustc_hir/src/lang_items.rs

Lines changed: 4 additions & 0 deletions
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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ pub enum ImplSource<'tcx, N> {
476476
/// ImplSource for a builtin `DeterminantKind` trait implementation.
477477
DiscriminantKind(ImplSourceDiscriminantKindData),
478478

479+
/// ImplSource for a builtin `Pointee` trait implementation.
480+
Pointee(ImplSourcePointeeData),
481+
479482
/// ImplSource automatically generated for a generator.
480483
Generator(ImplSourceGeneratorData<'tcx, N>),
481484

@@ -494,7 +497,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
494497
ImplSource::Generator(c) => c.nested,
495498
ImplSource::Object(d) => d.nested,
496499
ImplSource::FnPointer(d) => d.nested,
497-
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
500+
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
501+
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
498502
ImplSource::TraitAlias(d) => d.nested,
499503
}
500504
}
@@ -509,7 +513,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
509513
ImplSource::Generator(c) => &c.nested[..],
510514
ImplSource::Object(d) => &d.nested[..],
511515
ImplSource::FnPointer(d) => &d.nested[..],
512-
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
516+
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
517+
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
513518
ImplSource::TraitAlias(d) => &d.nested[..],
514519
}
515520
}
@@ -554,6 +559,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
554559
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
555560
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
556561
}
562+
ImplSource::Pointee(ImplSourcePointeeData) => {
563+
ImplSource::Pointee(ImplSourcePointeeData)
564+
}
557565
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
558566
alias_def_id: d.alias_def_id,
559567
substs: d.substs,
@@ -632,6 +640,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
632640
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
633641
pub struct ImplSourceDiscriminantKindData;
634642

643+
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
644+
pub struct ImplSourcePointeeData;
645+
635646
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
636647
pub struct ImplSourceTraitAliasData<'tcx, N> {
637648
pub alias_def_id: DefId,

compiler/rustc_middle/src/traits/select.rs

Lines changed: 3 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,51 @@ 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(..) => tcx.type_of(tcx.lang_items().dyn_metadata().unwrap()),
2168+
2169+
ty::Projection(_)
2170+
| ty::Param(_)
2171+
| ty::Opaque(..)
2172+
| ty::Infer(ty::TyVar(_))
2173+
| ty::Bound(..)
2174+
| ty::Placeholder(..)
2175+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2176+
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
2177+
}
2178+
}
2179+
}
2180+
21362181
/// When we create a closure, we record its kind (i.e., what trait
21372182
/// it implements) into its `ClosureSubsts` using a type
21382183
/// parameter. This is kind of a phantom type, except that the

compiler/rustc_span/src/symbol.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ symbols! {
476476
dropck_eyepatch,
477477
dropck_parametricity,
478478
dylib,
479+
dyn_metadata,
479480
dyn_trait,
480481
edition_macro_pats,
481482
eh_catch_typeinfo,
@@ -710,6 +711,7 @@ symbols! {
710711
memory,
711712
message,
712713
meta,
714+
metadata_type,
713715
min_align_of,
714716
min_align_of_val,
715717
min_const_fn,
@@ -832,6 +834,7 @@ symbols! {
832834
plugin,
833835
plugin_registrar,
834836
plugins,
837+
pointee_trait,
835838
pointer,
836839
pointer_trait,
837840
pointer_trait_fmt,

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 67 additions & 1 deletion
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 4 additions & 1 deletion
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

Lines changed: 14 additions & 4 deletions
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,8 @@ fn resolve_associated_item<'tcx>(
274274
traits::ImplSource::AutoImpl(..)
275275
| traits::ImplSource::Param(..)
276276
| traits::ImplSource::TraitAlias(..)
277-
| traits::ImplSource::DiscriminantKind(..) => None,
277+
| traits::ImplSource::DiscriminantKind(..)
278+
| traits::ImplSource::Pointee(..) => None,
278279
})
279280
}
280281

compiler/rustc_typeck/src/coherence/mod.rs

Lines changed: 14 additions & 1 deletion
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!(

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
#![feature(stmt_expr_attributes)]
134134
#![feature(str_split_as_str)]
135135
#![feature(str_split_inclusive_as_str)]
136+
#![feature(trait_alias)]
136137
#![feature(transparent_unions)]
137138
#![feature(try_blocks)]
138139
#![feature(unboxed_closures)]

0 commit comments

Comments
 (0)