Remove PointerLike trait

This commit is contained in:
Michael Goulet 2025-07-03 20:03:45 +00:00
parent 48aee7e383
commit e2e3f5809b
14 changed files with 14 additions and 288 deletions

View File

@ -6,7 +6,7 @@ use rustc_macros::HashStable_Generic;
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants,
PointeeInfo, Primitive, Size, Variants,
};
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
@ -115,16 +115,6 @@ impl<'a> Layout<'a> {
pub fn unadjusted_abi_align(self) -> Align {
self.0.0.unadjusted_abi_align
}
/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
///
/// Currently, that means that the type is pointer-sized, pointer-aligned,
/// and has a initialized (non-union), scalar ABI.
pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
self.size() == data_layout.pointer_size
&& self.align().abi == data_layout.pointer_align.abi
&& matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
}
}
/// The layout of a type, alongside the type itself.

View File

@ -367,8 +367,6 @@ language_item_table! {
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0);
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);

View File

@ -47,7 +47,6 @@ pub(super) fn check_trait<'tcx>(
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
checker.check(
lang_items.coerce_pointee_validated_trait(),
visit_implementation_of_coerce_pointee_validity,
@ -707,104 +706,6 @@ fn infringing_fields_error<'tcx>(
err.emit()
}
fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
let impl_span = tcx.def_span(checker.impl_def_id);
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
let is_permitted_primitive = match *self_ty.kind() {
ty::Adt(def, _) => def.is_box(),
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
_ => false,
};
if is_permitted_primitive
&& let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
return Ok(());
}
let why_disqualified = match *self_ty.kind() {
// If an ADT is repr(transparent)
ty::Adt(self_ty_def, args) => {
if self_ty_def.repr().transparent() {
// FIXME(compiler-errors): This should and could be deduplicated into a query.
// Find the nontrivial field.
let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
let field_ty = tcx.type_of(field_def.did).instantiate_identity();
!tcx.layout_of(adt_typing_env.as_query_input(field_ty))
.is_ok_and(|layout| layout.layout.is_1zst())
});
if let Some(nontrivial_field) = nontrivial_field {
// Check that the nontrivial field implements `PointerLike`.
let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field_ty,
tcx.require_lang_item(LangItem::PointerLike, impl_span),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
return Ok(());
} else {
format!(
"the field `{field_name}` of {descr} `{self_ty}` \
does not implement `PointerLike`",
field_name = nontrivial_field.name,
descr = self_ty_def.descr()
)
}
} else {
format!(
"the {descr} `{self_ty}` is `repr(transparent)`, \
but does not have a non-trivial field (it is zero-sized)",
descr = self_ty_def.descr()
)
}
} else if self_ty_def.is_box() {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this box is not a thin pointer.
String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
} else {
format!(
"the {descr} `{self_ty}` is not `repr(transparent)`",
descr = self_ty_def.descr()
)
}
}
ty::Ref(..) => {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this reference is not a thin pointer.
String::from("references to dynamically-sized types are too large to be `PointerLike`")
}
ty::Dynamic(..) | ty::Foreign(..) => {
String::from("types of dynamic or unknown size may not implement `PointerLike`")
}
_ => {
// This is a white lie; it is true everywhere outside the standard library.
format!("only user-defined sized types are eligible for `impl PointerLike`")
}
};
Err(tcx
.dcx()
.struct_span_err(
impl_span,
"implementation must be applied to type that has the same ABI as a pointer, \
or is `repr(transparent)` and whose field is `PointerLike`",
)
.with_note(why_disqualified)
.emit())
}
fn visit_implementation_of_coerce_pointee_validity(
checker: &Checker<'_>,
) -> Result<(), ErrorGuaranteed> {

View File

@ -1149,12 +1149,16 @@ impl<'tcx> TypingEnv<'tcx> {
{
// FIXME(#132279): We should assert that the value does not contain any placeholders
// as these placeholders are also local to the current inference context. However, we
// currently use pseudo-canonical queries in the trait solver which replaces params with
// placeholders. We should also simply not use pseudo-canonical queries in the trait
// solver, at which point we can readd this assert. As of writing this comment, this is
// only used by `fn layout_is_pointer_like` when calling `layout_of`.
// currently use pseudo-canonical queries in the trait solver, which replaces params
// with placeholders during canonicalization. We should also simply not use pseudo-
// canonical queries in the trait solver, at which point we can readd this assert.
//
// debug_assert!(!value.has_placeholders());
// As of writing this comment, this is only used when normalizing consts that mention
// params.
/* debug_assert!(
!value.has_placeholders(),
"{value:?} which has placeholder shouldn't be pseudo-canonicalized"
); */
PseudoCanonicalInput { typing_env: self, value }
}
}

View File

@ -1623,7 +1623,6 @@ symbols! {
pointee_sized,
pointee_trait,
pointer,
pointer_like,
poll,
poll_next,
position,

View File

@ -14,9 +14,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
use rustc_middle::ty::{
self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
};
use rustc_middle::ty::{self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use thin_vec::thin_vec;
@ -1147,38 +1145,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
));
// Require that all AFIT will return something that can be coerced into `dyn*`
// -- a shim will be responsible for doing the actual coercion to `dyn*`.
if let Some(principal) = data.principal() {
for supertrait in
elaborate::supertraits(tcx, principal.with_self_ty(tcx, source))
{
if tcx.is_trait_alias(supertrait.def_id()) {
continue;
}
for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) {
if !tcx.is_impl_trait_in_trait(assoc_item) {
continue;
}
// RPITITs with `Self: Sized` don't need to be checked.
if tcx.generics_require_sized_self(assoc_item) {
continue;
}
let pointer_like_goal = pointer_like_goal_for_rpitit(
tcx,
supertrait,
assoc_item,
&obligation.cause,
);
nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx)));
}
}
}
ImplSource::Builtin(BuiltinImplSource::Misc, nested)
}
@ -1344,46 +1310,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
}
}
/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be
/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent
/// trait to be coercible to `dyn Trait`.
///
/// We do this given a supertrait's substitutions, and then augment the substitutions
/// with bound variables to compute the goal universally. Given that `PointerLike` has
/// no region requirements (at least for the built-in pointer types), this shouldn't
/// *really* matter, but it is the best choice for soundness.
fn pointer_like_goal_for_rpitit<'tcx>(
tcx: TyCtxt<'tcx>,
supertrait: ty::PolyTraitRef<'tcx>,
rpitit_item: DefId,
cause: &ObligationCause<'tcx>,
) -> ty::PolyTraitRef<'tcx> {
let mut bound_vars = supertrait.bound_vars().to_vec();
let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind {
ty::GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id));
bound_vars.push(ty::BoundVariableKind::Region(kind));
ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
unreachable!()
}
});
ty::Binder::bind_with_vars(
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::PointerLike, cause.span),
[Ty::new_projection_from_args(tcx, rpitit_item, args)],
),
tcx.mk_bound_variable_kinds(&bound_vars),
)
}

View File

@ -191,7 +191,7 @@ use core::error::{self, Error};
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
use core::marker::{PointerLike, Tuple, Unsize};
use core::marker::{Tuple, Unsize};
use core::mem::{self, SizedTypeProperties};
use core::ops::{
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
@ -2132,6 +2132,3 @@ impl<E: Error> Error for Box<E> {
Error::provide(&**self, request);
}
}
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T> PointerLike for Box<T> {}

View File

@ -134,7 +134,6 @@
#![feature(panic_internals)]
#![feature(pattern)]
#![feature(pin_coerce_unsized_trait)]
#![feature(pointer_like_trait)]
#![feature(ptr_alignment_type)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]

View File

@ -252,7 +252,7 @@
use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display};
use crate::marker::{PhantomData, PointerLike, Unsize};
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
use crate::panic::const_panic;
@ -669,9 +669,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for Cell<T> {}
impl<T> Cell<[T]> {
/// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
///
@ -2361,9 +2358,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for UnsafeCell<T> {}
/// [`UnsafeCell`], but [`Sync`].
///
/// This is just an `UnsafeCell`, except it implements `Sync`
@ -2470,9 +2464,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for SyncUnsafeCell<T> {}
#[allow(unused)]
fn assert_coerce_unsized(
a: UnsafeCell<&i32>,

View File

@ -1066,37 +1066,6 @@ pub trait Destruct {}
#[rustc_do_not_implement_via_object]
pub trait Tuple {}
/// A marker for pointer-like types.
///
/// This trait can only be implemented for types that are certain to have
/// the same size and alignment as a [`usize`] or [`*const ()`](pointer).
/// To ensure this, there are special requirements on implementations
/// of `PointerLike` (other than the already-provided implementations
/// for built-in types):
///
/// * The type must have `#[repr(transparent)]`.
/// * The types sole non-zero-sized field must itself implement `PointerLike`.
#[unstable(feature = "pointer_like_trait", issue = "none")]
#[lang = "pointer_like"]
#[diagnostic::on_unimplemented(
message = "`{Self}` needs to have the same ABI as a pointer",
label = "`{Self}` needs to be a pointer-like type"
)]
#[rustc_do_not_implement_via_object]
pub trait PointerLike {}
marker_impls! {
#[unstable(feature = "pointer_like_trait", issue = "none")]
PointerLike for
isize,
usize,
{T} &T,
{T} &mut T,
{T} *const T,
{T} *mut T,
{T: PointerLike} crate::pin::Pin<T>,
}
/// A marker for types which can be used as types of `const` generic parameters.
///
/// These types must have a proper equivalence relation (`Eq`) and it must be automatically

View File

@ -1,5 +1,5 @@
use crate::cell::UnsafeCell;
use crate::marker::{PointerLike, Unpin};
use crate::marker::Unpin;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::pin::Pin;
use crate::{fmt, ptr};
@ -178,8 +178,4 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T>
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
#[unstable(feature = "pointer_like_trait", issue = "none")]
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?

View File

@ -1628,9 +1628,6 @@ impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T
#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<T: PointeeSized> PinCoerceUnsized for NonNull<T> {}
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T> core::marker::PointerLike for NonNull<T> {}
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: PointeeSized> fmt::Debug for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -1,14 +0,0 @@
//@ compile-flags: -Znext-solver
#![feature(pointer_like_trait)]
use std::marker::PointerLike;
fn require_(_: impl PointerLike) {}
fn main() {
require_(1usize);
require_(1u16);
//~^ ERROR `u16` needs to have the same ABI as a pointer
require_(&1i16);
}

View File

@ -1,24 +0,0 @@
error[E0277]: `u16` needs to have the same ABI as a pointer
--> $DIR/pointer-like.rs:11:14
|
LL | require_(1u16);
| -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
| |
| required by a bound introduced by this call
|
= note: the trait bound `u16: PointerLike` is not satisfied
note: required by a bound in `require_`
--> $DIR/pointer-like.rs:7:21
|
LL | fn require_(_: impl PointerLike) {}
| ^^^^^^^^^^^ required by this bound in `require_`
help: consider borrowing here
|
LL | require_(&1u16);
| +
LL | require_(&mut 1u16);
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.